Skip to content

What it is

Zap is Uber's structured logging library for Go, designed for very low allocation overhead in hot paths while producing machine-readable JSON.

Zap offers two APIs: the fast, strongly-typed Logger and the more ergonomic SugaredLogger. Both produce structured output with levels, sampling and configurable encoders.

Installation

go get -u go.uber.org/zap

Getting started

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

Structured fields
logger, _ := zap.NewProduction()
defer logger.Sync() // flush buffered entries before exit

logger.Info("request completed",
    zap.String("method", "GET"),
    zap.String("path", "/books"),
    zap.Int("status", 200),
    zap.Duration("took", elapsed),
)
Typed fields such as zap.String avoid the reflection that makes printf-style logging slow. The output is JSON, so a log platform can index status and took as real fields.
Child loggers with shared context
requestLogger := logger.With(
    zap.String("request_id", id),
    zap.String("user_id", userID),
)

requestLogger.Info("validating")
requestLogger.Warn("rate limit near", zap.Int("remaining", 3))
// every line carries request_id and user_id automatically
With returns a logger that stamps those fields on every subsequent entry — the standard way to correlate all the logs from one request.

Advanced usage

Where the library earns its place over a simpler alternative.

Custom configuration and sampling
config := zap.NewProductionConfig()
config.EncoderConfig.TimeKey = "ts"
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
config.Level = zap.NewAtomicLevelAt(zap.InfoLevel)

// Cap repetitive entries: first 100 per second, then 1 in 100.
config.Sampling = &zap.SamplingConfig{Initial: 100, Thereafter: 100}

logger, err := config.Build()

// The level is atomic, so it can be changed at runtime.
config.Level.SetLevel(zap.DebugLevel)
Sampling protects you from a hot error path filling the disk and your log bill. The atomic level lets you turn on debug logging in production without a redeploy.

Errors and fixes

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

Logs are missing after the program exits
Zap buffers. Call logger.Sync() before exit; note that Sync on stdout can return an error on some platforms, which is safe to ignore.
Debug lines never appear
NewProduction defaults to Info. Use NewDevelopment, or set the level explicitly via an AtomicLevel.

Best practices

  • Call defer logger.Sync() in main so buffered entries are flushed on exit.
  • Use the typed Logger in hot paths and SugaredLogger where convenience matters more.
  • Attach request-scoped fields with With rather than repeating them at every call site.
  • Never log secrets, tokens or full request bodies — structured logs are widely readable.

Background

Why it exists, and what it was reacting to.

Uber built Zap after finding that reflection-based logging dominated CPU profiles in high-throughput services. Its typed field API avoids reflection and allocation almost entirely.