Zerolog provides extensive global configuration through package-level variables. These settings affect all loggers and allow you to customize field names, formats, marshalers, and behavior across your entire application.
import (
"time"
"github.com/rs/zerolog"
)Customize the field names used in JSON output.
// Timestamp field name (default: "time")
var TimestampFieldName = "time"
// Level field name (default: "level")
var LevelFieldName = "level"
// Message field name (default: "message")
var MessageFieldName = "message"
// Error field name (default: "error")
var ErrorFieldName = "error"
// Caller field name (default: "caller")
var CallerFieldName = "caller"
// Error stack field name (default: "stack")
var ErrorStackFieldName = "stack"Example:
func init() {
zerolog.TimestampFieldName = "ts"
zerolog.LevelFieldName = "severity"
zerolog.MessageFieldName = "msg"
}
logger := zerolog.New(os.Stdout).With().Timestamp().Logger()
logger.Info().Msg("hello")
// Output: {"severity":"info","ts":"2024-01-15T10:30:00Z","msg":"hello"}Customize the string representation of log levels.
// Level string values
var LevelTraceValue = "trace"
var LevelDebugValue = "debug"
var LevelInfoValue = "info"
var LevelWarnValue = "warn"
var LevelErrorValue = "error"
var LevelFatalValue = "fatal"
var LevelPanicValue = "panic"Example:
func init() {
zerolog.LevelInfoValue = "information"
zerolog.LevelErrorValue = "err"
}
logger := zerolog.New(os.Stdout)
logger.Info().Msg("hello")
// Output: {"level":"information","message":"hello"}
logger.Error().Msg("failed")
// Output: {"level":"err","message":"failed"}Customize how levels are marshaled to strings.
// Customize level field marshaling
var LevelFieldMarshalFunc = func(l Level) string {
return l.String()
}Example:
func init() {
// Use numeric levels
zerolog.LevelFieldMarshalFunc = func(l zerolog.Level) string {
return strconv.Itoa(int(l))
}
}
logger := zerolog.New(os.Stdout)
logger.Info().Msg("hello")
// Output: {"level":"1","message":"hello"}Example with uppercase:
func init() {
zerolog.LevelFieldMarshalFunc = func(l zerolog.Level) string {
return strings.ToUpper(l.String())
}
}
logger.Info().Msg("hello")
// Output: {"level":"INFO","message":"hello"}Control how timestamps and durations are formatted.
// Time field format (default: time.RFC3339)
var TimeFieldFormat = time.RFC3339Standard time formats:
func init() {
// RFC3339 with milliseconds
zerolog.TimeFieldFormat = time.RFC3339Nano
// Custom format
zerolog.TimeFieldFormat = "2006-01-02 15:04:05"
}Unix timestamp formats:
// Time format constants for Unix timestamps
const (
TimeFormatUnix = "" // Unix seconds
TimeFormatUnixMs = "UNIXMS" // Unix milliseconds
TimeFormatUnixMicro = "UNIXMICRO" // Unix microseconds
TimeFormatUnixNano = "UNIXNANO" // Unix nanoseconds
)Example:
func init() {
// Use Unix milliseconds
zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs
}
logger := zerolog.New(os.Stdout).With().Timestamp().Logger()
logger.Info().Msg("hello")
// Output: {"level":"info","time":1705318200000,"message":"hello"}// Function to generate timestamps (default: time.Now)
var TimestampFunc = time.NowExample with frozen time (testing):
func init() {
// Freeze time for testing
frozenTime := time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC)
zerolog.TimestampFunc = func() time.Time {
return frozenTime
}
}Example with custom time source:
func init() {
// Use monotonic clock
start := time.Now()
zerolog.TimestampFunc = func() time.Time {
return start.Add(time.Since(start))
}
}// Duration field unit (default: time.Millisecond)
var DurationFieldUnit = time.Millisecond
// Render durations as integers (default: false)
var DurationFieldInteger = falseExample:
func init() {
// Use seconds for durations
zerolog.DurationFieldUnit = time.Second
zerolog.DurationFieldInteger = true
}
logger := zerolog.New(os.Stdout)
logger.Info().Dur("elapsed", 5*time.Second).Msg("completed")
// Output: {"level":"info","elapsed":5,"message":"completed"}With milliseconds (default):
func init() {
zerolog.DurationFieldUnit = time.Millisecond
zerolog.DurationFieldInteger = false
}
logger.Info().Dur("elapsed", 1234*time.Millisecond).Msg("completed")
// Output: {"level":"info","elapsed":1234,"message":"completed"}Customize error handling and formatting.
// Customize error marshaling (default: returns error as-is)
var ErrorMarshalFunc = func(err error) interface{} {
return err
}Example with custom error format:
func init() {
zerolog.ErrorMarshalFunc = func(err error) interface{} {
if err == nil {
return nil
}
return map[string]interface{}{
"message": err.Error(),
"type": fmt.Sprintf("%T", err),
}
}
}
err := errors.New("connection failed")
logger.Error().Err(err).Msg("operation failed")
// Output: {"level":"error","error":{"message":"connection failed","type":"*errors.errorString"},...}// Extract stack trace from error (default: nil)
var ErrorStackMarshaler func(err error) interface{}Example:
import "github.com/rs/zerolog/pkgerrors"
func init() {
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
}
logger.Error().Stack().Err(err).Msg("error with stack")
// Includes stack trace if error has oneSee Package Errors Integration for details.
// Handle write errors (default: print to stderr)
var ErrorHandler func(err error)Example:
func init() {
zerolog.ErrorHandler = func(err error) {
fmt.Fprintf(os.Stderr, "Logging error: %v\n", err)
// Could also send to monitoring system
}
}Customize caller file and line formatting.
// Number of stack frames to skip (default: 2)
var CallerSkipFrameCount = 2
// Customize caller format (default: "file:line")
var CallerMarshalFunc = func(pc uintptr, file string, line int) string {
return file + ":" + strconv.Itoa(line)
}Example with short file names:
func init() {
zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
// Use only filename, not full path
return filepath.Base(file) + ":" + strconv.Itoa(line)
}
}
logger.Info().Caller().Msg("hello")
// Output: {"caller":"main.go:42",...}Example with function name:
func init() {
zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
fn := runtime.FuncForPC(pc)
if fn == nil {
return file + ":" + strconv.Itoa(line)
}
return fn.Name() + " " + file + ":" + strconv.Itoa(line)
}
}
logger.Info().Caller().Msg("hello")
// Output: {"caller":"main.main /path/to/main.go:42",...}Customize how interface{} values are marshaled.
// Customize interface marshaling (default: json.Marshal without HTML escaping)
var InterfaceMarshalFunc = func(v interface{}) ([]byte, error) {
// Default implementation
}Example with custom marshaler:
import "encoding/json"
func init() {
zerolog.InterfaceMarshalFunc = func(v interface{}) ([]byte, error) {
// Use standard JSON marshaling with indentation (for debugging)
return json.MarshalIndent(v, "", " ")
}
}Control floating-point number formatting.
// Float formatting precision (default: -1, no limit)
var FloatingPointPrecision = -1Example:
func init() {
// Limit to 2 decimal places
zerolog.FloatingPointPrecision = 2
}
logger.Info().Float64("value", 3.14159).Msg("pi")
// Output: {"level":"info","value":3.14,"message":"pi"}Set default logger for context operations.
// Default logger from Ctx() when none in context (default: nil, returns disabled logger)
var DefaultContextLogger *LoggerExample:
func init() {
logger := zerolog.New(os.Stdout).With().
Str("app", "myapp").
Logger()
zerolog.DefaultContextLogger = &logger
}
// Now Ctx() returns the default logger if none in context
logger := zerolog.Ctx(context.Background())
logger.Info().Msg("using default logger")Customize console writer appearance.
// ANSI color codes per level
var LevelColors = map[Level]int{
TraceLevel: colorBlue,
DebugLevel: 0,
InfoLevel: colorGreen,
WarnLevel: colorYellow,
ErrorLevel: colorRed,
FatalLevel: colorRed,
PanicLevel: colorRed,
}
// Short level names for console output
var FormattedLevels = map[Level]string{
TraceLevel: "TRC",
DebugLevel: "DBG",
InfoLevel: "INF",
WarnLevel: "WRN",
ErrorLevel: "ERR",
FatalLevel: "FTL",
PanicLevel: "PNC",
}Example:
func init() {
// Custom colors
zerolog.LevelColors[zerolog.InfoLevel] = 36 // Cyan
// Custom level abbreviations
zerolog.FormattedLevels[zerolog.InfoLevel] = "INFO"
}Set minimum log level globally.
// Set global minimum level
func SetGlobalLevel(l Level)
// Get current global level
func GlobalLevel() LevelExample:
func init() {
if os.Getenv("DEBUG") == "true" {
zerolog.SetGlobalLevel(zerolog.DebugLevel)
} else {
zerolog.SetGlobalLevel(zerolog.InfoLevel)
}
}
// All loggers respect global level
logger.Debug().Msg("debug message") // Only logged if global level allowsGet current level:
currentLevel := zerolog.GlobalLevel()
fmt.Printf("Global level: %s\n", currentLevel)Globally disable all sampling.
// Disable sampling globally (for debugging)
func DisableSampling(v bool)Example:
func TestSomething(t *testing.T) {
// Disable sampling for tests
zerolog.DisableSampling(true)
defer zerolog.DisableSampling(false)
// All samplers now pass through
logger.Info().Msg("always logged")
}// Buffer size limit for TriggerLevelWriter pool (default: 64 KiB)
var TriggerLevelWriterBufferReuseLimit = 64 * 1024Example:
func init() {
// Increase buffer limit to 128 KiB
zerolog.TriggerLevelWriterBufferReuseLimit = 128 * 1024
}func init() {
// Minimal, efficient settings for production
zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs
zerolog.DurationFieldUnit = time.Millisecond
zerolog.DurationFieldInteger = true
zerolog.SetGlobalLevel(zerolog.InfoLevel)
}func init() {
// Readable settings for development
zerolog.TimeFieldFormat = time.RFC3339
zerolog.SetGlobalLevel(zerolog.DebugLevel)
// Custom field names for readability
zerolog.TimestampFieldName = "timestamp"
zerolog.MessageFieldName = "msg"
}func init() {
// Match Google Cloud Logging format
zerolog.TimestampFieldName = "timestamp"
zerolog.LevelFieldName = "severity"
zerolog.MessageFieldName = "message"
// Use uppercase levels
zerolog.LevelFieldMarshalFunc = func(l zerolog.Level) string {
return strings.ToUpper(l.String())
}
}func TestMain(m *testing.M) {
// Configure for testing
zerolog.SetGlobalLevel(zerolog.DebugLevel)
zerolog.DisableSampling(true)
// Use frozen time
testTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
zerolog.TimestampFunc = func() time.Time { return testTime }
code := m.Run()
os.Exit(code)
}func init() {
// JSON with standard fields
zerolog.TimestampFieldName = "@timestamp"
zerolog.TimeFieldFormat = time.RFC3339Nano
// Add pod info in application code via context
}Set global configuration in init() or early in main():
func init() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs
zerolog.SetGlobalLevel(zerolog.InfoLevel)
}Use environment variables for configuration:
func init() {
if env := os.Getenv("LOG_LEVEL"); env != "" {
if level, err := zerolog.ParseLevel(env); err == nil {
zerolog.SetGlobalLevel(level)
}
}
if os.Getenv("LOG_FORMAT") == "text" {
zerolog.TimeFieldFormat = "2006-01-02 15:04:05"
}
}If you customize field names, document them:
// Log field names (customized for our infrastructure)
// - "ts": timestamp
// - "lvl": log level
// - "msg": message
func init() {
zerolog.TimestampFieldName = "ts"
zerolog.LevelFieldName = "lvl"
zerolog.MessageFieldName = "msg"
}Custom marshalers run for every event. Keep them fast:
// Good - fast
zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
return filepath.Base(file) + ":" + strconv.Itoa(line)
}
// Avoid - slow
zerolog.ErrorMarshalFunc = func(err error) interface{} {
// Don't do expensive operations here
details := fetchErrorDetails(err) // BAD: database/API call
return details
}Unless you have specific requirements, use default field names:
// Good - standard names
// zerolog.TimestampFieldName = "time" // default
// zerolog.LevelFieldName = "level" // default
// Only customize when required by infrastructure
zerolog.LevelFieldName = "severity" // Required by Google Cloud LoggingSetGlobalLevel() and DisableSampling() use atomic operations and are thread-safe