From 8a09b6f8b2f2b3aec497be54df6296f5eee8bf3b Mon Sep 17 00:00:00 2001 From: Ethan Reesor Date: Fri, 5 Jul 2024 20:21:55 +0000 Subject: [PATCH] Fix stdlog/slog [#3612] Closes #3612. Fixes an issue where `log.Println` messages disappear. Changelog: fix --- cmd/accumulated/run/logging.go | 12 ++++++++++++ internal/logging/slog.go | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/cmd/accumulated/run/logging.go b/cmd/accumulated/run/logging.go index ca7767eba..0c23a6ba2 100644 --- a/cmd/accumulated/run/logging.go +++ b/cmd/accumulated/run/logging.go @@ -9,6 +9,7 @@ package run import ( "encoding/json" "io" + "log" "log/slog" "os" "strings" @@ -71,6 +72,17 @@ func (l *Logging) start(inst *Instance) error { inst.logger = slog.New(h) slog.SetDefault(inst.logger) + // [slog.SetDefault] also sets the [log] output to pass all [log] messages + // through [slog]. By default this bridge logs [log] calls with level INFO. + // Which means all [log] calls will get dropped if the [slog] level is + // greater than INFO. The log level of the bridge can be changed (before the + // call to [slog.SetDefault]) via [slog.SetLogLoggerLevel], but IMO setting + // the default level to something more severe (i.e. WARN or ERROR) is not a + // good solution. So instead, we set the [log] output to + // [logging.StdlogWriter] which cooperates with [logging]'s [slog.Handler] + // to exclude [log] messages from filtering. + log.SetOutput(&logging.StdlogWriter{Handler: h}) + return nil } diff --git a/internal/logging/slog.go b/internal/logging/slog.go index 3a793cfeb..7feded234 100644 --- a/internal/logging/slog.go +++ b/internal/logging/slog.go @@ -10,7 +10,9 @@ import ( "context" "fmt" "io" + stdlog "log" "log/slog" + "runtime" "strings" "time" @@ -130,6 +132,9 @@ func (h *logHandler) WithGroup(name string) slog.Handler { } func (h *logHandler) Enabled(ctx context.Context, level slog.Level) bool { + if ctx.Value(isStdlog) != nil { + return true + } if level < h.lowestLevel { return false } @@ -141,7 +146,8 @@ func (h *logHandler) Enabled(ctx context.Context, level slog.Level) bool { func (h *logHandler) Handle(ctx context.Context, record slog.Record) error { record.AddAttrs(Attrs(ctx)...) - if record.Level < h.levelFor(h.defaultLevel, record.Attrs) { + if ctx.Value(isStdlog) == nil && + record.Level < h.levelFor(h.defaultLevel, record.Attrs) { return nil } @@ -194,3 +200,29 @@ func (h *logHandler) levelFor(level slog.Level, fn func(func(slog.Attr) bool)) s }) return level } + +var isStdlog _contextKey + +type StdlogWriter struct { + Handler slog.Handler +} + +func (w *StdlogWriter) Write(buf []byte) (int, error) { + var pc uintptr + if stdlog.Flags()&(stdlog.Lshortfile|stdlog.Llongfile) != 0 { + // skip [runtime.Callers, w.Write, Logger.Output, log.Print] + var pcs [1]uintptr + runtime.Callers(4, pcs[:]) + pc = pcs[0] + } + + // Remove final newline. + origLen := len(buf) // Report that the entire buf was written. + if len(buf) > 0 && buf[len(buf)-1] == '\n' { + buf = buf[:len(buf)-1] + } + + ctx := context.WithValue(context.Background(), isStdlog, true) + r := slog.NewRecord(time.Now(), slog.LevelInfo, string(buf), pc) + return origLen, w.Handler.Handle(ctx, r) +}