fix(logger): wide event source points at StartWideEvent caller + tests#6269
fix(logger): wide event source points at StartWideEvent caller + tests#6269Flo4604 wants to merge 1 commit into
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
The wide event system emits its accumulated log from End(), which is almost always a deferred call inside middleware. Calling logger.Error / logger.Info from event.go meant slog captured the PC of those lines, so every wide event's source attribute resolved to pkg/logger/event.go:103 — useless for finding the actual handler. Capture the PC at StartWideEvent instead, store it on the Event, and build the slog.Record manually in End() with that PC. Source now points at the middleware/handler that opened the event. Tests: - pkg/logger/loggertest: shared CaptureHandler + FlatAttrs/PCFrame helpers so callers across services can assert on emitted log records without redefining a handler in every test file. - pkg/logger: faultHandler enrichment (fault errors, plain errors, no errors, multiple errors, slog.Attr-wrapped errors, multi-sink fan-out) and source PC attribution for logger.Error aliases and wide events. - svc/api/internal/middleware: errors middleware emits a 500 log with workspaceId/requestId/code/publicMessage/http.* group, stashes the full internal error chain on the session, and stays silent on 4xx.
5b9925c to
bff0013
Compare
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — initial review of the wide-event source fix and its accompanying test infrastructure. The change correctly redirects the emitted log's source attribute at the StartWideEvent caller instead of the internal Handle call site, and the new tests pin down both the PC plumbing and the surrounding fault-enrichment behavior end-to-end.
- Capture caller PC at
StartWideEvent—runtime.Callers(2, pcs[:])stores the caller's PC onEvent.pc;End()now builds aslog.Recordmanually so the captured PC survives instead of being overwritten bylogger.Error/Infoinsideevent.go. End()rewrite — switched from variadic[]anyto a typed[]slog.Attr, added an explicitEnabledshort-circuit, and dispatched vialogger.Handler().Handle(ctx, r)to preserve the captured PC. Existing semantics around message ("error"vs supplied) anderrors.<n>grouping are preserved.- New
pkg/logger/loggertestpackage — sharedCaptureHandlerplusInstall,Last,Find,Snapshot/Since,FlatAttrs, andPCFramehelpers. Lives outsidepkg/loggerso production code can't depend on it, and the doc is explicit about the global-state lifecycle (no teardown, scope via snapshot indices). pkg/loggerunit tests —faultHandlerenrichment across fault errors, plain errors, no-error records, multi-error precedence, multi-sink fan-out, andslog.Any-wrapped errors; PC attribution for thelogger.Erroralias and for wide events; double-End()idempotency.svc/api/internal/middlewareunit tests — first coverage forWithErrorHandling: 500 emits the fullworkspaceId/requestId/code/publicMessage/http.*attribute set with the fault chain attached via the global enrichment handler; the full internal error chain is stashed viaSetInternalError; 4xx (key-not-found) is silent.- Bazel —
go_testtargets added in bothpkg/logger/BUILD.bazelandsvc/api/internal/middleware/BUILD.bazel, plus a newpkg/logger/loggertest/BUILD.bazel.
Verified the PC skip count (2 is correct for a direct caller of StartWideEvent), the faultHandler does not double-enrich wide events because errors live inside the errors group (top-level Record.Attrs walk only), and MultiHandler.Enabled short-circuits don't suppress CaptureHandler (always returns true). The discarded runtime.Callers return value is benign — pcs[0] stays zero on the unlikely empty result, and the wide-event test explicitly asserts NotZero to catch that path.
Claude Opus | 𝕏

The wide event system emits its accumulated log from End(), which is almost always a deferred call inside middleware. Calling logger.Error / logger.Info from event.go meant slog captured the PC of those lines, so every wide event's source attribute resolved to pkg/logger/event.go:103 which is useless for finding the actual handler.
Capture the PC at StartWideEvent instead, store it on the Event, and build the slog.Record manually in End() with that PC. Source now points at the middleware/handler that opened the event.
Add unit tests:
pkg/logger: faultHandler enrichment (fault errors, plain errors, no errors, multiple errors, slog.Attr-wrapped errors, multi-sink fan-out) and source PC attribution for logger.Error aliases and wide events.
svc/api/internal/middleware: errors middleware emits a 500 log with workspaceId/requestId/code/publicMessage/http.* group, stashes the full internal error chain on the session, and stays silent on 4xx.