Go (Golang) Tutorial 0/45 lessons ~6 min read Lesson 37

    Logging

    Go 1.21 introduced log/slog — structured logging in the standard library.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Go 1.21 introduced log/slog — structured logging in the standard library. Replace fmt.Println debugging with leveled logs (Debug, Info, Warn, Error) carrying key-value attributes queryable in ELK, Loki, and CloudWatch.

    Production logging adds request correlation IDs via middleware, logs errors with stack context, and never logs secrets. The legacy log package still appears in older codebases — know both, prefer slog for new projects.

    Interviewers ask structured vs unstructured logging, log levels, and correlation in distributed systems — this lesson implements slog with JSON handler for production output.

    The story

    When a Google SRE debugs a failing gRPC call at 2 AM, structured JSON logs with fields like {"service":"payments","trace_id":"abc","latency_ms":842} let them filter in Datadog instantly. Go 1.21+ log/slog replaces ad-hoc fmt.Printf with leveled, structured logging — the standard for Kubernetes operators and microservices.

    Log at appropriate levels: DEBUG for development, INFO for business events, ERROR for failures with stack context — never log secrets or PII in production.

    Understanding the topic

    Key concepts

    • slog.Info(msg, key, val, key, val) structured key-value pairs.
    • slog.NewJSONHandler writes JSON lines to io.Writer.
    • Log levels: Debug, Info, Warn, Error — filter by minimum level.
    • slog.WithGroup and With attrs add persistent context.
    • Context-scoped logger via middleware stored in context.
    • Never log passwords, tokens, PAN, or full PII.
    text
    sequenceDiagram
    Client->>Server: HTTP Request
    Server->>Handler: ServeHTTP
    Handler->>Service: Business Logic
    Service->>DB: Query
    DB-->>Handler: Data
    Handler-->>Client: JSON Response

    Step-by-step explanation

    1. Create handler: slog.NewJSONHandler(os.Stdout, opts).
    2. Default logger: slog.SetDefault(slog.New(handler)).
    3. Middleware extracts/generates request ID, adds to logger.
    4. Handler logs request start/end with duration and status.
    5. Error logs include err attribute and operation context.
    6. Production ships JSON logs to centralized aggregation.

    Practical code example

    Structured logging with slog JSON handler and request middleware:

    go
    package main
    import (
    "log/slog"
    "net/http"
    "os"
    "time"
    )
    func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    start := time.Now()
    reqID := r.Header.Get("X-Request-ID")
    if reqID == "" {
    reqID = "gen-" + time.Now().Format("150405")
    }
    logger := slog.With("request_id", reqID, "method", r.Method, "path", r.URL.Path)
    logger.Info("request started")
    next.ServeHTTP(w, r)
    logger.Info("request completed", "duration_ms", time.Since(start).Milliseconds())
    })
    }
    func main() {
    handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo})
    slog.SetDefault(slog.New(handler))
    mux := http.NewServeMux()
    mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("ok"))
    })
    slog.Info("server starting", "port", 8080)
    http.ListenAndServe(":8080", loggingMiddleware(mux))
    }

    Line-by-line code explanation

    • slog.Info("request handled", "method", r.Method, "path", r.URL.Path) logs structured key-value pairs.
    • slog.Error("db query failed", "err", err) records errors with context fields.
    • logger := slog.With("service", "payments") creates a child logger with bound fields.
    • slog.NewJSONHandler(os.Stdout, opts) emits JSON lines for log aggregators like Loki or CloudWatch.
    • slog.SetDefault(logger) configures the global logger for packages using slog.Info directly.
    • log/slog levels: Debug, Info, Warn, Error — filter by level in production.
    • context-aware logging — attach trace IDs from context values in middleware.
    • avoid fmt.Sprintf in hot paths — structured handlers defer formatting until the level is enabled.

    Key takeaway: JSON logs parse in Loki/ELK. Add request_id for distributed tracing correlation. Set Level Debug in dev, Info in prod.

    Real-world use

    Where you'll use this in production

    • Centralized logging in Kubernetes with Fluent Bit sidecar.
    • Audit trails for financial transaction services.
    • Debugging production incidents with request ID search.
    • SLI/SLO monitoring from structured log metrics.

    Best practices

    • Use slog structured attributes, not fmt.Sprintf in logs.
    • Consistent field names: request_id, user_id, duration_ms.
    • Log level appropriate: Error for failures, Info for business events.
    • Redact sensitive fields before logging.
    • One log line per event — avoid multi-line unstructured dumps.
    • Integrate with OpenTelemetry for logs+traces correlation.

    Common mistakes

    • Logging inside tight loops at Info level — noise and cost.
    • String interpolation instead of structured fields.
    • Logging full request bodies with passwords.
    • No correlation ID — impossible to trace distributed requests.
    • Debug logs left on in production overwhelming storage.

    Advanced interview questions

    Q1Beginnerslog vs log package?
    slog structured leveled logging; log legacy unstructured — prefer slog for new code.
    Q2BeginnerWhy structured logging?
    Queryable fields in log aggregation; machine-parseable JSON.
    Q3IntermediateCorrelation ID pattern?
    Middleware reads/generates ID; adds to slog attrs and response header.
    Q4IntermediateLogs vs metrics vs traces?
    Logs discrete events; metrics aggregated numbers; traces request spans.
    Q5AdvancedLogging for PCI-compliant payment service.
    No PAN/CVV; tokenized IDs; separate immutable audit log; retention policy.

    Summary

    log/slog provides structured leveled logging in stdlib. JSON handler outputs machine-parseable production logs. Middleware adds request_id for correlation. Never log secrets; redact PII consistently. Next lesson: dependency injection patterns.

    Ready to mark this lesson complete?Track your journey across the entire course.