rdev/internal/logging/config.go
jordan d69da6d627 feat: add structured logging infrastructure and SDLC extensions
Major changes:
- Add internal/logging package with field constants, context propagation,
  sensitive data auto-redaction, and per-component log levels
- Add worker timeout constants (TimeoutQuickOp, TimeoutHealthCheck, etc.)
- Extend SDLC with callback handlers, generate endpoints, and executor
- Add new cookbook trees for aeries and slackpath progression
- Add skeleton templates for queue, realtime, and microservices
- Add worker component template with async job processing
- Refactor services and handlers to use new logging infrastructure
- Split component.go into component_infra.go and component_listing.go

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 22:56:04 -07:00

91 lines
2.4 KiB
Go

package logging
import (
"strings"
"github.com/orchard9/rdev/internal/envutil"
)
// Config holds logging configuration.
type Config struct {
// Level is the default log level.
Level Level
// Format is the output format (json or text).
Format Format
// ComponentLevels overrides log levels per component.
// Example: {"handlers": LevelDebug, "worker": LevelWarn}
ComponentLevels map[string]Level
// RedactEnabled enables automatic redaction of sensitive data.
RedactEnabled bool
// AddSource adds source file/line to log entries (performance impact).
AddSource bool
}
// DefaultConfig returns sensible defaults for production.
func DefaultConfig() Config {
return Config{
Level: LevelInfo,
Format: FormatJSON,
ComponentLevels: make(map[string]Level),
RedactEnabled: true,
AddSource: false,
}
}
// ConfigFromEnv creates a Config from environment variables.
//
// Environment variables:
// - LOG_LEVEL: default level (debug, info, warn, error)
// - LOG_FORMAT: output format (json, text)
// - LOG_LEVELS: per-component levels (handlers:debug,worker:warn)
// - LOG_REDACT: enable/disable sensitive data redaction (true/false)
// - LOG_SOURCE: add source file/line to logs (true/false)
func ConfigFromEnv() Config {
cfg := DefaultConfig()
cfg.Level = ParseLevel(envutil.GetEnv("LOG_LEVEL", "info"))
cfg.Format = ParseFormat(envutil.GetEnv("LOG_FORMAT", "json"))
cfg.RedactEnabled = envutil.GetEnvBool("LOG_REDACT", true)
cfg.AddSource = envutil.GetEnvBool("LOG_SOURCE", false)
// Parse per-component log levels: "handlers:debug,worker:warn"
if levels := envutil.GetEnv("LOG_LEVELS", ""); levels != "" {
cfg.ComponentLevels = parseComponentLevels(levels)
}
return cfg
}
// parseComponentLevels parses a comma-separated list of component:level pairs.
func parseComponentLevels(s string) map[string]Level {
result := make(map[string]Level)
for pair := range strings.SplitSeq(s, ",") {
pair = strings.TrimSpace(pair)
if pair == "" {
continue
}
parts := strings.SplitN(pair, ":", 2)
if len(parts) != 2 {
continue
}
component := strings.TrimSpace(parts[0])
level := ParseLevel(parts[1])
if component != "" {
result[component] = level
}
}
return result
}
// LevelFor returns the log level for a component, falling back to the default.
func (c Config) LevelFor(component string) Level {
if level, ok := c.ComponentLevels[component]; ok {
return level
}
return c.Level
}