package encoder
import (
"strconv"
"time"
)
// FormatTimestamp returns an RFC3339-nano string in UTC. Exported so tests
// and alternative encoders share the same wire format. Zero times become
// empty strings; the JSON encoder substitutes the current time in that
// case.
func FormatTimestamp(t time.Time) string {
if t.IsZero() {
return ""
}
return t.UTC().Format(time.RFC3339Nano)
}
// FormatDuration returns d as a string of milliseconds with an "ms" suffix.
// Negative durations are preserved verbatim so callers can detect clock
// skew in downstream dashboards.
func FormatDuration(d time.Duration) string {
ms := int64(d / time.Millisecond)
return strconv.FormatInt(ms, 10) + "ms"
}
// FormatMilliseconds returns d as a bare millisecond integer.
func FormatMilliseconds(d time.Duration) int64 {
return int64(d / time.Millisecond)
}
// FormatLevel returns the canonical lowercase representation of the level
// name. Unknown inputs pass through lowercased so user code is not
// prevented from inventing its own levels (e.g. "audit").
func FormatLevel(level string) string {
switch level {
case "TRACE", "trace":
return "trace"
case "DEBUG", "debug":
return "debug"
case "INFO", "info":
return "info"
case "WARN", "warning", "WARNING":
return "warn"
case "ERROR", "error":
return "error"
case "FATAL", "fatal":
return "fatal"
}
return toLower(level)
}
// toLower is an inline ASCII-only lowercaser. The log-level space never
// contains non-ASCII, so the unicode-aware path is unnecessary.
func toLower(s string) string {
needs := false
for i := 0; i < len(s); i++ {
c := s[i]
if c >= 'A' && c <= 'Z' {
needs = true
break
}
}
if !needs {
return s
}
b := make([]byte, len(s))
for i := 0; i < len(s); i++ {
c := s[i]
if c >= 'A' && c <= 'Z' {
c += 32
}
b[i] = c
}
return string(b)
}
// LevelPriority returns a monotonically increasing integer per level. Higher
// priority means more severe. Unknown names collapse to InfoPriority so
// they are neither silenced nor flagged as critical by mistake.
func LevelPriority(level string) int {
switch FormatLevel(level) {
case "trace":
return 0
case "debug":
return 10
case "info":
return 20
case "warn":
return 30
case "error":
return 40
case "fatal":
return 50
}
return 20
}
// InfoPriority is the default threshold.
const InfoPriority = 20