or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

fields.mdindex.mdintegrations.mdlogger.mdtesting.mdzapcore.md
tile.json

logger.mddocs/

Core Logging API

This document covers the main logging APIs: Logger, SugaredLogger, configuration, and runtime level management.

Logger

The Logger type provides fast, strongly-typed, structured logging. All methods are safe for concurrent use.

type Logger struct {
    // All fields are unexported
}

Logger Construction

// 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

Logger Methods

Logging Methods

// 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

Child Loggers and Context

// 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

Logger Configuration

// Clone logger and apply options
func (log *Logger) WithOptions(opts ...Option) *Logger

// Convert to more ergonomic SugaredLogger
func (log *Logger) Sugar() *SugaredLogger

Logger Inspection

// 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

Logger Usage Examples

// 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"

SugaredLogger

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
}

SugaredLogger Methods

Printf-style Logging

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{})

Print-style Logging

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{})

Println-style Logging

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{})

Structured Logging with Key-Value Pairs

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{})

Context and Configuration

// 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() error

SugaredLogger Usage Examples

logger, _ := 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")

LevelEnablerFunc

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

LevelEnablerFunc Usage Example

// 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

AtomicLevel provides thread-safe runtime log level changes and can serve as an HTTP endpoint.

type AtomicLevel struct {
    // Has unexported fields
}

AtomicLevel Construction

// 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)

AtomicLevel Methods

// 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)

AtomicLevel Usage Examples

// 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 level

Configuration

The 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"`
}

Config Fields

  • Level: Atomic, dynamic minimum logging level
  • Development: Enable development mode (DPanic panics, more stack traces)
  • DisableCaller: Disable automatic caller annotation (file:line)
  • DisableStacktrace: Disable automatic stack trace capture
  • Sampling: Sampling configuration for rate limiting (nil disables)
  • Encoding: Encoder name ("json", "console", or registered custom)
  • EncoderConfig: Encoder-specific configuration
  • OutputPaths: Log output destinations (file paths or URLs)
  • ErrorOutputPaths: Destinations for internal logger errors
  • InitialFields: Fields added to all log entries

Config Methods and Functions

// Create preset configurations
func NewProductionConfig() Config
func NewDevelopmentConfig() Config

// Build logger from config
func (cfg Config) Build(opts ...Option) (*Logger, error)

SamplingConfig

type SamplingConfig struct {
    Initial    int                                           `json:"initial" yaml:"initial"`
    Thereafter int                                           `json:"thereafter" yaml:"thereafter"`
    Hook       func(zapcore.Entry, zapcore.SamplingDecision) `json:"-" yaml:"-"`
}
  • Initial: Number of messages to log per second before sampling
  • Thereafter: Log every Nth message after Initial threshold
  • Hook: Optional callback for each sampling decision

Configuration Usage Examples

// 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

Options configure Logger behavior. They can be passed to constructors or applied with WithOptions.

type Option interface {
    // Has unexported method
}

Option Constructors

// 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) Option

Options Usage Examples

logger := 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
    }),
)

Global Logger Functions

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()

Global Logger Usage

// 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")

Standard Library Integration

Standard log Package Redirection

// 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)

Standard Library Integration Examples

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")

Encoder Configuration

// Get production encoder config
func NewProductionEncoderConfig() zapcore.EncoderConfig

// Get development encoder config
func NewDevelopmentEncoderConfig() zapcore.EncoderConfig

Production encoder config produces JSON logs with:

  • level: Lowercase level name
  • ts: Unix timestamp (seconds)
  • msg: Log message
  • caller: Short file:line (if enabled)
  • stacktrace: Stack trace (if enabled)

Development encoder config produces console logs with:

  • Uppercase colored level
  • ISO8601 timestamp
  • Abbreviated caller

Utility Functions

// 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.Level

Sink Interface

type Sink interface {
    zapcore.WriteSyncer
    io.Closer
}

Field Type

Fields are used for structured logging context. See fields.md for all field constructors.

type Field = zapcore.Field