Skip to content

Commit 19fc7f8

Browse files
author
Luigi
committed
refactor: harden log package for PR#102 review fixes
- Replace bare pointer with atomic.Pointer[slog.Logger] for safe concurrent SetLevel - Move os.Getenv out of log.go into config.Config (LogFormat, LogLevel, LogSource) to satisfy getenv audit invariant - Add Configure(format, level, addSource) hook wired to cmd/api, worker, migrate - TTY auto-detect: falls back to human-readable text handler when stdout is a terminal - Add *Context family (InfoContext, WarnContext, ErrorContext, DebugContext) that inject trace_id/span_id when an OTel span is active on the context - Add otelHandler wrapper on every slog.Handler for native trace correlation - Harden Mask(): URL credential redaction (user:pass@ → ***@), prefix+suffix truncation, clamp prefix 4–20, handle empty/short strings gracefully - Add 30 test cases covering Mask, level parsing, concurrent SetLevel, JSON/text output, env config, and context enrichment (all -race clean)
1 parent b018f10 commit 19fc7f8

6 files changed

Lines changed: 658 additions & 27 deletions

File tree

cmd/api/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ func main() {
5252
if err := cfg.Validate(config.APIRequiredFields...); err != nil {
5353
log.Fatal("config validation failed", "err", err)
5454
}
55+
addSource := cfg.LogSource == "1" || cfg.LogSource == "true"
56+
log.Configure(cfg.LogFormat, cfg.LogLevel, addSource)
5557
if cfg.EncryptionKey != "" {
5658
if err := pcmicrypto.InitKey(cfg.EncryptionKey); err != nil {
5759
log.Fatal("encryption key initialization failed", "err", err)

cmd/migrate/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020

2121
func main() {
2222
cfg := config.Load()
23+
addSource := cfg.LogSource == "1" || cfg.LogSource == "true"
24+
log.Configure(cfg.LogFormat, cfg.LogLevel, addSource)
2325
if cfg.DatabaseURL == "" {
2426
log.Fatal("DATABASE_URL is required")
2527
}

cmd/worker/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ func main() {
3838
if err := cfg.Validate(config.WorkerRequiredFields...); err != nil {
3939
log.Fatal("config validation failed", "err", err)
4040
}
41+
addSource := cfg.LogSource == "1" || cfg.LogSource == "true"
42+
log.Configure(cfg.LogFormat, cfg.LogLevel, addSource)
4143
log.Info("config loaded", "db", log.Mask(cfg.DatabaseURL, 40), "redis", cfg.RedisAddr)
4244

4345
ctxTelemetry := context.Background()

internal/config/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ type Config struct {
7676

7777
// Dedup (PCMI-011): default ingest dedup mode when tenant/request omit it.
7878
DedupMode string
79+
80+
// Logging
81+
LogFormat string // "json" (default) or "text"
82+
LogLevel string // "info" (default) | "debug" | "warn" | "error"
83+
LogSource string // "1" | "true" to enable source file:line in every record
7984
}
8085

8186
// APIConfig returns the subset of fields required by the API service.
@@ -135,6 +140,10 @@ func Load() *Config {
135140
OTELServiceName: strings.TrimSpace(os.Getenv("OTEL_SERVICE_NAME")),
136141

137142
DedupMode: envOr("DEDUP_MODE", "none"),
143+
144+
LogFormat: envOr("PCMI_LOG_FORMAT", ""),
145+
LogLevel: envOr("PCMI_LOG_LEVEL", ""),
146+
LogSource: strings.TrimSpace(os.Getenv("PCMI_LOG_SOURCE")),
138147
}
139148
return cfg
140149
}

0 commit comments

Comments
 (0)