Skip to content

feat: reuse logger template rendering for contextual logs#4241

Draft
ReneWerner87 wants to merge 3 commits intomainfrom
codex/reusable-log-template
Draft

feat: reuse logger template rendering for contextual logs#4241
ReneWerner87 wants to merge 3 commits intomainfrom
codex/reusable-log-template

Conversation

@ReneWerner87
Copy link
Copy Markdown
Member

@ReneWerner87 ReneWerner87 commented Apr 27, 2026

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 to middleware/logger.

  • Extract logger template parsing/rendering into a shared internal logtemplate package.
  • Reuse the shared template engine in middleware/logger without duplicating template parsing logic.
  • Keep logger.Data.TemplateChain and logger.Data.LogFuncChain compatible for existing custom logger integrations.
  • Add log.SetContextTemplate so Fiber’s default logger can render contextual fields for log.WithContext.
  • Keep WithContext(ctx any) compatible with Fiber-supported context inputs such as fiber.Ctx, *fasthttp.RequestCtx-style UserValue contexts, and context.Context.
  • Add built-in ${value:key} support for ordinary context-style values.
  • Document contextual application logging with request middleware values, including request ID examples.
  • Add regression coverage for legacy logger chains, contextual tags, and ${value:key} rendering.

Validation

  • make lint
  • make test

Copilot AI review requested due to automatic review settings April 27, 2026 12:38
@ReneWerner87 ReneWerner87 requested a review from a team as a code owner April 27, 2026 12:38
@ReneWerner87 ReneWerner87 linked an issue Apr 27, 2026 that may be closed by this pull request
3 tasks
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f4ad2558-a01f-4e43-8d47-b01dbb00c115

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This 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 WithContext method to retain and use context during logging.

Changes

Cohort / File(s) Summary
Template System
internal/logtemplate/template.go, internal/logtemplate/template_test.go, internal/logtemplate/errors.go
New generic template rendering module supporting precompiled log format strings with ${tag[:param]} syntax. Includes Build for compilation, Execute for rendering, and sentinel error ErrParameterMissing for missing parameters.
Context Logging APIs
log/context.go, log/context_test.go
Introduces SetContextTemplate function and context tagging infrastructure, including built-in value: tag for extracting context values. Defines ContextData, ContextTagFunc, and ContextConfig types.
Default Logger Updates
log/default.go, log/default_test.go
Modified WithContext to bind context to logger instance, added writeContext helper to conditionally append template-rendered context fields. Tests updated to verify context template integration and caller line accuracy.
Logger Middleware Refactoring
middleware/logger/logger.go, middleware/logger/default_logger.go, middleware/logger/config.go, middleware/logger/errors.go, middleware/logger/template_chain.go, middleware/logger/logger_test.go
Migrated logger middleware to use new logtemplate.Build API; replaced in-file template compilation (buildLogFuncChain) with centralized logtemplate.ExecuteChains. Type aliases now reference logtemplate definitions. Added test for legacy template-chain behavior.
Interface & Doc Updates
log/log.go, ctx_interface_gen.go, req_interface_gen.go, res_interface_gen.go, docs/api/log.md, docs/middleware/logger.md, docs/whats_new.md
Updated AllLogger[T] interface to explicitly require WithContext method. Enhanced doc comments for form/response methods and added examples demonstrating context-aware logging with request IDs and custom tags.

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

  • PR #3153 — Updates AllLogger[T] interface and modifies core logging subsystem including log/default.go behavior changes
  • PR #3446 — Demonstrates using custom context tags (request ID) for middleware-driven logging with SetContextTemplate
  • PR #3677 — Introduces context-aware logging APIs and documents helper functions like requestid.FromContext for extracting context values

Suggested labels

✏️ Feature, codex, v3

Suggested reviewers

  • gaby
  • sixcolors
  • efectn

Poem

🐰 A template in the meadow, where contexts dance and play,
With ${value:key} whispers, bringing logs to light of day,
Request IDs hop along, in buffers swift and neat,
Context-aware log chains make the logging tale complete! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.84% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description is concise and directly addresses the problem, but lacks structured detail on documentation updates, examples, and testing coverage required by the template. Clarify which documentation files were updated, provide specific examples of the new feature usage, and confirm testing was completed for all new functionality.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: reuse logger template rendering for contextual logs' is a concise summary of the primary change—extracting shared template logic and reusing it for contextual logging.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/reusable-log-template

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread internal/logtemplate/template.go Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 27, 2026

Codecov Report

❌ Patch coverage is 76.11940% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.15%. Comparing base (16d7bc1) to head (8323c21).

Files with missing lines Patch % Lines
log/context.go 66.66% 11 Missing and 1 partial ⚠️
log/default.go 88.23% 1 Missing and 1 partial ⚠️
middleware/logger/errors.go 66.66% 2 Missing ⚠️
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     
Flag Coverage Δ
unittests 91.15% <76.11%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ReneWerner87 ReneWerner87 marked this pull request as draft April 27, 2026 12:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/logtemplate and switch middleware/logger to 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).

Comment thread internal/logtemplate/errors.go Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 | 🟡 Minor

Test coverage for the error-append path (lines 121–123) appears to be missing.

ExecuteChains correctly 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 in LogFuncChain or a buffer write within ExecuteChains fails. 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 failing LogFunc or wraps the buffer to trigger an error inside ExecuteChains, 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 / LogFuncChain are written into the pooled Data on 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 in Data's GoDoc that custom LoggerFunc implementations 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.

SetContextTemplate panics if logtemplate.Build rejects the format string. For a library setter API this is unusual — callers typically expect Set* functions to be infallible or to return an error. Panicking forces users to either validate the format themselves or wrap calls in recover(). 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 MustSetContextTemplate wrapper following the standard library text/template.Must convention.

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.md already 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

📥 Commits

Reviewing files that changed from the base of the PR and between 16d7bc1 and bba8c4c.

📒 Files selected for processing (20)
  • ctx_interface_gen.go
  • docs/api/log.md
  • docs/middleware/logger.md
  • docs/whats_new.md
  • internal/logtemplate/errors.go
  • internal/logtemplate/template.go
  • internal/logtemplate/template_test.go
  • log/context.go
  • log/context_test.go
  • log/default.go
  • log/default_test.go
  • log/log.go
  • middleware/logger/config.go
  • middleware/logger/default_logger.go
  • middleware/logger/errors.go
  • middleware/logger/logger.go
  • middleware/logger/logger_test.go
  • middleware/logger/template_chain.go
  • req_interface_gen.go
  • res_interface_gen.go
💤 Files with no reviewable changes (1)
  • middleware/logger/template_chain.go

Comment thread log/default.go
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

🤗 [Question]: About fiber v3 log

2 participants