Readers search zap sugaredlogger, sugaredlogger, zap logger, golang zap, zap request id, zap logging, zap golang, zap sugaredlogger vs logger, golang zap logger, and zap logger golang for the same library: go.uber.org/zap, Uber’s structured zap logger for Go. This guide covers Logger vs SugaredLogger, correct Infow usage, zap request id patterns, levels with AtomicLevel, and production-style configuration—with links to the official docs for encoder tuning and rotation add-ons.
Examples assume a recent Go toolchain on Linux and zap v1.27+ in a Go module. Snippets use
{run=false}because they importgo.uber.org/zapoutside the minimal Playground module set.
Install zap (golang zap, zap golang)
In a module:
go get go.uber.org/zap@latestImport go.uber.org/zap. Commit go.sum changes in versioned services.
Zap sugaredlogger vs Logger (zap logger)
Typed Logger takes zap.Field values (zap.String, zap.Int, …). It is the default choice in hot paths where allocations matter.
SugaredLogger comes from logger.Sugar(). It adds Infof, Infow, and similar helpers. Zap sugaredlogger vs logger is mostly an ergonomics vs performance trade—benchmark your own message shape with Go benchmarks instead of relying on stale absolute timings from older posts.
package main
import (
"go.uber.org/zap"
)
func main() {
logger, err := zap.NewProduction()
if err != nil {
panic(err)
}
defer logger.Sync()
logger.Info("typed", zap.String("request_id", "req-1"), zap.Int("status", 200))
sugar := logger.Sugar()
sugar.Infow("sugared", "request_id", "req-2", "path", "/api/health")
}Run prints two JSON lines, each with request_id (and path on the sugared line). Avoid Infof when you want key-value structure; use Infow("msg", "key", value, ...) or the typed Info.
Zap request id and child loggers (zap request id)
For HTTP handlers, derive a per-request logger once, then pass it down (or store it on context with your own helper):
reqLog := logger.With(zap.String("request_id", requestID))
reqLog.Info("incoming", zap.String("method", "GET"))With SugaredLogger:
s := logger.Sugar()
reqSugar := s.With("request_id", requestID)
reqSugar.Infow("incoming", "method", "GET")That is the usual answer to zap request id: fields on a child logger so every line in the scope carries the same correlation id.
Levels and AtomicLevel (zap logging)
Zap levels map to zapcore.Level (Debug, Info, Warn, Error, …). zap.NewAtomicLevel() (or NewAtomicLevelAt) plugs into zap.Config.Level so you can call SetLevel while goroutines log—useful for temporary debug in production without restart.
package main
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func main() {
al := zap.NewAtomicLevelAt(zapcore.InfoLevel)
cfg := zap.NewProductionConfig()
cfg.Level = al
logger, err := cfg.Build()
if err != nil {
panic(err)
}
defer logger.Sync()
logger.Info("info only before debug enabled")
al.SetLevel(zapcore.DebugLevel)
logger.Debug("now debug is visible")
}Run shows the debug line only after SetLevel.
JSON, console, outputs, and rotation
zap.NewProduction() and zap.NewDevelopment() are opinionated starting points: production JSON to stdout, development console with different defaults. Customize zap.Config (Encoding, EncoderConfig, OutputPaths, ErrorOutputPaths) for files or dual writes. Log rotation is not built into zap itself—pair file OutputPaths with something like lumberjack from the ecosystem, or your platform’s log agent.
For contrasts with the standard library log package, see changing the default log format.
Summary
Zap logger and zap logging workflows center on zap.NewProduction / Config.Build, defer logger.Sync(), and choosing Logger (typed zap.Field) versus SugaredLogger for zap sugaredlogger-style ergonomics. Zap sugaredlogger vs logger boils down to typed fields vs Infow pairs; both support zap request id style correlation via With. Golang zap and zap golang are the same go.uber.org/zap module—pin versions, handle Build errors, and tune AtomicLevel when you need live level changes without redeploying.

