go.missing_structured_logging
Observability
Low
Detects usage of fmt.Println/log.Print instead of structured logging (zerolog/zap/slog).
Why It Matters
Section titled “Why It Matters”Unstructured logs are hard to work with:
- Not queryable — Can’t search for specific fields
- Not aggregatable — Can’t count or group events
- Not alertable — Can’t set conditions on values
- Parsing hell — Regex extraction is fragile
Modern observability requires structured data with consistent fields.
Example
Section titled “Example”// ❌ Beforefmt.Printf("User %s logged in\n", userID)log.Printf("Error: %v", err)These are impossible to filter or aggregate in your logging system.
// ✅ After (zerolog)import "github.com/rs/zerolog/log"
log.Info().Str("user_id", userID).Msg("user logged in")log.Error().Err(err).Msg("operation failed")Now you can query user_id:123 or count login events by user.
What Unfault Detects
Section titled “What Unfault Detects”fmt.Print,fmt.Printf,fmt.Printlnlog.Print,log.Printf,log.Printlnlog.Fatal,log.Panic(also replace with structured)
Auto-Fix
Section titled “Auto-Fix”Unfault converts print statements to zerolog calls.
Recommended Libraries
Section titled “Recommended Libraries”// zerolog - Fast, structured, zero allocationimport "github.com/rs/zerolog/log"log.Info().Str("key", "value").Msg("message")
// zap - Uber's high-performance loggerimport "go.uber.org/zap"logger, _ := zap.NewProduction()logger.Info("message", zap.String("key", "value"))
// slog - Standard library (Go 1.21+)import "log/slog"slog.Info("message", "key", "value")Configuration
Section titled “Configuration”// zerolog with pretty console for devzerolog.TimeFieldFormat = zerolog.TimeFormatUnixlog.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
// Production JSON outputlog.Logger = zerolog.New(os.Stdout).With().Timestamp().Logger()