feat: reuse logger template rendering for contextual logs#4241
feat: reuse logger template rendering for contextual logs#4241ReneWerner87 wants to merge 3 commits intomainfrom
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughThis PR introduces context-aware logging capabilities by adding a generic template system, enabling application logs to include middleware-derived values like request IDs. It adds new context tagging APIs, refactors the logger middleware to use the new template system, and updates the default logger's Changes
Sequence Diagram(s)sequenceDiagram
participant Handler as Route Handler
participant Logger as Logger Instance
participant Template as Context Template
participant Buffer as Output Buffer
participant Context as context.Context
Handler->>Logger: WithContext(ctx)
activate Logger
Logger->>Logger: Store context
Logger->>Logger: Return bound logger
deactivate Logger
Handler->>Logger: Info("message")
activate Logger
Logger->>Template: Check if template loaded
alt Template exists
Logger->>Template: Execute(buffer, ctx, data)
activate Template
Template->>Context: Read context values
Context-->>Template: Return value
Template->>Buffer: Write rendered output
deactivate Template
end
Logger->>Buffer: Write log message
deactivate Logger
Estimated code review effort🎯 4 (Complex) | ⏱️ ~65 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a unified log template mechanism in the internal/logtemplate package, which is now utilized by both the log package and the logger middleware. Key enhancements include the addition of log.WithContext and log.SetContextTemplate to allow for consistent, context-aware logging across the application. Documentation and generated interface files were also updated to reflect these changes and clarify behavior regarding multipart form parsing and route URL generation. A review comment suggested optimizing slice allocation in the template builder to prevent unnecessary reallocations.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4241 +/- ##
==========================================
- Coverage 91.17% 91.15% -0.03%
==========================================
Files 123 124 +1
Lines 12084 12103 +19
==========================================
+ Hits 11018 11032 +14
- Misses 668 676 +8
+ Partials 398 395 -3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR introduces a shared internal log template engine to reuse template parsing/rendering across Fiber’s request logger middleware and the log.WithContext application logger, enabling consistent “contextual tag” rendering (e.g., request IDs).
Changes:
- Extract template parsing/execution into
internal/logtemplateand switchmiddleware/loggerto use it. - Add configurable contextual template rendering for Fiber’s default logger via
log.SetContextTemplate+log.WithContext. - Update docs and add tests for legacy logger chains, contextual tags, and
${value:key}rendering.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| internal/logtemplate/template.go | Adds reusable template parsing + chain execution utilities. |
| internal/logtemplate/errors.go | Introduces shared template parse error(s). |
| internal/logtemplate/template_test.go | Adds unit tests for template execution and missing-parameter behavior. |
| middleware/logger/logger.go | Replaces per-middleware template compilation with logtemplate.Build(...). |
| middleware/logger/default_logger.go | Reuses shared chain executor for default logger rendering. |
| middleware/logger/config.go | Re-exports shared Buffer/Func types for logger tag functions. |
| middleware/logger/errors.go | Maps legacy logger template error to shared logtemplate error. |
| middleware/logger/template_chain.go | Removes now-superseded in-package template compilation logic. |
| middleware/logger/logger_test.go | Adds regression coverage for legacy TemplateChain/LogFuncChain behavior. |
| log/context.go | Adds SetContextTemplate and ${value:key} tag support for default logger context enrichment. |
| log/default.go | Implements contextual template rendering in default logger when bound via WithContext. |
| log/context_test.go | Adds tests for ${value:key} and custom context tags. |
| log/default_test.go | Updates caller expectations and adds coverage for contextual template output. |
| log/log.go | Updates AllLogger docs/comments to reflect context binding responsibilities. |
| docs/api/log.md | Documents SetContextTemplate, custom tags, and log.WithContext(c) behavior. |
| docs/middleware/logger.md | Documents reuse of tag/template approach for application logging. |
| docs/whats_new.md | Adds “What’s New” entry for contextual application logging templates. |
| ctx_interface_gen.go | Updates interface docs (multipart BodyLimit notes; HTML <p> escaping note; route URL comment). |
| req_interface_gen.go | Updates interface docs for multipart parsing/BodyLimit enforcement. |
| res_interface_gen.go | Updates interface docs (HTML <p> escaping note; route URL comment). |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
middleware/logger/default_logger.go (1)
119-123:⚠️ Potential issue | 🟡 MinorTest coverage for the error-append path (lines 121–123) appears to be missing.
ExecuteChainscorrectly short-circuits on the first error and returns it, allowing the error string to be appended to the buffer. This matches the short-circuit semantics of the previous manual chain iteration. However, no test currently exercises the error path where a function inLogFuncChainor a buffer write withinExecuteChainsfails. The existing error output tests (Test_Logger_ErrorOutput*) exercise stream write failures only, not template execution failures. Consider adding a test case that injects a failingLogFuncor wraps the buffer to trigger an error insideExecuteChains, then verifies the error message is correctly appended to the log output.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@middleware/logger/default_logger.go` around lines 119 - 123, Add a unit test that exercises the error-append path of ExecuteChains by injecting a failing LogFunc or a writer that errors during ExecuteChains and asserting the returned error string is appended to the log buffer; specifically, create a test (e.g., Test_Logger_ErrorOutput_TemplateFailure) that builds a Logger config with a LogFuncChain containing a function that returns an error (or wraps the buffer with an io.Writer whose Write returns an error), call logtemplate.ExecuteChains (via the logger flow used in existing Test_Logger_ErrorOutput* tests), capture the buffer output and the error, and assert the buffer contains err.Error() as appended text to validate the error-append behavior in default_logger.go.
🧹 Nitpick comments (2)
middleware/logger/logger.go (1)
100-101:TemplateChain/LogFuncChainare written into the pooledDataon every request — confirm no consumer mutates them.Both fields share the same underlying slices across all requests. The default logger now passes them straight to
logtemplate.ExecuteChains, which only reads, so this is safe today. Worth a brief note inData's GoDoc that customLoggerFuncimplementations must treat these slices as read-only, since mutation would corrupt every subsequent request.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@middleware/logger/logger.go` around lines 100 - 101, The Data struct's TemplateChain and LogFuncChain fields are shared pooled slices and must be treated as read-only by consumers; update the GoDoc for type Data to explicitly state that TemplateChain and LogFuncChain are shared across requests and must not be mutated by custom LoggerFunc implementations (they may only read/iterate), and add a short comment near the assignment site (where data.TemplateChain and data.LogFuncChain are set) referencing logtemplate.ExecuteChains as the current reader to make the expectation clear.log/context.go (1)
35-48: Consider returning the build error instead of panicking.
SetContextTemplatepanics iflogtemplate.Buildrejects the format string. For a library setter API this is unusual — callers typically expectSet*functions to be infallible or to return an error. Panicking forces users to either validate the format themselves or wrap calls inrecover(). Since this is a brand-new API, the signature change is essentially free.♻️ Suggested change to return an error
-// SetContextTemplate configures contextual fields rendered by WithContext for Fiber's default logger. -func SetContextTemplate(config ContextConfig) { +// SetContextTemplate configures contextual fields rendered by WithContext for Fiber's default logger. +// It returns an error if config.Format cannot be parsed. +func SetContextTemplate(config ContextConfig) error { if config.Format == "" { contextTemplate.Store(nil) - return + return nil } tmpl, err := logtemplate.Build[context.Context, ContextData](config.Format, createContextTagMap(config.CustomTags)) if err != nil { - panic(err) + return err } contextTemplate.Store(tmpl) + return nil }If a panicking variant is still desirable, consider a
MustSetContextTemplatewrapper following the standard librarytext/template.Mustconvention.Please confirm whether the panic-on-error semantics is intentional (e.g., to surface misconfiguration loudly at startup) and double-check whether any of the new docs/examples in
docs/api/log.mdalready advertise this signature, since changing it would require a docs update.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@log/context.go` around lines 35 - 48, Change SetContextTemplate to return an error instead of panicking: call logtemplate.Build inside SetContextTemplate, and if it returns an error, return that error to the caller; on success store the template into contextTemplate via contextTemplate.Store(tmpl) and return nil. Keep the current panic behavior as an optional MustSetContextTemplate wrapper (e.g., MustSetContextTemplate calls SetContextTemplate and panics on non-nil error) if you want a loud-startup variant. Update references to SetContextTemplate callers to handle the returned error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@log/default.go`:
- Around line 227-242: The writeContext function currently executes the template
directly into the provided buf which can leave a partial render if tmpl.Execute
fails; change writeContext to first load the template (contextTemplate.Load) and
execute it into a temporary/scratch buffer (local Buffer or bytes buffer)
instead of writing straight into l's buf, and only append the scratch buffer to
buf if tmpl.Execute succeeds; if Execute returns an error, avoid appending the
partial content and surface the failure once via an internal logger or write a
safe fixed fallback (e.g., omit context or write "[context error]"), referencing
the writeContext method, tmpl.Execute call, the contextTemplate.Load usage, and
ContextData so you modify the same symbols.
---
Outside diff comments:
In `@middleware/logger/default_logger.go`:
- Around line 119-123: Add a unit test that exercises the error-append path of
ExecuteChains by injecting a failing LogFunc or a writer that errors during
ExecuteChains and asserting the returned error string is appended to the log
buffer; specifically, create a test (e.g.,
Test_Logger_ErrorOutput_TemplateFailure) that builds a Logger config with a
LogFuncChain containing a function that returns an error (or wraps the buffer
with an io.Writer whose Write returns an error), call logtemplate.ExecuteChains
(via the logger flow used in existing Test_Logger_ErrorOutput* tests), capture
the buffer output and the error, and assert the buffer contains err.Error() as
appended text to validate the error-append behavior in default_logger.go.
---
Nitpick comments:
In `@log/context.go`:
- Around line 35-48: Change SetContextTemplate to return an error instead of
panicking: call logtemplate.Build inside SetContextTemplate, and if it returns
an error, return that error to the caller; on success store the template into
contextTemplate via contextTemplate.Store(tmpl) and return nil. Keep the current
panic behavior as an optional MustSetContextTemplate wrapper (e.g.,
MustSetContextTemplate calls SetContextTemplate and panics on non-nil error) if
you want a loud-startup variant. Update references to SetContextTemplate callers
to handle the returned error.
In `@middleware/logger/logger.go`:
- Around line 100-101: The Data struct's TemplateChain and LogFuncChain fields
are shared pooled slices and must be treated as read-only by consumers; update
the GoDoc for type Data to explicitly state that TemplateChain and LogFuncChain
are shared across requests and must not be mutated by custom LoggerFunc
implementations (they may only read/iterate), and add a short comment near the
assignment site (where data.TemplateChain and data.LogFuncChain are set)
referencing logtemplate.ExecuteChains as the current reader to make the
expectation clear.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 643b9135-e9a2-48a3-9006-9aef019af8fd
📒 Files selected for processing (20)
ctx_interface_gen.godocs/api/log.mddocs/middleware/logger.mddocs/whats_new.mdinternal/logtemplate/errors.gointernal/logtemplate/template.gointernal/logtemplate/template_test.golog/context.golog/context_test.golog/default.golog/default_test.golog/log.gomiddleware/logger/config.gomiddleware/logger/default_logger.gomiddleware/logger/errors.gomiddleware/logger/logger.gomiddleware/logger/logger_test.gomiddleware/logger/template_chain.goreq_interface_gen.gores_interface_gen.go
💤 Files with no reviewable changes (1)
- middleware/logger/template_chain.go
There was a problem hiding this comment.
⚠️ Performance Alert ⚠️
Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.
| Benchmark suite | Current: 03fc04e | Previous: 16d7bc1 | Ratio |
|---|---|---|---|
Benchmark_Ctx_SendString_B (github.com/gofiber/fiber/v3) |
19.61 ns/op 0 B/op 0 allocs/op |
10.31 ns/op 0 B/op 0 allocs/op |
1.90 |
Benchmark_Ctx_SendString_B (github.com/gofiber/fiber/v3) - ns/op |
19.61 ns/op |
10.31 ns/op |
1.90 |
Benchmark_Compress/Zstd (github.com/gofiber/fiber/v3/middleware/compress) - B/op |
1 B/op |
0 B/op |
+∞ |
Benchmark_Compress_Levels/Zstd_LevelDefault (github.com/gofiber/fiber/v3/middleware/compress) - B/op |
1 B/op |
0 B/op |
+∞ |
Benchmark_Compress_Levels/Zstd_LevelBestCompression (github.com/gofiber/fiber/v3/middleware/compress) - B/op |
1 B/op |
0 B/op |
+∞ |
This comment was automatically generated by workflow using github-action-benchmark.
Replaces the approach from #4106 and fixes #3763.
This keeps the original goal of making
log.WithContext(...)useful for request-scoped application logs, but changes the design from automatic middleware extractors to an explicit, user-controlled template system similar tomiddleware/logger.logtemplatepackage.middleware/loggerwithout duplicating template parsing logic.logger.Data.TemplateChainandlogger.Data.LogFuncChaincompatible for existing custom logger integrations.log.SetContextTemplateso Fiber’s default logger can render contextual fields forlog.WithContext.WithContext(ctx any)compatible with Fiber-supported context inputs such asfiber.Ctx,*fasthttp.RequestCtx-styleUserValuecontexts, andcontext.Context.${value:key}support for ordinary context-style values.${value:key}rendering.Validation
make lintmake test