Repository navigation
Stop dropping slog records at intermediate levels - #12624
geraldw-ai wants to merge 7 commits into
Conversation
handler.Handle() matches record.Level by exact equality against the four named slog levels, with an empty default that discards anything else and returns nil, so the caller believes the record was written. slog levels are plain ints and the API permits values between the constants, so a record at slog.LevelInfo+1 is admitted by Enabled() (which maps by range via convertSlogToZapLevel()) and then silently dropped by Handle(). Map by range in Handle() too, mirroring convertSlogToZapLevel(). Records at levels between or beyond the named constants are emitted instead of discarded; the four named levels are unaffected.
08fcf42 to
3af0ea0
Compare
|
@0xamlab Thanks for your time! |
abhisheksharma2411
left a comment
There was a problem hiding this comment.
Ran it locally and it behaves as described. I also put the old exact-match switch back with your new test in place, and it fails on all four intermediate levels — so the test is genuinely pinning the mapping, not just passing next to it.
One thing I noticed while reading, not a change request: Enabled() and Handle() still disagree in a second spot. extractZapLogger() unwraps through throttledLogger, so Enabled() asks the zap core directly while Handle() writes through h.logger, which is still the throttled one. When the limiter is out of tokens the record goes nowhere, with no log and no error — same silent shape you're fixing here, just from throttling instead of level mapping. It doesn't look reachable from the three nexus call sites today (they pass the plain logger, not the one from resource/fx.go), so same "trap for the next caller" category as the bug itself.
Small one: the logging-call-at assertion hardcodes slog_test.go:41, which is why adding an import made you edit an unrelated test. Might be worth deriving that line number so the next import doesn't do it again.
|
You're welcome — the intermediate-level cases were the gap worth pinning down. Range checks mirror convertSlogToZapLevel cleanly. |
The logging-call-at assertion hardcodes the line of the Info() call it is checking, so any edit above that point - adding an import, for instance - requires updating an otherwise unrelated assertion. Derive the line with runtime.Caller(0) instead. The assertion still discriminates: breaking the derivation makes it fail, and inserting a line above the Info() call no longer does.
…-temporal into slog-custom-levels

What changed?
handler.Handle()(common/log/slog.go) now mapsrecord.Levelby range instead of exact equality:Why?
Enabled()andHandle()disagree, and the file already contains the correct mapping.Enabled()admits a record by range:Handle()then matched by exact equality against the four named constants, with an emptydefault:andreturn nil. So a record at an intermediate level passed the gate, was reported as handled, and was never written — no log, no error, no metric.slog levels are plain
ints and the API explicitly supports values between the named constants.convertSlogToZapLevel()'s own doc comment acknowledges this and links the Go design proposal's Levels section: "there is some room between slog levels while zap levels are continuous, so we can't 1:1 map them." The handler knew about the gaps;Handle()just didn't honor them.Latent today.
NewSlogLogger()'s three call sites all feedcommon/nexus/nexusrpc(nexus_completion_http_handler.go:117,nexus_operation_http_handler.go:76,:109), which logs only via.Error()and.Warn()— and nothing in the repo logs at a non-named level, so no record is currently lost.Still worth fixing:
NewSlogLogger()is exported API, the loss is silent (no log, no error,Handle()returnsnil), andEnabled()advertises the levelsHandle()discards. A trap for the next caller, not a live defect.How did you test it?
TestSlogFromLayeredLoggerpasses before and after, but cannot catch this: it only ever logs atslog.LevelInfo, an exact-match case, so the emptydefault:is never reached.Added
TestSlogLevelMappingto the same file — table-driven over nine levels, asserting for each thatEnabled()admits it and that a record then arrives at the expected zap level. Written before the fix and run against unmodifiedmainfirst:All nine pass with the fix.
go vet ./common/log/is clean.Potential risks
Low, and confined to one method. No record that was previously logged changes level — all four named levels map identically before and after, which the new test confirms: its
debug/info/warn/errorcases pass on unmodifiedmain. The only change is that records previously discarded now appear, atzapcore.DebugLevelfor anything belowslog.LevelInfoandzapcore.ErrorLevelfor anything at or aboveslog.LevelError, followingconvertSlogToZapLevel().And since nothing in the repo emits at a non-named level, no in-repo call path changes behavior at all. The change is observable only to an external consumer of
NewSlogLogger()that logs at intermediate levels, which would see those records start appearing and a corresponding rise in log volume.