This document covers the main logging APIs: Logger, SugaredLogger, configuration, and runtime level management.
The Logger type provides fast, strongly-typed, structured logging. All methods are safe for concurrent use.
type Logger struct {
// All fields are unexported
}// Create logger from Core and Options
func New(core zapcore.Core, options ...Option) *Logger
// Create no-op logger that never writes logs
func NewNop() *Logger
// Preset constructors with sensible defaults
func NewProduction(options ...Option) (*Logger, error)
func NewDevelopment(options ...Option) (*Logger, error)
func NewExample(options ...Option) *Logger
// Helper that panics on error (useful with Must pattern)
func Must(logger *Logger, err error) *Logger// Log at specific levels with structured fields
func (log *Logger) Debug(msg string, fields ...Field)
func (log *Logger) Info(msg string, fields ...Field)
func (log *Logger) Warn(msg string, fields ...Field)
func (log *Logger) Error(msg string, fields ...Field)
func (log *Logger) DPanic(msg string, fields ...Field) // Panics in development mode
func (log *Logger) Panic(msg string, fields ...Field) // Always panics after logging
func (log *Logger) Fatal(msg string, fields ...Field) // Calls os.Exit(1) after logging
// Log at dynamic level
func (log *Logger) Log(lvl zapcore.Level, msg string, fields ...Field)
// Check if level is enabled and get CheckedEntry for conditional logging
func (log *Logger) Check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry// Create child logger with additional context fields
func (log *Logger) With(fields ...Field) *Logger
// Create child logger with lazy field evaluation
func (log *Logger) WithLazy(fields ...Field) *Logger
// Add name segment to logger (typically package/module name)
func (log *Logger) Named(s string) *Logger// Clone logger and apply options
func (log *Logger) WithOptions(opts ...Option) *Logger
// Convert to more ergonomic SugaredLogger
func (log *Logger) Sugar() *SugaredLogger// Get minimum enabled logging level
func (log *Logger) Level() zapcore.Level
// Get underlying Core
func (log *Logger) Core() zapcore.Core
// Get logger's name (or empty string if unnamed)
func (log *Logger) Name() string
// Flush any buffered log entries
func (log *Logger) Sync() error// Create production logger
logger, err := zap.NewProduction()
if err != nil {
panic(err)
}
defer logger.Sync()
// Strongly-typed structured logging
logger.Info("user request",
zap.String("method", "GET"),
zap.String("path", "/api/users"),
zap.Int("status", 200),
zap.Duration("latency", 45*time.Millisecond),
)
// Create child logger with context
userLogger := logger.With(
zap.String("user_id", "12345"),
zap.String("session", "abc-def"),
)
// Child logger includes parent context automatically
userLogger.Info("profile updated") // Includes user_id and session fields
// Named loggers for different subsystems
dbLogger := logger.Named("database")
dbLogger.Debug("query executed", zap.String("query", "SELECT ..."))
// Logs with name: "database"
apiLogger := dbLogger.Named("api")
// Logs with name: "database.api"The SugaredLogger provides a more ergonomic, loosely-typed API. It's 4-10x slower than Logger but much more convenient and still faster than most alternatives.
type SugaredLogger struct {
// Has unexported fields
}func (s *SugaredLogger) Debugf(template string, args ...interface{})
func (s *SugaredLogger) Infof(template string, args ...interface{})
func (s *SugaredLogger) Warnf(template string, args ...interface{})
func (s *SugaredLogger) Errorf(template string, args ...interface{})
func (s *SugaredLogger) DPanicf(template string, args ...interface{})
func (s *SugaredLogger) Panicf(template string, args ...interface{})
func (s *SugaredLogger) Fatalf(template string, args ...interface{})
func (s *SugaredLogger) Logf(lvl zapcore.Level, template string, args ...interface{})func (s *SugaredLogger) Debug(args ...interface{})
func (s *SugaredLogger) Info(args ...interface{})
func (s *SugaredLogger) Warn(args ...interface{})
func (s *SugaredLogger) Error(args ...interface{})
func (s *SugaredLogger) DPanic(args ...interface{})
func (s *SugaredLogger) Panic(args ...interface{})
func (s *SugaredLogger) Fatal(args ...interface{})
func (s *SugaredLogger) Log(lvl zapcore.Level, args ...interface{})func (s *SugaredLogger) Debugln(args ...interface{})
func (s *SugaredLogger) Infoln(args ...interface{})
func (s *SugaredLogger) Warnln(args ...interface{})
func (s *SugaredLogger) Errorln(args ...interface{})
func (s *SugaredLogger) DPanicln(args ...interface{})
func (s *SugaredLogger) Panicln(args ...interface{})
func (s *SugaredLogger) Fatalln(args ...interface{})
func (s *SugaredLogger) Logln(lvl zapcore.Level, args ...interface{})func (s *SugaredLogger) Debugw(msg string, keysAndValues ...interface{})
func (s *SugaredLogger) Infow(msg string, keysAndValues ...interface{})
func (s *SugaredLogger) Warnw(msg string, keysAndValues ...interface{})
func (s *SugaredLogger) Errorw(msg string, keysAndValues ...interface{})
func (s *SugaredLogger) DPanicw(msg string, keysAndValues ...interface{})
func (s *SugaredLogger) Panicw(msg string, keysAndValues ...interface{})
func (s *SugaredLogger) Fatalw(msg string, keysAndValues ...interface{})
func (s *SugaredLogger) Logw(lvl zapcore.Level, msg string, keysAndValues ...interface{})// Create child logger with additional context
func (s *SugaredLogger) With(args ...interface{}) *SugaredLogger
// Create child logger with lazy field evaluation
func (s *SugaredLogger) WithLazy(args ...interface{}) *SugaredLogger
// Add name segment
func (s *SugaredLogger) Named(name string) *SugaredLogger
// Clone and apply options
func (s *SugaredLogger) WithOptions(opts ...Option) *SugaredLogger
// Convert back to base Logger
func (s *SugaredLogger) Desugar() *Logger
// Get minimum enabled level
func (s *SugaredLogger) Level() zapcore.Level
// Flush buffered entries
func (s *SugaredLogger) Sync() errorlogger, _ := zap.NewProduction()
sugar := logger.Sugar()
defer sugar.Sync()
// Printf-style
sugar.Infof("User %s logged in from %s", username, ipAddress)
// Print-style
sugar.Info("Request completed successfully")
// Structured key-value pairs (recommended)
sugar.Infow("user action",
"username", "alice",
"action", "login",
"ip", "192.168.1.1",
"success", true,
)
// With context
requestLogger := sugar.With(
"request_id", "abc-123",
"method", "POST",
)
requestLogger.Info("handling request")
requestLogger.Errorw("validation failed", "field", "email")A function type that implements the zapcore.LevelEnabler interface, useful for creating custom level filters.
// LevelEnablerFunc is a convenient way to implement zapcore.LevelEnabler with
// an anonymous function. Particularly useful when splitting log output between
// different outputs (e.g., standard error and standard out).
type LevelEnablerFunc func(zapcore.Level) bool
// Enabled calls the function to determine if the given level is enabled
func (f LevelEnablerFunc) Enabled(lvl zapcore.Level) bool// Split logs between stdout (info and below) and stderr (warn and above)
highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl >= zapcore.WarnLevel
})
lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl < zapcore.WarnLevel
})
// Use with separate cores
highCore := zapcore.NewCore(encoder, stderr, highPriority)
lowCore := zapcore.NewCore(encoder, stdout, lowPriority)
logger := zap.New(zapcore.NewTee(highCore, lowCore))AtomicLevel provides thread-safe runtime log level changes and can serve as an HTTP endpoint.
type AtomicLevel struct {
// Has unexported fields
}// Create AtomicLevel at InfoLevel
func NewAtomicLevel() AtomicLevel
// Create AtomicLevel at specific level
func NewAtomicLevelAt(l zapcore.Level) AtomicLevel
// Parse AtomicLevel from string
func ParseAtomicLevel(text string) (AtomicLevel, error)// Get current minimum enabled level
func (lvl AtomicLevel) Level() zapcore.Level
// Set minimum enabled level (thread-safe)
func (lvl AtomicLevel) SetLevel(l zapcore.Level)
// Check if level is enabled (implements LevelEnabler)
func (lvl AtomicLevel) Enabled(l zapcore.Level) bool
// Get string representation
func (lvl AtomicLevel) String() string
// Marshal to text
func (lvl AtomicLevel) MarshalText() ([]byte, error)
// Unmarshal from text
func (lvl AtomicLevel) UnmarshalText(text []byte) error
// HTTP handler for GET (query level) and PUT (change level)
func (lvl AtomicLevel) ServeHTTP(w http.ResponseWriter, r *http.Request)// Create config with atomic level
config := zap.NewProductionConfig()
config.Level = zap.NewAtomicLevelAt(zap.InfoLevel)
logger, _ := config.Build()
// Change level at runtime
config.Level.SetLevel(zap.DebugLevel)
// Serve HTTP endpoint to change log level
http.Handle("/log/level", config.Level)
// GET /log/level returns current level as JSON
// PUT /log/level with JSON body {"level": "debug"} changes levelThe Config type provides declarative logger construction with JSON/YAML support.
type Config struct {
Level AtomicLevel `json:"level" yaml:"level"`
Development bool `json:"development" yaml:"development"`
DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
Encoding string `json:"encoding" yaml:"encoding"`
EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
}// Create preset configurations
func NewProductionConfig() Config
func NewDevelopmentConfig() Config
// Build logger from config
func (cfg Config) Build(opts ...Option) (*Logger, error)type SamplingConfig struct {
Initial int `json:"initial" yaml:"initial"`
Thereafter int `json:"thereafter" yaml:"thereafter"`
Hook func(zapcore.Entry, zapcore.SamplingDecision) `json:"-" yaml:"-"`
}// Start with preset config
config := zap.NewProductionConfig()
// Customize
config.OutputPaths = []string{"stdout", "/var/log/app.log"}
config.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
config.InitialFields = map[string]interface{}{
"app": "myservice",
"version": "1.2.3",
}
// Build logger
logger, err := config.Build()
if err != nil {
panic(err)
}
// Load from JSON
configJSON := []byte(`{
"level": "info",
"encoding": "json",
"outputPaths": ["stdout"],
"errorOutputPaths": ["stderr"],
"initialFields": {"service": "api"}
}`)
var cfg zap.Config
if err := json.Unmarshal(configJSON, &cfg); err != nil {
panic(err)
}
logger, _ = cfg.Build()Options configure Logger behavior. They can be passed to constructors or applied with WithOptions.
type Option interface {
// Has unexported method
}// Core modification
func WrapCore(f func(zapcore.Core) zapcore.Core) Option
// Hooks for side effects
func Hooks(hooks ...func(zapcore.Entry) error) Option
// Add fields to all log entries
func Fields(fs ...Field) Option
// Set error output destination
func ErrorOutput(w zapcore.WriteSyncer) Option
// Enable development mode
func Development() Option
// Caller annotation
func AddCaller() Option
func WithCaller(enabled bool) Option
func AddCallerSkip(skip int) Option
// Stack traces
func AddStacktrace(lvl zapcore.LevelEnabler) Option
// Increase minimum level
func IncreaseLevel(lvl zapcore.LevelEnabler) Option
// Custom hooks for panic and fatal
func WithPanicHook(hook zapcore.CheckWriteHook) Option
func WithFatalHook(hook zapcore.CheckWriteHook) Option
// Custom clock for timestamps
func WithClock(clock zapcore.Clock) Optionlogger := zap.NewExample(
zap.AddCaller(),
zap.AddStacktrace(zap.ErrorLevel),
zap.Fields(
zap.String("app", "myservice"),
zap.Int("version", 2),
),
)
// Add options to existing logger
logger = logger.WithOptions(
zap.AddCallerSkip(1),
zap.Hooks(func(entry zapcore.Entry) error {
// Custom side effect, e.g., metrics
if entry.Level >= zapcore.ErrorLevel {
errorCounter.Inc()
}
return nil
}),
)Zap provides global loggers accessible via functions.
// Get global Logger
func L() *Logger
// Get global SugaredLogger
func S() *SugaredLogger
// Replace global loggers (returns restore function)
func ReplaceGlobals(logger *Logger) func()// Initialize global logger at startup
logger, _ := zap.NewProduction()
defer logger.Sync()
// Replace globals
undo := zap.ReplaceGlobals(logger)
defer undo()
// Access from anywhere in application
zap.L().Info("using global logger")
zap.S().Infow("using global sugared logger", "key", "value")// Redirect standard library log to zap at InfoLevel
func RedirectStdLog(l *Logger) func()
// Redirect standard library log to zap at specified level
func RedirectStdLogAt(l *Logger, level zapcore.Level) (func(), error)
// Create *log.Logger writing to zap at InfoLevel
func NewStdLog(l *Logger) *log.Logger
// Create *log.Logger writing to zap at specified level
func NewStdLogAt(l *Logger, level zapcore.Level) (*log.Logger, error)logger, _ := zap.NewProduction()
// Redirect all standard log calls to zap
undo := zap.RedirectStdLog(logger)
defer undo()
// Now standard library log calls use zap
log.Println("this goes through zap")
// Or create a new *log.Logger backed by zap
stdLogger := zap.NewStdLog(logger)
stdLogger.Println("logged via zap")// Get production encoder config
func NewProductionEncoderConfig() zapcore.EncoderConfig
// Get development encoder config
func NewDevelopmentEncoderConfig() zapcore.EncoderConfigProduction encoder config produces JSON logs with:
level: Lowercase level namets: Unix timestamp (seconds)msg: Log messagecaller: Short file:line (if enabled)stacktrace: Stack trace (if enabled)Development encoder config produces console logs with:
// Combine multiple WriteSyncers into one
func CombineWriteSyncers(writers ...zapcore.WriteSyncer) zapcore.WriteSyncer
// Open output paths (files or URLs) and return WriteSyncer
func Open(paths ...string) (zapcore.WriteSyncer, func(), error)
// Register custom encoder
func RegisterEncoder(name string, constructor func(zapcore.EncoderConfig) (zapcore.Encoder, error)) error
// Register custom sink (output destination)
func RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error
// Flag support for log level
func LevelFlag(name string, defaultLevel zapcore.Level, usage string) *zapcore.Leveltype Sink interface {
zapcore.WriteSyncer
io.Closer
}Fields are used for structured logging context. See fields.md for all field constructors.
type Field = zapcore.Field