Zerolog provides comprehensive, strongly-typed field methods for adding data to log events. All field methods are available on both Event and Context types, with identical signatures. Methods on Event return *Event for chaining, while methods on Context return Context.
import (
"fmt"
"net"
"time"
"github.com/rs/zerolog"
)// Add string field
func (e *Event) Str(key, val string) *Event
func (c Context) Str(key, val string) Context
// Add string array field
func (e *Event) Strs(key string, vals []string) *Event
func (c Context) Strs(key string, vals []string) ContextExample:
logger.Info().
Str("username", "alice").
Str("operation", "login").
Msg("user action")
logger.Info().
Strs("tags", []string{"api", "production", "critical"}).
Msg("service started")// Add fmt.Stringer field (or null if val is nil)
func (e *Event) Stringer(key string, val fmt.Stringer) *Event
func (c Context) Stringer(key string, val fmt.Stringer) Context
// Add fmt.Stringer array field
func (e *Event) Stringers(key string, vals []fmt.Stringer) *Event
func (c Context) Stringers(key string, vals []fmt.Stringer) ContextExample:
type UserID int
func (u UserID) String() string { return fmt.Sprintf("user_%d", u) }
logger.Info().
Stringer("user_id", UserID(42)).
Msg("user action")
// Output includes: "user_id":"user_42"// Add bytes as string field
func (e *Event) Bytes(key string, val []byte) *Event
func (c Context) Bytes(key string, val []byte) Context
// Add bytes as hex-encoded string field
func (e *Event) Hex(key string, val []byte) *Event
func (c Context) Hex(key string, val []byte) Context
// Add pre-encoded JSON field (not escaped)
func (e *Event) RawJSON(key string, b []byte) *Event
func (c Context) RawJSON(key string, b []byte) Context
// Add pre-encoded CBOR field
func (e *Event) RawCBOR(key string, b []byte) *Event
func (c Context) RawCBOR(key string, b []byte) ContextExample:
data := []byte("hello")
logger.Info().
Bytes("data", data).
Hex("data_hex", data).
Msg("binary data")
// Output: "data":"hello","data_hex":"68656c6c6f"
// Pre-encoded JSON
jsonData := []byte(`{"nested":"value","count":42}`)
logger.Info().
RawJSON("metadata", jsonData).
Msg("with metadata")
// Output: "metadata":{"nested":"value","count":42}// Add boolean field
func (e *Event) Bool(key string, b bool) *Event
func (c Context) Bool(key string, b bool) Context
// Add boolean array field
func (e *Event) Bools(key string, b []bool) *Event
func (c Context) Bools(key string, b []bool) ContextExample:
logger.Info().
Bool("success", true).
Bool("authenticated", false).
Msg("operation result")
logger.Debug().
Bools("flags", []bool{true, false, true}).
Msg("feature flags")// Add int field
func (e *Event) Int(key string, i int) *Event
func (c Context) Int(key string, i int) Context
// Add int8 field
func (e *Event) Int8(key string, i int8) *Event
func (c Context) Int8(key string, i int8) Context
// Add int16 field
func (e *Event) Int16(key string, i int16) *Event
func (c Context) Int16(key string, i int16) Context
// Add int32 field
func (e *Event) Int32(key string, i int32) *Event
func (c Context) Int32(key string, i int32) Context
// Add int64 field
func (e *Event) Int64(key string, i int64) *Event
func (c Context) Int64(key string, i int64) ContextExample:
logger.Info().
Int("status_code", 200).
Int32("user_id", 42).
Int64("bytes_processed", 1234567890).
Msg("request completed")// Add int array field
func (e *Event) Ints(key string, i []int) *Event
func (c Context) Ints(key string, i []int) Context
// Add int8 array field
func (e *Event) Ints8(key string, i []int8) *Event
func (c Context) Ints8(key string, i []int8) Context
// Add int16 array field
func (e *Event) Ints16(key string, i []int16) *Event
func (c Context) Ints16(key string, i []int16) Context
// Add int32 array field
func (e *Event) Ints32(key string, i []int32) *Event
func (c Context) Ints32(key string, i []int32) Context
// Add int64 array field
func (e *Event) Ints64(key string, i []int64) *Event
func (c Context) Ints64(key string, i []int64) ContextExample:
logger.Info().
Ints("scores", []int{100, 95, 87, 92}).
Ints64("timestamps", []int64{1234567890, 1234567900}).
Msg("batch results")// Add uint field
func (e *Event) Uint(key string, i uint) *Event
func (c Context) Uint(key string, i uint) Context
// Add uint8 field
func (e *Event) Uint8(key string, i uint8) *Event
func (c Context) Uint8(key string, i uint8) Context
// Add uint16 field
func (e *Event) Uint16(key string, i uint16) *Event
func (c Context) Uint16(key string, i uint16) Context
// Add uint32 field
func (e *Event) Uint32(key string, i uint32) *Event
func (c Context) Uint32(key string, i uint32) Context
// Add uint64 field
func (e *Event) Uint64(key string, i uint64) *Event
func (c Context) Uint64(key string, i uint64) ContextExample:
logger.Info().
Uint16("port", 8080).
Uint32("process_id", 12345).
Uint64("request_count", 1000000).
Msg("server stats")// Add uint array field
func (e *Event) Uints(key string, i []uint) *Event
func (c Context) Uints(key string, i []uint) Context
// Add uint8 array field
func (e *Event) Uints8(key string, i []uint8) *Event
func (c Context) Uints8(key string, i []uint8) Context
// Add uint16 array field
func (e *Event) Uints16(key string, i []uint16) *Event
func (c Context) Uints16(key string, i []uint16) Context
// Add uint32 array field
func (e *Event) Uints32(key string, i []uint32) *Event
func (c Context) Uints32(key string, i []uint32) Context
// Add uint64 array field
func (e *Event) Uints64(key string, i []uint64) *Event
func (c Context) Uints64(key string, i []uint64) ContextExample:
logger.Info().
Uints16("open_ports", []uint16{80, 443, 8080}).
Uints64("metrics", []uint64{1000, 2000, 3000}).
Msg("system info")// Add float32 field
func (e *Event) Float32(key string, f float32) *Event
func (c Context) Float32(key string, f float32) Context
// Add float64 field
func (e *Event) Float64(key string, f float64) *Event
func (c Context) Float64(key string, f float64) Context
// Add float32 array field
func (e *Event) Floats32(key string, f []float32) *Event
func (c Context) Floats32(key string, f []float32) Context
// Add float64 array field
func (e *Event) Floats64(key string, f []float64) *Event
func (c Context) Floats64(key string, f []float64) ContextExample:
logger.Info().
Float64("cpu_usage", 45.7).
Float64("memory_percent", 78.3).
Float32("temperature", 62.5).
Msg("system metrics")
logger.Debug().
Floats64("coordinates", []float64{37.7749, -122.4194}).
Msg("location data")Note: Float formatting precision is controlled by the global zerolog.FloatingPointPrecision variable. See Global Configuration.
// Add time.Time field
func (e *Event) Time(key string, t time.Time) *Event
func (c Context) Time(key string, t time.Time) Context
// Add time.Time array field
func (e *Event) Times(key string, t []time.Time) *Event
func (c Context) Times(key string, t []time.Time) Context
// Add timestamp with configured field name (zerolog.TimestampFieldName)
func (e *Event) Timestamp() *Event
func (c Context) Timestamp() ContextExample:
now := time.Now()
created := time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC)
logger.Info().
Time("created_at", created).
Time("updated_at", now).
Timestamp().
Msg("record updated")Note: Time formatting is controlled by the global zerolog.TimeFieldFormat variable. Default is RFC3339. Special values: "" (Unix seconds), "UNIXMS" (milliseconds), "UNIXMICRO" (microseconds), "UNIXNANO" (nanoseconds).
// Add time.Duration field
func (e *Event) Dur(key string, d time.Duration) *Event
func (c Context) Dur(key string, d time.Duration) Context
// Add time.Duration array field
func (e *Event) Durs(key string, d []time.Duration) *Event
func (c Context) Durs(key string, d []time.Duration) Context
// Add time difference as duration
func (e *Event) TimeDiff(key string, t, start time.Time) *Event
func (c Context) TimeDiff(key string, t, start time.Time) ContextExample:
start := time.Now()
// ... do work ...
elapsed := time.Since(start)
logger.Info().
Dur("elapsed", elapsed).
TimeDiff("duration", time.Now(), start).
Msg("operation completed")
logger.Debug().
Durs("intervals", []time.Duration{
100 * time.Millisecond,
200 * time.Millisecond,
150 * time.Millisecond,
}).
Msg("timing data")Note: Duration formatting is controlled by:
zerolog.DurationFieldUnit - Unit for conversion (default: time.Millisecond)zerolog.DurationFieldInteger - Render as integer vs float (default: false)// Add IP address field
func (e *Event) IPAddr(key string, ip net.IP) *Event
func (c Context) IPAddr(key string, ip net.IP) Context
// Add IP prefix/CIDR field
func (e *Event) IPPrefix(key string, pfx net.IPNet) *Event
func (c Context) IPPrefix(key string, pfx net.IPNet) Context
// Add MAC address field
func (e *Event) MACAddr(key string, ha net.HardwareAddr) *Event
func (c Context) MACAddr(key string, ha net.HardwareAddr) ContextExample:
ip := net.ParseIP("192.168.1.100")
_, ipnet, _ := net.ParseCIDR("10.0.0.0/8")
mac, _ := net.ParseMAC("00:11:22:33:44:55")
logger.Info().
IPAddr("client_ip", ip).
IPPrefix("subnet", *ipnet).
MACAddr("mac_address", mac).
Msg("network event")
// Output: "client_ip":"192.168.1.100","subnet":"10.0.0.0/8","mac_address":"00:11:22:33:44:55"// Add error with default error field name (zerolog.ErrorFieldName)
func (e *Event) Err(err error) *Event
func (c Context) Err(err error) Context
// Add error with custom key
func (e *Event) AnErr(key string, err error) *Event
func (c Context) AnErr(key string, err error) Context
// Add error array field
func (e *Event) Errs(key string, errs []error) *Event
func (c Context) Errs(key string, errs []error) Context
// Add stack trace (requires ErrorStackMarshaler to be set)
func (e *Event) Stack() *Event
func (c Context) Stack() ContextExample:
err := errors.New("connection failed")
validationErr := errors.New("invalid input")
logger.Error().
Err(err).
Msg("operation failed")
// Output: "level":"error","error":"connection failed","message":"operation failed"
logger.Warn().
AnErr("primary_error", err).
AnErr("secondary_error", validationErr).
Msg("multiple errors")
logger.Error().
Err(err).
Stack().
Msg("error with stack trace")
// Stack trace included if ErrorStackMarshaler is configuredError Marshaling: Customize with zerolog.ErrorMarshalFunc. Extract stack traces with zerolog.ErrorStackMarshaler. See Package Errors Integration for stack trace support.
// Add array field using LogArrayMarshaler
func (e *Event) Array(key string, arr LogArrayMarshaler) *Event
func (c Context) Array(key string, arr LogArrayMarshaler) ContextExample:
arr := zerolog.Arr().
Str("first").
Str("second").
Int(42).
Bool(true)
logger.Info().
Array("items", arr).
Msg("array example")
// Output: "items":["first","second",42,true]See Advanced Types for complete Array API.
// Add nested dictionary field
func (e *Event) Dict(key string, dict *Event) *Event
func (c Context) Dict(key string, dict *Event) ContextExample:
dict := zerolog.Dict().
Str("name", "alice").
Int("age", 30).
Bool("active", true)
logger.Info().
Dict("user", dict).
Msg("user info")
// Output: "user":{"name":"alice","age":30,"active":true}See Advanced Types for more on Dict.
// Add object field using LogObjectMarshaler interface
func (e *Event) Object(key string, obj LogObjectMarshaler) *Event
func (c Context) Object(key string, obj LogObjectMarshaler) Context
// Embed object fields at top level (no key)
func (e *Event) EmbedObject(obj LogObjectMarshaler) *Event
func (c Context) EmbedObject(obj LogObjectMarshaler) ContextExample:
type User struct {
Name string
Age int
}
func (u User) MarshalZerologObject(e *zerolog.Event) {
e.Str("name", u.Name).Int("age", u.Age)
}
user := User{Name: "alice", Age: 30}
logger.Info().
Object("user", user).
Msg("user action")
// Output: "user":{"name":"alice","age":30}
logger.Info().
EmbedObject(user).
Msg("user action")
// Output: "name":"alice","age":30 (no "user" key)See Advanced Types for marshaler interfaces.
// Add interface{} field using reflection
func (e *Event) Interface(key string, i interface{}) *Event
func (c Context) Interface(key string, i interface{}) Context
// Alias for Interface
func (e *Event) Any(key string, i interface{}) *Event
func (c Context) Any(key string, i interface{}) ContextExample:
data := map[string]interface{}{
"name": "alice",
"age": 30,
"tags": []string{"user", "active"},
}
logger.Info().
Interface("data", data).
Msg("structured data")
// Any is identical to Interface
logger.Debug().
Any("value", someValue).
Msg("debug info")Note: Interface() uses reflection and the marshaler specified by zerolog.InterfaceMarshalFunc (default: json.Marshal). This is less efficient than strongly-typed methods.
// Add multiple fields from map or struct
func (e *Event) Fields(fields interface{}) *Event
func (c Context) Fields(fields interface{}) ContextExample:
// With map
fields := map[string]interface{}{
"service": "api",
"version": "1.0.0",
"port": 8080,
"debug": true,
}
logger.Info().
Fields(fields).
Msg("service started")
// With slice (alternating keys and values)
logger.Info().
Fields([]interface{}{
"key1", "value1",
"key2", 42,
"key3", true,
}).
Msg("multiple fields")Note: Only map[string]interface{} and []interface{} are accepted. For slices, odd-length arrays ignore the last element.
// Add caller file and line information
func (e *Event) Caller(skip ...int) *Event
// Add caller with specific frame skip count
func (e *Event) CallerSkipFrame(skip int) *EventExample:
logger.Info().Caller().Msg("log with caller")
// Output: "caller":"/path/to/file.go:42","message":"log with caller"
// Skip frames (useful when wrapping logger)
logger.Info().Caller(1).Msg("skip one frame")Note: Default skip count is controlled by zerolog.CallerSkipFrameCount (default: 2). Customize caller format with zerolog.CallerMarshalFunc.
// Add type name of value
func (e *Event) Type(key string, val interface{}) *EventExample:
type CustomType struct{}
value := CustomType{}
logger.Debug().
Type("value_type", value).
Msg("type info")
// Output: "value_type":"main.CustomType"| Category | Methods | Types |
|---|---|---|
| String | Str, Strs, Stringer, Stringers | string, []string, fmt.Stringer, []fmt.Stringer |
| Binary | Bytes, Hex, RawJSON, RawCBOR | []byte |
| Boolean | Bool, Bools | bool, []bool |
| Signed Int | Int, Int8, Int16, Int32, Int64 | int, int8, int16, int32, int64 |
| Signed Int Array | Ints, Ints8, Ints16, Ints32, Ints64 | []int, []int8, []int16, []int32, []int64 |
| Unsigned Int | Uint, Uint8, Uint16, Uint32, Uint64 | uint, uint8, uint16, uint32, uint64 |
| Unsigned Int Array | Uints, Uints8, Uints16, Uints32, Uints64 | []uint, []uint8, []uint16, []uint32, []uint64 |
| Float | Float32, Float64, Floats32, Floats64 | float32, float64, []float32, []float64 |
| Time | Time, Times, Timestamp | time.Time, []time.Time |
| Duration | Dur, Durs, TimeDiff | time.Duration, []time.Duration |
| Network | IPAddr, IPPrefix, MACAddr | net.IP, net.IPNet, net.HardwareAddr |
| Error | Err, AnErr, Errs, Stack | error, []error |
| Complex | Array, Dict, Object, EmbedObject | LogArrayMarshaler, *Event, LogObjectMarshaler |
| Generic | Interface, Any, Fields | interface{} |
| Metadata | Caller, CallerSkipFrame, Type | - |
Prefer strongly-typed methods over Interface() for better performance:
// Good
logger.Info().Int("count", 42).Msg("result")
// Avoid (slower due to reflection)
logger.Info().Interface("count", 42).Msg("result")Use the narrowest type that fits your data:
// Good
logger.Info().Uint16("port", 8080).Msg("server started")
// Works but wastes bytes
logger.Info().Uint64("port", 8080).Msg("server started")Always use Err() for error values to get proper error marshaling:
// Good
logger.Error().Err(err).Msg("failed")
// Avoid
logger.Error().Str("error", err.Error()).Msg("failed")For nested JSON, use RawJSON() to avoid double-encoding:
jsonData := []byte(`{"key":"value"}`)
// Good
logger.Info().RawJSON("data", jsonData).Msg("message")
// Avoid (double-encoded)
logger.Info().Str("data", string(jsonData)).Msg("message")Use typed array methods for arrays of the same type:
// Good
logger.Info().Ints("scores", []int{100, 95, 87}).Msg("results")
// Avoid (less efficient)
arr := zerolog.Arr().Int(100).Int(95).Int(87)
logger.Info().Array("scores", arr).Msg("results")Use consistent field names across your application:
// Good - consistent naming
logger.Info().Str("user_id", id).Msg("action")
logger.Debug().Str("user_id", id).Msg("debug")
// Avoid - inconsistent
logger.Info().Str("user_id", id).Msg("action")
logger.Debug().Str("userId", id).Msg("debug")Interface() and Any() use reflection (slower)Enabled() check before expensive field computations