feat(log): support generic configurable logger#3705
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. Warning Rate limit exceeded@ReneWerner87 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 12 minutes and 16 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
WalkthroughIntroduces generics to the logging surface: Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor App
participant LogPkg as log package
participant Def as defaultLogger
participant MW as middleware/logger
App->>LogPkg: DefaultLogger[*log.Logger]()
activate LogPkg
LogPkg->>Def: construct/return singleton (typed)
Def-->>LogPkg: AllLogger[*log.Logger]
LogPkg-->>App: AllLogger[*log.Logger]
deactivate LogPkg
App->>LogPkg: SetLogger[*log.Logger](logger)
LogPkg-->>App: stored as baseLogger
App->>MW: LoggerToWriter[*log.Logger](logger, level)
MW-->>App: io.Writer (typed wrapper)
App->>logger: Logger()
logger-->>App: *log.Logger (typed)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Summary of Changes
Hello @ReneWerner87, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request significantly enhances the logging system by leveraging Go generics. The primary goal is to provide a more flexible and type-safe way to configure and interact with loggers, allowing users to seamlessly integrate various logging libraries while maintaining strong type guarantees. This involves making key logger interfaces and functions generic, introducing an internal base logger interface for better management, and updating documentation to reflect these changes.
Highlights
- Generic Logger Interfaces: The
AllLoggerandConfigurableLoggerinterfaces are now generic, enabling type-safe handling of different underlying logger implementations. - Type-Safe Logger Access: The
DefaultLogger()andSetLogger()functions are updated to be generic, allowing direct retrieval and setting of concrete logger types without manual type assertions. - Internal Logger Management: A new
baseLoggerinterface is introduced to internally manage diverse logger implementations, improving the system's robustness. - Streamlined Logger Integration: The
LoggerToWriterhelper function is generalized with generics, simplifying the integration of third-party loggers with the middleware. - Comprehensive Documentation: The documentation in
docs/api/log.mdanddocs/whats_new.mdhas been updated to provide clear guidance and examples for utilizing the new generic logging capabilities.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Pull Request Overview
This PR adds generic type support to the Fiber logging system, enabling better type safety when working with custom loggers. The changes introduce a new baseLogger interface for internal use while making the public logging interfaces generic to support typed logger instances.
- Introduces generic type parameters to
ConfigurableLoggerandAllLoggerinterfaces - Updates
SetLoggerandDefaultLoggerfunctions to work with generic types - Generalizes the
LoggerToWriterutility function to support typed loggers
Reviewed Changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| log/log.go | Adds baseLogger interface and makes ConfigurableLogger and AllLogger generic |
| log/fiberlog.go | Updates SetLogger function to accept generic logger types |
| log/default.go | Makes DefaultLogger generic and updates Logger() method return type |
| middleware/logger/utils.go | Generalizes LoggerToWriter and related types to support generic loggers |
| middleware/logger/logger_test.go | Updates test code to use generic logger types |
| log/fiberlog_test.go | Updates test code to use generic logger types |
| log/default_test.go | Removes unnecessary type assertion in test |
| client/client.go | Updates client initialization to use generic logger |
| docs/api/log.md | Updates documentation to reflect generic logger usage |
| docs/whats_new.md | Adds migration notes for the generic logger changes |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3705 +/- ##
==========================================
- Coverage 91.79% 91.79% -0.01%
==========================================
Files 114 114
Lines 11536 11539 +3
==========================================
+ Hits 10590 10592 +2
- Misses 684 685 +1
Partials 262 262
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.
Code Review
This pull request introduces a generic logger interface to allow retrieving the concrete logger instance, which is a great enhancement for flexibility. The changes are well-reflected in the documentation and tests.
However, there's a critical issue in the implementation of log.DefaultLogger where a failing type assertion is not handled, which can lead to panics. Additionally, there are several places where DefaultLogger[any]() is used, which seems to stem from a misunderstanding of how Go generics work with interfaces and will cause the application to panic. I've provided comments and suggestions to fix these issues. There's also a minor point about clarifying the use of generics in the whats_new.md documentation to avoid confusion for users.
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 (6)
docs/whats_new.md (1)
1168-1171: Inconsistent comment: says “zerolog” but example uses zapThe snippet creates a zap logger (
fiberzap.NewLogger), but the comment says “zerolog”. Update the comment to “zap” to avoid confusion.- // Use the logger middleware with zerolog logger + // Use the logger middleware with zap loggerdocs/api/log.md (1)
159-163: Broken example: uses unexported defaultLogger and won’t compileThis snippet references
defaultLogger, which is unexported and not available to users. Also, constructing it directly bypasses the intended API surface. Replace with the public functions.-// Writing Logs to Stderr -// (broken: uses unexported type) -var logger fiberlog.AllLogger[*log.Logger] = &defaultLogger{ - stdlog: log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), - depth: 4, -} +// Writing Logs to Stderr (correct) +fiberlog.SetOutput(os.Stderr) +// Optionally adjust std logger flags +std := fiberlog.DefaultLogger[*log.Logger]().Logger() +std.SetFlags(log.LstdFlags | log.Lshortfile | log.Lmicroseconds)client/client.go (1)
33-34: Fix logger initializer to match its declared interfaceThe
Clientstruct declares itsloggerfield as alog.CommonLogger, but the initializer inNewWithClientuses the generic calllog.DefaultLogger[any](), which returns anAllLogger[any]. Since our default implementation (defaultLogger) only satisfiesAllLogger[*log.Logger], the type assertion insideDefaultLogger[any]()fails and yieldsnil, leading to a broken logger at runtime.To resolve, specialize the type parameter to the concrete
*log.Loggerso that the returned value truly implementsCommonLogger:• In
client/client.go, around line 665, change the initializer:- logger: log.DefaultLogger[any](), + logger: log.DefaultLogger[*log.Logger](),• This ensures
DefaultLogger[*log.Logger]()returns anAllLogger[*log.Logger], which embedsCommonLoggerand matches your field.Additionally, scan the codebase for any other uses of
DefaultLogger[any]()(e.g., in middleware tests atmiddleware/logger/logger_test.go:1105and1261) and either:
- Update them to
DefaultLogger[*log.Logger](), or- Change the receiving field to accept
AllLogger[any].log/fiberlog.go (1)
73-76: Docstring typo: Panicf comment references TracefThe comment says “Panicf calls the default logger's Tracef method,” which is incorrect and misleading for users of this API.
Apply this diff to fix the docstring:
-// Panicf calls the default logger's Tracef method. +// Panicf calls the default logger's Panicf method.middleware/logger/utils.go (1)
50-67: Default case returns (0, nil); prefer reporting full consumption or errorReturning (0, nil) from Write may cause callers to retry or mis-handle partial writes. Since invalid levels are filtered earlier, default should either consume all bytes or return an error.
Apply this diff:
default: - return 0, nil + // Treat as a no-op but signal full consumption to avoid retry loops. + return len(p), nil }Alternatively, return 0 and a concrete error (but that would propagate into middleware paths).
log/default.go (1)
55-59: privateLogf bug: empty arg slice drops the format stringWhen no args are provided, the else path calls Fprint with fmtArgs (empty), resulting in an empty message instead of the format string.
Apply this fix:
- if len(fmtArgs) > 0 { - _, _ = fmt.Fprintf(buf, format, fmtArgs...) - } else { - _, _ = fmt.Fprint(buf, fmtArgs...) - } + if len(fmtArgs) > 0 { + _, _ = fmt.Fprintf(buf, format, fmtArgs...) + } else { + buf.WriteString(format) + }Add a unit test to cover Infof("msg") without args.
🧹 Nitpick comments (16)
log/log.go (3)
11-18: Solid internal abstraction, but consider documenting variance limitationsDefining a non-generic
baseLoggerlets you keep a single global while exposing generics publicly. Please add a short note in the comment that values stored inloggermust implementAllLogger[T]for their concrete T (no covariance), so callers should not expectDefaultLogger[any]()to succeed. This will preempt misuse down the line.
80-86: Consider a typed variant of WithContext for power users
WithContext(ctx) CommonLoggerpreserves the old surface, but it discards the type information. Consider adding an optionalWithContextT[T any](ctx) AllLogger[T](or a method on concrete implementations) so users can still access typed underlying loggers after binding a context.
104-119: Minor naming nit:strs->levelPrefixes
strsis a bit vague. A more descriptive name would improve readability.- var strs = []string{ + var levelPrefixes = []string{ @@ -func (lv Level) toString() string { +func (lv Level) toString() string { - if lv >= LevelTrace && lv <= LevelPanic { - return strs[lv] + if lv >= LevelTrace && lv <= LevelPanic { + return levelPrefixes[lv] }docs/whats_new.md (1)
1881-1884: Add a caution about generics variance to prevent misusePlease add a one-liner that
AllLogger[T]is not covariant: implementations usually satisfyAllLogger[*log.Logger](std lib), notAllLogger[any]. Users should use the concrete underlying type (e.g.,*log.Logger) when callingDefaultLogger[T].#### 🧾 Log - -The `ConfigurableLogger` and `AllLogger` interfaces now use generics. You can specify the underlying logger type when implementing these interfaces or use `any` for maximum flexibility. `log.SetLogger` and `log.DefaultLogger` also accept a type parameter, so the concrete logger can be retrieved and used directly, for example `log.DefaultLogger[*MyLogger]().Logger()`. +The `ConfigurableLogger` and `AllLogger` interfaces now use generics. Specify the concrete underlying logger type (e.g., `*log.Logger`) when implementing or retrieving defaults. Note: `AllLogger[T]` is not covariant—using `any` as `T` will not match implementations built for a concrete `T`. `log.SetLogger` and `log.DefaultLogger` accept a type parameter; for example, `log.DefaultLogger[*log.Logger]().Logger()`.docs/api/log.md (1)
28-53: Interfaces look correct; minor duplicationTurning
ConfigurableLoggerandAllLoggerinto generics is on point. NoteAllLogger[T]embedsCommonLogger(which already embedsWithLogger), so the extraWithLoggerline inAllLogger[T]is redundant. Not wrong, just repetitive.type AllLogger[T any] interface { CommonLogger ConfigurableLogger[T] - WithLogger }log/fiberlog.go (3)
78-82: Clarify repetitive “w”-method docstringsThe phrase “pairs are treated as they are privateLog With.” is awkward and unclear across Tracew/Debugw/Infow/Warnw/Errorw/Fatalw/Panicw. Suggest a concise, consistent phrasing.
Example diff for one occurrence (apply similarly to all “w” variants):
-// Tracew logs a message with some additional context. The variadic key-value -// pairs are treated as they are privateLog With. +// Tracew logs a message with additional key-value context (same semantics as With).Also applies to: 84-88, 90-94, 96-100, 102-106, 108-112, 114-118
126-129: SetLogger is not concurrency-safe; benches call it in parallelThe comment correctly states non-concurrency-safety. However, Benchmark_SetLogger_Parallel exercises SetLogger concurrently in tests, which will race under -race. Consider keeping the benchmark but add a note or a build tag to skip with -race, or make the global swap atomic if you want to support concurrent reconfiguration.
Option A: Keep as-is, add a clarifying comment in the benchmark.
Option B (heavier): Use atomic.Value for the global logger to make swaps race-free.If you want to explore Option B later, I can draft it behind an internal helper to avoid public API changes.
120-122: Typed WithContext returns CommonLogger — document type erasureWithContext returns CommonLogger (non-generic), which erases the type parameter. That’s fine per log.go’s interface, but please ensure docs mention that typed accessors (like Logger()) won’t be available on the returned value.
log/fiberlog_test.go (2)
149-162: Parallel SetLogger will race under -raceThis intentionally stresses SetLogger, but it will deterministically flag a data race under -race (as documented by the API). Consider skipping this benchmark when -race is enabled.
Apply this diff to add a guard:
func Benchmark_SetLogger_Parallel(b *testing.B) { + if raceEnabled() { // helper that returns true under -race, see below + b.Skip("SetLogger is not concurrency-safe; skip under -race") + } setLog := &defaultLogger{ stdlog: log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), depth: 6, } @@ b.RunParallel(func(pb *testing.PB) { for pb.Next() { SetLogger(setLog) } }) } + +// place near tests: +func raceEnabled() bool { return false } // replaced at build-time with -tags race via a file with `package log; func raceEnabled() bool { return true }`
201-211: Parallel SetLevel mutates shared state without syncSetLevel writes to mockLogger.level; concurrent calls can race under -race. Either keep (documented) or isolate from -race runs similar to SetLogger.
middleware/logger/utils.go (2)
45-48: Generic parameter T is unused in writer; consider narrowing to CommonLoggercustomLoggerWriter[T] stores AllLogger[T] but only uses CommonLogger methods. You can simplify API and avoid unnecessary generic instantiation by accepting fiberlog.CommonLogger instead. This avoids monomorphization and reduces surface area.
Example:
-type customLoggerWriter[T any] struct { - loggerInstance fiberlog.AllLogger[T] +type customLoggerWriter struct { + loggerInstance fiberlog.CommonLogger level fiberlog.Level }And adjust LoggerToWriter accordingly (see below).
72-87: Broaden level validation to future-proof against out-of-range valuesYou panic for Fatal/Panic, but other invalid ints could slip through if Level gains values or callers pass arbitrary ints. Validate the permitted range explicitly.
If Level values are contiguous from LevelTrace to LevelError:
-func LoggerToWriter[T any](logger fiberlog.AllLogger[T], level fiberlog.Level) io.Writer { +func LoggerToWriter[T any](logger fiberlog.AllLogger[T], level fiberlog.Level) io.Writer { // Check if customLogger is nil if logger == nil { fiberlog.Panic("LoggerToWriter: customLogger must not be nil") } // Check if level is valid - if level == fiberlog.LevelFatal || level == fiberlog.LevelPanic { + if level < fiberlog.LevelTrace || level > fiberlog.LevelError { fiberlog.Panic("LoggerToWriter: invalid level") } - return &customLoggerWriter[T]{ + return &customLoggerWriter[T]{ level: level, loggerInstance: logger, } }If you adopt the CommonLogger simplification, also change the return to &customLoggerWriter{...} and the argument type to fiberlog.CommonLogger.
log/default.go (3)
22-24: Docstrings: minor grammar fixes“logs a message at a given level log the default logger.” → “logs a message at the given level using the default logger.”
-// privateLog logs a message at a given level log the default logger. +// privateLog logs a message at the given level using the default logger. ... -// privateLog logs a message at a given level log the default logger. +// privateLogf logs a message at the given level using the default logger. ... -// privateLog logs a message at a given level log the default logger. +// privateLogw logs a message at the given level using the default logger.Also applies to: 45-47, 72-74
29-43: Ensure pooled buffer is returned on panic pathsIn privateLog/privateLogf/privateLogw, a panic occurs before the buffer is returned to the pool. Use a defer to always Reset+Put even on panic.
Apply this pattern to all three functions:
buf := bytebufferpool.Get() + defer func() { + buf.Reset() + bytebufferpool.Put(buf) + }() buf.WriteString(level) // ... - _ = l.stdlog.Output(l.depth, buf.String()) //nolint:errcheck // It is fine to ignore the error - if lv == LevelPanic { - panic(buf.String()) - } - buf.Reset() - bytebufferpool.Put(buf) + _ = l.stdlog.Output(l.depth, buf.String()) //nolint:errcheck // It is fine to ignore the error + if lv == LevelPanic { + panic(buf.String()) + } if lv == LevelFatal { os.Exit(1) //nolint:revive // we want to exit the program when Fatal is called }Note: os.Exit bypasses defers, but you already Put the buffer before Exit; keep that sequencing.
Also applies to: 51-70, 79-111
218-221: DefaultLogger: handle failed type assertion explicitly (and quiet linters)Returning a nil typed interface when the assertion fails is fine, but being explicit improves readability and can address static analysis noise.
Apply:
-func DefaultLogger[T any]() AllLogger[T] { - l, _ := logger.(AllLogger[T]) - return l -} +func DefaultLogger[T any]() AllLogger[T] { + if l, ok := logger.(AllLogger[T]); ok { + return l + } + return nil +}If errcheck flagged this line (hint suggests so), confirm the warning disappears with this change.
middleware/logger/logger_test.go (1)
1104-1110: Benchmarks use typed DefaultLogger and LoggerToWriter correctlyGood coverage for the generic path in both serial and parallel benches. If you adopt the CommonLogger simplification in LoggerToWriter, the benchmark call sites won’t need generics.
Also applies to: 1259-1265
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (10)
client/client.go(1 hunks)docs/api/log.md(6 hunks)docs/whats_new.md(3 hunks)log/default.go(2 hunks)log/default_test.go(1 hunks)log/fiberlog.go(1 hunks)log/fiberlog_test.go(3 hunks)log/log.go(3 hunks)middleware/logger/logger_test.go(4 hunks)middleware/logger/utils.go(3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
docs/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Review and update the contents of the
docsfolder if necessary when modifying code
Files:
docs/api/log.mddocs/whats_new.md
🧠 Learnings (1)
📚 Learning: 2024-11-15T07:56:21.623Z
Learnt from: ReneWerner87
PR: gofiber/fiber#3161
File: app.go:923-932
Timestamp: 2024-11-15T07:56:21.623Z
Learning: In the Fiber framework, breaking changes are acceptable when moving from version 2 to version 3, including modifications to method signatures such as in the `Test` method in `app.go`.
Applied to files:
docs/whats_new.md
🧬 Code graph analysis (8)
client/client.go (1)
log/default.go (1)
DefaultLogger(219-222)
log/default.go (1)
log/log.go (2)
AllLogger(80-86)Logger(26-34)
log/fiberlog.go (1)
log/log.go (1)
AllLogger(80-86)
log/default_test.go (1)
log/log.go (1)
Logger(26-34)
log/fiberlog_test.go (2)
log/default.go (1)
DefaultLogger(219-222)log/log.go (1)
Logger(26-34)
middleware/logger/utils.go (1)
log/log.go (2)
AllLogger(80-86)Level(91-91)
log/log.go (1)
log/fiberlog.go (3)
SetLevel(139-141)SetOutput(132-134)WithContext(120-122)
middleware/logger/logger_test.go (3)
log/default.go (1)
DefaultLogger(219-222)log/log.go (2)
Logger(26-34)LevelFatal(100-100)middleware/logger/utils.go (1)
LoggerToWriter(73-88)
🪛 GitHub Check: lint
log/default.go
[failure] 220-220:
Error return value is not checked (errcheck)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: unit (1.25.x, macos-13)
- GitHub Check: unit (1.25.x, windows-latest)
- GitHub Check: unit (1.25.x, macos-latest)
- GitHub Check: repeated
- GitHub Check: Compare
🔇 Additional comments (16)
log/log.go (2)
20-23: Global default uses std log with rich flags — LGTMGood defaults: stderr +
LstdFlags|Lshortfile|Lmicrosecondsanddepth: 4.
65-76: TypedLogger() Tis the right callChanging
ConfigurableLoggertoConfigurableLogger[T]withLogger() Teliminates unsafe assertions on the consumer side. Nice.docs/whats_new.md (2)
986-989: Good overview of the new typed logger surfaceClear statement of
AllLogger[T]+Logger().
1413-1413: Index update for Log migration — LGTMAnchor aligns with the new section.
docs/api/log.md (4)
120-121: Nice compile-time guarantee
var _ fiberlog.AllLogger[*log.Logger] = (*customLogger)(nil)is a good interface guard.
129-132: Typed SetLogger example — LGTMUsing
SetLogger[*log.Logger]demonstrates the generic API well.
133-136: Good: direct typed access to std logger
DefaultLogger[*log.Logger]().Logger()removing runtime assertions is exactly the benefit users need.
211-215: Typed retrieval section — LGTMClear and accurate.
log/default_test.go (1)
233-236: Test now reflects typedLogger()— LGTMDropping the runtime type assertion is correct after making
Logger()return a concrete*log.Logger.log/fiberlog_test.go (3)
13-15: Typed DefaultLogger usage LGTMSwitching to DefaultLogger*log.Logger removes runtime type assertions and is consistent with the new API.
73-78: Benchmark DefaultSystemLogger typed call LGTMUsing the typed DefaultLogger in the benchmark is consistent and keeps allocations observable.
139-147: Parallel read of DefaultLogger is fine; ensure no concurrent SetLogger during this benchReading the global logger concurrently is benign if no concurrent writers. Keep this bench isolated from SetLogger concurrent benches when running with -race.
log/default.go (2)
214-216: Logger() return type LGTMReturning *log.Logger directly improves ergonomics and removes type assertions in tests and examples.
14-14: Compile-time assertion LGTMAsserting defaultLogger implements AllLogger[*log.Logger] ensures API coherence after the generics shift.
middleware/logger/logger_test.go (2)
344-346: Typed DefaultLogger + direct std logger access LGTMUsing DefaultLogger[*log.Logger] and then Logger() avoids reflection and clarifies intent.
381-384: LoggerToWriter generic usage and panic tests LGTMTyped invocation matches the new signature; invalid level and nil logger panics are well-covered.
Also applies to: 396-406
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Summary
Logger()and makeDefaultLogger/SetLoggergenericLoggerToWriterhelper and document typed logger usageTesting
make audit(fails: EncodeMsg passes lock by value)make generatemake betteralign(fails: package requires newer Go version go1.25)make modernize(fails: package requires newer Go version go1.25)make formatmake testhttps://chatgpt.com/codex/tasks/task_e_68a9b76433788326b13092e0c67f49e8