Skip to content

zerolog

ObservabilityLoggingGo

What it is

zerolog is a zero-allocation JSON logger for Go with a chainable API, aimed at the same performance goals as Zap with a lighter interface.

Log entries are built by chaining typed methods and terminated with Msg or Msgf. It supports levels, sampling, context-bound loggers and a pretty console writer for development.

Installation

go get -u github.com/rs/zerolog/log

Getting started

The smallest useful thing you can do with it, and what each part means.

Chained structured logging
log.Info().
    Str("method", "GET").
    Str("path", "/books").
    Int("status", 200).
    Dur("took", elapsed).
    Msg("request completed")

// Msg terminates the entry — forgetting it means nothing is written.
The chain builds the JSON object directly. The most common mistake is omitting the terminating Msg or Send call, which silently discards the line.
Console output in development
if os.Getenv("ENV") == "development" {
    log.Logger = log.Output(zerolog.ConsoleWriter{
        Out:        os.Stderr,
        TimeFormat: time.Kitchen,
    })
}
zerolog.SetGlobalLevel(zerolog.InfoLevel)
ConsoleWriter produces coloured, human-readable output locally while production keeps raw JSON. It is deliberately slow, so never enable it in production.

Advanced usage

Where the library earns its place over a simpler alternative.

Request-scoped logger through context
func middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        logger := log.With().
            Str("request_id", uuid.NewString()).
            Str("path", r.URL.Path).
            Logger()

        ctx := logger.WithContext(r.Context())
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

// Anywhere downstream:
func handler(w http.ResponseWriter, r *http.Request) {
    zerolog.Ctx(r.Context()).Info().Msg("handling")
}
Carrying the logger on the context means deep helper functions can log with full request correlation without taking a logger parameter.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

Nothing is logged
Either the chain was not terminated with Msg, or the global level is above the entry's level. Check both.
Errors lack a stack trace
Set zerolog.ErrorStackMarshaler and use Err(err).Stack(); zerolog does not capture stacks by default.

Best practices

  • Always terminate a chain with Msg, Msgf or Send — an unterminated chain logs nothing.
  • Use ConsoleWriter only in development; it is far slower than the JSON encoder.
  • Attach a request-scoped logger to the context rather than threading it through signatures.
  • Set the global level from configuration so verbosity is adjustable without a rebuild.

Background

Why it exists, and what it was reacting to.

Created by Olivier Poitrey, zerolog writes JSON directly into a byte buffer with no intermediate representation, which is how it reaches genuinely zero allocations for most log lines.