Structured Logging Done Right

Why structured logs matter and how to implement them without overcomplicating things.

Key Insights

  • Structured logs (JSON) are for querying; if you ever need to search your logs at scale, structure them from the start
  • Log at boundaries (HTTP handlers, queue consumers, jobs) with consistent field names and include request/user context
  • Go’s standard library slog package (1.21+) provides structured logging without third-party dependencies

Plain text logs are fine for reading. Structured logs are for querying. If you ever need to search your logs (you will), structure them from the start.

What Structured Logging Looks Like

Instead of:

2025-12-22 10:30:15 ERROR Failed to process order 12345 for user john@example.com: insufficient funds

Emit:

{"time":"2025-12-22T10:30:15Z","level":"error","msg":"failed to process order","order_id":"12345","user":"john@example.com","reason":"insufficient_funds"}

Go’s slog Package

Since Go 1.21, the standard library includes structured logging:

logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelInfo,
}))

logger.Info("order processed",
    slog.String("order_id", order.ID),
    slog.Int("items", len(order.Items)),
    slog.Duration("duration", elapsed),
)

Key Principles

  1. Log at boundaries: HTTP handlers, queue consumers, scheduled jobs
  2. Include context: Request IDs, user IDs, operation names
  3. Use consistent field names: user_id everywhere, not sometimes userId
  4. Log the outcome, not the attempt: “order processed” not “processing order”
  5. Levels matter: ERROR for things that need attention, INFO for business events, DEBUG for development

What Not to Log

  • Passwords, tokens, or secrets
  • Full request/response bodies in production
  • Every iteration of a loop
  • Things you’ll never search for

Structured logging is a foundation for observability. Get it right early and debugging production issues becomes significantly easier.

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.