Modern Structured Logging in Go with log/slog
"Complete guide to structured logging with Go 1.21+ log/slog: JSON handlers, performance tuning, context propagation, and data redaction."
Modern Structured Logging in Go with log/slog
With the release of Go 1.21, the standard library introduced log/slog, bringing native, high-performance structured logging to the standard distribution and eliminating the mandatory requirement for third-party dependencies like uber-go/zap or rs/zerolog in most projects.
Structured logging outputs machine-readable key-value pairs (typically JSON), making logs indexable and queryable in tools like Datadog, ElasticSearch, and Grafana Loki.
Core Concepts of log/slog
log/slog separates logging into two main abstractions:
Logger: The frontend API providing log methods (Info,Warn,Error,Debug).Handler: The backend processor that formats records into text, JSON, or downstream network streams.
slog.InfoContext(ctx, "msg", attrs...)
│
▼
[ slog.Record ]
│
▼
[ slog.Handler (JSON / Text) ]
│
▼
[ stdout / io.Writer ]
Setting Up JSON Structured Logging
package main
import (
"context"
"log/slog"
"os"
)
func main() {
opts := &slog.HandlerOptions{
Level: slog.LevelInfo,
AddSource: true, // Includes file name and line number
}
// Create JSON handler targeting stdout
handler := slog.NewJSONHandler(os.Stdout, opts)
logger := slog.New(handler)
// Set as global default logger
slog.SetDefault(logger)
slog.Info("server starting",
"port", 8080,
"env", "production",
)
}
JSON Output
{
"time": "2026-09-02T12:00:00.000Z",
"level": "INFO",
"source": {"function": "main.main", "file": "main.go", "line": 21},
"msg": "server starting",
"port": 8080,
"env": "production"
}
Strongly-Typed Attributes vs. Loose Key-Values
While slog.Info("msg", "key", "value") is convenient, it allocates memory due to any boxing. In performance-critical hot paths, use strongly-typed attributes:
// Loosely typed (heap escapes)
slog.Info("user logged in", "user_id", 42, "role", "admin")
// Strongly typed (zero allocations for primitives)
slog.Info("user logged in",
slog.Int64("user_id", 42),
slog.String("role", "admin"),
)
Masking Sensitive Data with slog.LogValuer
In compliance environments (PCI-DSS, GDPR, HIPAA), credentials, passwords, and API tokens must never appear in clear text. slog provides the LogValuer interface to customize serialization:
package auth
import "log/slog"
type Password string
// LogValue implements slog.LogValuer to prevent accidental leaking
func (p Password) LogValue() slog.Value {
return slog.StringValue("REDACTED")
}
type User struct {
ID string
Email string
Password Password
}
func (u User) LogValue() slog.Value {
return slog.GroupValue(
slog.String("id", u.ID),
slog.String("email", u.Email),
slog.Any("password", u.Password), // Will output REDACTED
)
}
Context-Aware Logging Middleware
A standard requirement in backend microservices is attaching request-scoped TraceID and TenantID to every log line without passing arguments manually.
package logging
import (
"context"
"log/slog"
)
type ContextHandler struct {
slog.Handler
}
func (h *ContextHandler) Handle(ctx context.Context, r slog.Record) error {
// Extract TraceID if present in context
if traceID, ok := ctx.Value("trace_id").(string); ok {
r.AddAttrs(slog.String("trace_id", traceID))
}
return h.Handler.Handle(ctx, r)
}
Performance Comparison: slog vs zap vs zerolog
BenchmarkJSONLogging/slog-16 8,901,234 134 ns/op 0 allocs/op (with Attrs)
BenchmarkJSONLogging/zap-16 10,210,432 118 ns/op 0 allocs/op
BenchmarkJSONLogging/zerolog-16 11,450,120 98 ns/op 0 allocs/op
Recommendation
For 95% of applications, log/slog in the standard library delivers top-tier performance with zero external dependency baggage. For ultra-low latency requirements, zap or zerolog remain slightly faster due to manual buffer pooling optimizations.
Conclusion
With log/slog, Go finally provides an enterprise-ready, context-aware structured logger built right into the runtime. Standardize on slog, leverage slog.LogValuer for security redaction, and pass context.Context through every log call.
About the Author
huud
@huud
Systems architect and software engineer building high-performance distributed platforms.