Troubleshooting
5 minute read
Common issues and solutions when using the logging package.
Logs Not Appearing
Debug Logs Not Showing
Problem: Debug logs don’t appear in output.
Cause: Log level is set higher than Debug.
Solution: Enable debug level:
logger := logging.MustNew(
logging.WithJSONHandler(),
logging.WithDebugLevel(), // Enable debug logs
)
Or check current level:
currentLevel := logger.Level()
fmt.Printf("Current level: %s\n", currentLevel)
No Logs at All
Problem: No logs appear, even errors.
Possible causes:
- Logger shutdown: Check if logger was shut down.
if !logger.IsEnabled() {
fmt.Println("Logger is shut down")
}
- Wrong output: Verify output destination.
logger := logging.MustNew(
logging.WithOutput(os.Stdout), // Not stderr
)
- Sampling too aggressive: Check sampling configuration.
info := logger.DebugInfo()
if sampling, ok := info["sampling"]; ok {
fmt.Printf("Sampling: %+v\n", sampling)
}
Logs Disappear After Some Time
Problem: Logs stop appearing after initial burst.
Cause: Log sampling is dropping logs.
Solution: Adjust sampling or disable:
// Less aggressive sampling
logger := logging.MustNew(
logging.WithSampling(logging.SamplingConfig{
Initial: 1000,
Thereafter: 10, // 10% instead of 1%
Tick: time.Minute,
}),
)
// Or disable sampling
logger := logging.MustNew(
logging.WithJSONHandler(),
// No WithSampling() call
)
Sensitive Data Issues
Sensitive Data Not Redacted
Problem: Custom sensitive fields not being redacted.
Cause: Only built-in fields are automatically redacted.
Solution: Add custom redaction:
logger := logging.MustNew(
logging.WithJSONHandler(),
logging.WithReplaceAttr(func(groups []string, a slog.Attr) slog.Attr {
// Redact custom fields
if a.Key == "credit_card" || a.Key == "ssn" {
return slog.String(a.Key, "***REDACTED***")
}
return a
}),
)
Built-in redacted fields:
passwordtokensecretapi_keyauthorization
Too Much Redaction
Problem: Fields being redacted unnecessarily.
Cause: Field names match redaction patterns.
Solution: Rename fields to avoid keywords:
// Instead of "token" (redacted)
log.Info("processing", "request_token_id", tokenID)
// Instead of "secret" (redacted)
log.Info("config", "shared_secret_name", secretName)
Trace Correlation Issues
No Trace IDs in Logs
Problem: Logs don’t include trace_id and span_id.
Possible causes:
- Tracing not initialized:
// Initialize tracing
tracer := tracing.MustNew(
tracing.WithOTLP("localhost:4317"),
)
defer tracer.Shutdown(context.Background())
- Not using ContextLogger:
// Wrong - plain logger
logger.Info("message")
// Right - context logger
cl := logging.NewContextLogger(ctx, logger)
cl.Info("message") // Includes trace_id and span_id
- Context has no active span:
// Start a span
ctx, span := tracer.Start(context.Background(), "operation")
defer span.End()
cl := logging.NewContextLogger(ctx, logger)
cl.Info("message") // Now includes trace IDs
Wrong Trace IDs
Problem: Trace IDs don’t match distributed trace.
Cause: Context not properly propagated.
Solution: Ensure context flows through call chain:
func handler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() // Get context with trace
// Pass context down
result := processRequest(ctx)
w.Write(result)
}
func processRequest(ctx context.Context) []byte {
// Use context
cl := logging.NewContextLogger(ctx, logger)
cl.Info("processing")
return data
}
Performance Issues
High CPU Usage
Problem: Logging causes high CPU usage.
Possible causes:
- Logging in tight loops:
// Bad - logs thousands of times
for _, item := range items {
logger.Debug("processing", "item", item)
}
// Good - log summary
logger.Info("processing batch", "count", len(items))
- Source location enabled in production:
// Bad for production
logger := logging.MustNew(
logging.WithSource(true), // Adds overhead
)
// Good for production
logger := logging.MustNew(
logging.WithJSONHandler(),
// No source location
)
- Debug level in production:
// Bad - debug logs have overhead even if filtered
logger := logging.MustNew(
logging.WithDebugLevel(),
)
// Good - appropriate level
logger := logging.MustNew(
logging.WithLevel(logging.LevelInfo),
)
High Memory Usage
Problem: Memory usage grows over time.
Possible causes:
- No log rotation: Logs written to file without rotation.
Solution: Use external log rotation (logrotate) or rotate in code:
// Use external tool like logrotate
// Or implement rotation
- Buffered output not flushed: Buffers growing without flush.
Solution: Ensure proper shutdown:
defer func() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
logger.Shutdown(ctx)
}()
Configuration Issues
Cannot Change Log Level
Problem: SetLevel returns error.
Cause: Using custom logger.
Error:
err := logger.SetLevel(logging.LevelDebug)
if errors.Is(err, logging.ErrCannotChangeLevel) {
// Custom logger doesn't support dynamic level changes
}
Solution: Control level in custom logger:
var levelVar slog.LevelVar
levelVar.Set(slog.LevelInfo)
customLogger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: &levelVar,
}))
// Change level directly
levelVar.Set(slog.LevelDebug)
Service Metadata Not Appearing
Problem: Service name, version, or environment not in logs.
Cause: Not configured or using custom logger.
Solution: Configure service metadata:
logger := logging.MustNew(
logging.WithJSONHandler(),
logging.WithServiceName("my-api"),
logging.WithServiceVersion("v1.0.0"),
logging.WithEnvironment("production"),
)
For custom logger, add metadata manually:
customLogger := slog.New(handler).With(
"service", "my-api",
"version", "v1.0.0",
"env", "production",
)
Router Integration Issues
Access Log Not Working
Problem: HTTP requests not being logged.
Possible causes:
- Logger not set on router:
r := router.MustNew()
logger := logging.MustNew(logging.WithJSONHandler())
r.SetLogger(logger) // Must set logger
- Middleware not applied:
import "rivaas.dev/router/middleware/accesslog"
r.Use(accesslog.New()) // Apply middleware
- Path excluded:
r.Use(accesslog.New(
accesslog.WithExcludePaths("/health", "/metrics"),
))
// /health and /metrics won't be logged
Context Logger Not Working
Problem: Router context logger has no trace IDs.
Cause: Tracing not initialized or middleware not applied.
Solution: Initialize tracing:
a, _ := app.New(
app.WithServiceName("my-api"),
app.WithObservability(
app.WithLogging(logging.WithJSONHandler()),
app.WithTracing(tracing.WithOTLP("localhost:4317")),
),
)
Testing Issues
Test Logs Not Captured
Problem: Logs not appearing in test buffer.
Cause: Using wrong logger instance.
Solution: Use TestHelper or ensure buffer is captured:
func TestMyFunction(t *testing.T) {
th := logging.NewTestHelper(t)
myFunction(th.Logger) // Pass test logger
logs, _ := th.Logs()
assert.Len(t, logs, 1)
}
Parse Errors
Problem: ParseJSONLogEntries returns error.
Cause: Non-JSON output or malformed JSON.
Solution: Ensure JSON handler:
th := logging.NewTestHelper(t,
logging.WithJSONHandler(), // Must be JSON
)
Error Types
ErrNilLogger
var ErrNilLogger = errors.New("custom logger is nil")
When: Providing nil custom logger.
Solution:
if customLogger != nil {
logger := logging.MustNew(
logging.WithCustomLogger(customLogger),
)
}
ErrInvalidHandler
var ErrInvalidHandler = errors.New("invalid handler type")
When: Invalid handler type specified.
Solution: Use valid handler types:
logging.WithHandlerType(logging.JSONHandler)
logging.WithHandlerType(logging.TextHandler)
logging.WithHandlerType(logging.ConsoleHandler)
ErrLoggerShutdown
var ErrLoggerShutdown = errors.New("logger is shut down")
When: Operations after shutdown.
Solution: Don’t use logger after shutdown:
defer logger.Shutdown(context.Background())
// Don't log after this point
ErrInvalidLevel
var ErrInvalidLevel = errors.New("invalid log level")
When: Invalid log level provided.
Solution: Use valid levels:
logging.LevelDebug
logging.LevelInfo
logging.LevelWarn
logging.LevelError
ErrCannotChangeLevel
var ErrCannotChangeLevel = errors.New("cannot change level on custom logger")
When: Calling SetLevel on custom logger.
Solution: Control level in custom logger directly or don’t use custom logger.
Getting Help
If you encounter issues not covered here:
- Check the API Reference for method details
- Review Examples for patterns
- See Best Practices for recommendations
- Check the GitHub issues
Debugging Tips
Enable Debug Info
info := logger.DebugInfo()
fmt.Printf("Logger state: %+v\n", info)
Check Sampling State
info := logger.DebugInfo()
if sampling, ok := info["sampling"]; ok {
fmt.Printf("Sampling config: %+v\n", sampling)
}
Verify Configuration
fmt.Printf("Service: %s\n", logger.ServiceName())
fmt.Printf("Version: %s\n", logger.ServiceVersion())
fmt.Printf("Environment: %s\n", logger.Environment())
fmt.Printf("Level: %s\n", logger.Level())
fmt.Printf("Enabled: %v\n", logger.IsEnabled())
Next Steps
- Review API Reference for complete method documentation
- Check Options for configuration details
- See Best Practices for production guidance
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.