🔥 feat: log.WithContext automatically includes context fields#4106
🔥 feat: log.WithContext automatically includes context fields#4106
Conversation
…textExtractor
Add ContextExtractor type and RegisterContextExtractor function to the log
package. The default logger's WithContext method now stores the context and
extracts registered fields at log time, prepending them as key=value pairs.
The requestid middleware auto-registers an extractor via init() so that
log.WithContext(c).Info("msg") automatically includes request-id=<id>.
Co-authored-by: gaby <835733+gaby@users.noreply.github.com>
Co-authored-by: gaby <835733+gaby@users.noreply.github.com>
Co-authored-by: gaby <835733+gaby@users.noreply.github.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #4106 +/- ##
==========================================
- Coverage 91.07% 90.98% -0.10%
==========================================
Files 122 122
Lines 11550 11619 +69
==========================================
+ Hits 10519 10571 +52
- Misses 651 662 +11
- Partials 380 386 +6
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.
⚠️ 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: cdcd49b | Previous: b3a9e3f | Ratio |
|---|---|---|---|
Benchmark_NewError (github.com/gofiber/fiber/v3) |
80.35 ns/op 24 B/op 1 allocs/op |
51.97 ns/op 24 B/op 1 allocs/op |
1.55 |
Benchmark_NewError (github.com/gofiber/fiber/v3) - ns/op |
80.35 ns/op |
51.97 ns/op |
1.55 |
BenchmarkDecoderedirectionMsg (github.com/gofiber/fiber/v3) |
162.8 ns/op 196.52 MB/s 0 B/op 0 allocs/op |
78.38 ns/op 408.26 MB/s 0 B/op 0 allocs/op |
2.08 |
BenchmarkDecoderedirectionMsg (github.com/gofiber/fiber/v3) - ns/op |
162.8 ns/op |
78.38 ns/op |
2.08 |
This comment was automatically generated by workflow using github-action-benchmark.
|
@copilot
|
…ctor, update docs - Removed init() from requestid, register extractor via sync.Once in New() - Added context extractor for basicauth middleware (username field) - Added tests for WithContext with fiber.Ctx and context.Context types - Updated docs/api/log.md with context extractors documentation - Updated docs/whats_new.md with context-aware logging section Co-authored-by: gaby <835733+gaby@users.noreply.github.com>
Addressed all three points in
Other middlewares ( Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot All these middlewares need the change to support the logger WithContext:
|
There was a problem hiding this comment.
Pull request overview
Adds context-aware logging to Fiber’s default log implementation by introducing a ContextExtractor registry so middleware (e.g., requestid, basicauth) can automatically prepend context-derived key=value fields to log.WithContext(...) output.
Changes:
- Introduces
log.ContextExtractor+log.RegisterContextExtractorand updates the default logger to prepend extracted fields on log writes. - Registers default extractors from
requestid.New()(request-id) andbasicauth.New()(username). - Adds tests validating extractor behavior and requestid integration; updates docs to describe automatic/custom extractors.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
log/log.go |
Adds the extractor type/registry used by default logging. |
log/default.go |
Stores bound context and prepends extracted fields across log paths. |
log/default_test.go |
Adds unit tests validating extractor behavior across Info/Infof/Infow. |
middleware/requestid/requestid.go |
Registers a request-id extractor when middleware is constructed. |
middleware/requestid/requestid_test.go |
Adds integration tests ensuring request-id appears in log.WithContext(...) output. |
middleware/basicauth/basicauth.go |
Registers a username extractor when middleware is constructed. |
docs/api/log.md |
Documents automatic context fields and custom extractor registration. |
docs/whats_new.md |
Announces context-aware logging feature and points to API docs. |
…ewares - csrf: registers csrf-token extractor via sync.Once in New() - keyauth: registers api-key extractor via sync.Once in New() - session: registers session-id extractor via sync.Once in NewWithStore() - Added Test_CSRF_LogWithContext, Test_KeyAuth_LogWithContext, Test_Session_LogWithContext - Updated docs/api/log.md and docs/whats_new.md to list all 5 middlewares Co-authored-by: gaby <835733+gaby@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Fixed in |
|
@claude[agent] Right now, |
…consistency with fiber.ValueFromContext Co-authored-by: gaby <835733+gaby@users.noreply.github.com>
Changed in cdcd49b. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@claude[agent] Please review this implementation for potential issues and ensure it is both secure and safe. Additionally, verify that it cannot be exploited for Denial-of-Service (DoS) attacks or other server malfunctions. |
Security Review SummaryI've conducted a comprehensive security review of the log context extraction implementation. The code is secure and safe with robust protections against common attack vectors. ✅ Security Strengths1. Concurrency Safety
2. DoS Attack Resistance
3. Information Disclosure Prevention
4. Memory Safety
5. Input Validation
|
ReneWerner87
left a comment
There was a problem hiding this comment.
Feature looks good, but lets talk about the review hints (feature control, format)
|
|
||
| ### Automatic Context Fields | ||
|
|
||
| Middleware that stores values in the request context can register extractors so that `log.WithContext` automatically includes those values in every log entry. The following middlewares register extractors when their `New()` constructor is called: |
There was a problem hiding this comment.
Since these are values that are written internally, I have two questions:
- Are these values always written, even if I use the logger multiple times in a handler? If so, this feature should be made configurable in some way.
- Questions about formatting will likely arise, so this should be considered right from the start of the feature
to ensure that it is possible to format this output.
Since everything is output in JSON format in the microservices world, it would be good if these values could also directly conform to this schema.
There was a problem hiding this comment.
- You mean to make the registration optional for each middleware?
Right now it registers in the middleware, but that doesn't do anything unless the user is using fiberlog.
There was a problem hiding this comment.
Added compatibility note in b3fc68a addressing both points:
-
Always written: Yes, context fields are automatically included with every
log.WithContext(c)call in a handler. This is intentional for request correlation. If you need to log without context fields, use the regularlog.Info()methods instead oflog.WithContext(c).Info(). -
Formatting: The default format is
key=valuepairs prepended to messages. For JSON/structured logging, the note now recommends using theLogwmethods (e.g.,log.WithContext(c).Infow("message", "key", "value")) which preserve field structure and work better with JSON formatters.
There was a problem hiding this comment.
If I use three middleware components from the core, for example, requestId, csrf, and session
and then call the log method multiple times in my business logic handler, as a consumer I might not want to see the IDs of these three core middleware components in the output every time
|
…ontext - Added concrete output examples showing how context fields appear in logs - Added example with multiple middleware to show how fields are combined - Added compatibility note explaining key=value format and JSON/structured logging support - Clarified that context fields are always included when using WithContext - Fixed markdown linting issues (language specification and blank lines) Co-authored-by: gaby <835733+gaby@users.noreply.github.com>
Completed in b3fc68a:
|
| // ContextExtractor extracts a key-value pair from the given context for | ||
| // inclusion in log output when using WithContext. | ||
| // It returns the log field name, its value, and whether extraction succeeded. | ||
| // The ctx parameter can be fiber.Ctx, *fasthttp.RequestCtx, or context.Context. |
| // Register a log context extractor so that log.WithContext(c) automatically | ||
| // includes the request ID when the requestid middleware is in use. | ||
| // An empty request ID (no middleware or middleware skipped) is omitted. | ||
| registerExtractor.Do(func() { | ||
| log.RegisterContextExtractor(func(ctx any) (string, any, bool) { | ||
| rid := FromContext(ctx) | ||
| return "request-id", rid, rid != "" | ||
| }) |
| - Works with any logger that implements the `AllLogger` interface | ||
| - For JSON or structured logging, use the `Logw` methods (e.g., `log.WithContext(c).Infow("message", "key", "value")`) which preserve field structure | ||
| - Context fields are always included when using `log.WithContext()`, regardless of how many times you call the logger in a handler |
| `log.WithContext` now automatically includes context fields extracted by middleware. The method accepts `fiber.Ctx`, `*fasthttp.RequestCtx`, or `context.Context`, making it flexible and consistent with Fiber's context handling throughout the framework. | ||
|
|
||
| Middleware such as `requestid`, `basicauth`, `keyauth`, `csrf`, and `session` register extractors when their `New()` constructor is called. When you pass a context to `log.WithContext`, registered fields are prepended to every log entry. | ||
|
|
||
| ```go | ||
| app.Use(requestid.New()) | ||
|
|
||
| app.Get("/", func(c fiber.Ctx) error { | ||
| // Output: [Info] request-id=abc-123 processing request | ||
| log.WithContext(c).Info("processing request") |
Description
log.WithContext(ctx).Info("msg")was identical tolog.Info("msg")— the context parameter was discarded. This adds aContextExtractormechanism so middleware can register functions that extract key-value pairs from context at log time. Each middleware registers its extractor viasync.Onceinside itsNew()constructor, so extraction only activates when the middleware is actually used.WithContextacceptsfiber.Ctx,*fasthttp.RequestCtx, orcontext.Context, making it flexible and consistent with Fiber'sValueFromContextpattern used throughout the framework. When using standardcontext.Contextinstances (such asc.Context()), enablePassLocalsToContextin the app config so that values stored infiber.Ctx.Localsare propagated through the context chain.All five middlewares that store values in the request context now register log context extractors:
requestidrequest-idbasicauthusernamekeyauthapi-key****)csrfcsrf-token[redacted])sessionsession-id****for IDs longer than 8 chars; fully redacted otherwise)All sensitive fields (
api-key,csrf-token,session-id) are always redacted to prevent credential and session-token leakage in logs. Extractors that return an empty key are silently skipped to prevent malformed=valuelog output.RegisterContextExtractoris concurrency-safe — reads use async.RWMutex-guarded snapshot and writes use a copy-on-write strategy so in-flight log calls always observe a stable slice.Output Format
Context fields are prepended to log messages in
key=valueformat. Example outputs:Single middleware:
Multiple middlewares:
Context fields are always included when using
log.WithContext(), regardless of how many times the logger is called within a handler. For JSON or structured logging needs, use theLogwmethods (e.g.,log.WithContext(c).Infow("message", "key", "value")) which preserve field structure and work better with JSON formatters.Security
The implementation has been thoroughly reviewed for security vulnerabilities and DoS attack vectors:
sync.RWMutexwith copy-on-write prevents all race conditionssync.Onceper middleware (max 5 extractors), buffer pooling, early returns for nil/empty valuesbytebufferpoolChanges introduced
log/log.go:ContextExtractortype signature changed to acceptanyinstead ofcontext.Contextfor consistency withfiber.ValueFromContext.RegisterContextExtractor— a generic hook for middleware to supply context fields to the logger. Rejectsnilextractors with a panic for robustness. Usessync.RWMutexwith copy-on-write for safe concurrent registration and logging. ExposesloadContextExtractors()for safe snapshot reads.AllLoggerinterface updated to reflect the new signature.log/default.go:WithContextnow acceptsanyand stores the context;writeContextFieldshelper loads an immutable snapshot of extractors and prepends extracted key-value pairs to log output. Skips extractors returning empty keys.middleware/requestid/requestid.go: Registers extractor viasync.OnceinNew()to includerequest-idin logs. Updated to useanysignature.middleware/basicauth/basicauth.go: Registers extractor viasync.OnceinNew()to includeusernamein logs. Updated to useanysignature.middleware/keyauth/keyauth.go: Registers extractor viasync.OnceinNew()to include redactedapi-keyin logs (first 4 chars +****). Updated to useanysignature.middleware/csrf/csrf.go: Registers extractor viasync.OnceinNew()to include always-redactedcsrf-tokenin logs ([redacted]). Updated to useanysignature.middleware/session/middleware.go: Registers extractor viasync.OnceinNew()to include redactedsession-idin logs. Updated to useanysignature.Test_BasicAuth_LogWithContext,Test_RequestID_LogWithContext_FiberCtx,Test_RequestID_LogWithContext_ContextContext,Test_KeyAuth_LogWithContext,Test_CSRF_LogWithContext, andTest_Session_LogWithContextto verify context extraction works correctly for all middlewares. Updatedlog/default_test.goto use the newanysignature.docs/api/log.mdwith "Automatic Context Fields" and "Custom Context Extractors" sections, documenting the newanysignature and usage withfiber.ValueFromContext. Added concrete output examples showing single and multi-middleware logging format. Added compatibility note explainingkey=valueformat and guidance for JSON/structured logging usingLogwmethods. Updateddocs/whats_new.mdwith context-aware logging feature description and supported context types.Type of change
Checklist
/docs/directory for Fiber's documentation.Original prompt
🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.