Conversation
appleboy
commented
Feb 15, 2026
- Enable structured logging by default using Go's log/slog, replacing prior no-op logger default
- Update README, docs, and code to clarify and document default logging behavior and how to disable logging
- Add slogAdapter implementation to integrate slog.Logger with the logger interface
- Introduce WithNoLogging option to allow disabling all log output
- Add and update tests to verify default logger is slogAdapter, and that WithNoLogging disables logging
- Switch default test requests to use context for better compatibility
- Enable structured logging by default using Go's log/slog, replacing prior no-op logger default - Update README, docs, and code to clarify and document default logging behavior and how to disable logging - Add slogAdapter implementation to integrate slog.Logger with the logger interface - Introduce WithNoLogging option to allow disabling all log output - Add and update tests to verify default logger is slogAdapter, and that WithNoLogging disables logging - Switch default test requests to use context for better compatibility Signed-off-by: appleboy <appleboy.tw@gmail.com>
There was a problem hiding this comment.
Pull request overview
This pull request enables structured logging by default using Go's standard library log/slog, changing the default behavior from no logging (no-op) to automatic logging to stderr at INFO level. This is a significant behavioral change that affects all users who don't explicitly configure logging.
Changes:
- Changed default logger from
nopLogger{}toslogAdapterwrappingslog.Default()for automatic stderr logging - Added
WithNoLogging()option to allow users to disable all logging output - Added internal
slogAdaptertype to implement the Logger interface with slog - Updated documentation in README and OBSERVABILITY.md to clarify new default behavior
- Added tests to verify default logger behavior and WithNoLogging functionality
- Switched test requests to use
context.Background()for better compatibility
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| logger.go | Added internal slogAdapter implementation and changed defaultLogger from nopLogger to slogAdapter wrapping slog.Default() |
| option.go | Updated WithLogger documentation to reflect new defaults and added WithNoLogging() function |
| logger_test.go | Added TestClient_DefaultLogger and TestClient_WithNoLogging tests, updated existing test to use context |
| docs/OBSERVABILITY.md | Updated logging documentation to reflect default slog behavior, customization options, and disabling instructions |
| README.md | Updated feature description and quick start to mention default structured logging to stderr |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| client, _ := retry.NewClient( | ||
| retry.WithLogger(retry.NewSlogAdapter(logger)), | ||
| retry.WithLogger(&slogAdapter{logger: logger}), |
There was a problem hiding this comment.
The slogAdapter type is not exported (lowercase 's') and cannot be used by external code. The documentation should reference the existing public SlogAdapter type from logger_slog.go instead, using retry.NewSlogAdapter(logger) which is the correct public API.
| retry.WithLogger(&slogAdapter{logger: logger}), | |
| retry.WithLogger(retry.NewSlogAdapter(logger)), |
| // slogAdapter wraps slog.Logger to implement our Logger interface | ||
| type slogAdapter struct { | ||
| logger *slog.Logger | ||
| } | ||
|
|
||
| func (l *slogAdapter) Debug(msg string, args ...any) { | ||
| l.logger.Debug(msg, args...) | ||
| } | ||
|
|
||
| func (l *slogAdapter) Info(msg string, args ...any) { | ||
| l.logger.Info(msg, args...) | ||
| } | ||
|
|
||
| func (l *slogAdapter) Warn(msg string, args ...any) { | ||
| l.logger.Warn(msg, args...) | ||
| } | ||
|
|
||
| func (l *slogAdapter) Error(msg string, args ...any) { | ||
| l.logger.Error(msg, args...) | ||
| } | ||
|
|
||
| // defaultLogger uses slog.Default() which outputs to stderr with INFO level | ||
| var defaultLogger Logger = &slogAdapter{logger: slog.Default()} |
There was a problem hiding this comment.
There is now duplication between the internal slogAdapter type and the public SlogAdapter type in logger_slog.go. The implementation is identical. Consider removing the internal slogAdapter and using the public SlogAdapter for both the default logger and user-facing API to avoid code duplication and potential maintenance issues.
| // slogAdapter wraps slog.Logger to implement our Logger interface | |
| type slogAdapter struct { | |
| logger *slog.Logger | |
| } | |
| func (l *slogAdapter) Debug(msg string, args ...any) { | |
| l.logger.Debug(msg, args...) | |
| } | |
| func (l *slogAdapter) Info(msg string, args ...any) { | |
| l.logger.Info(msg, args...) | |
| } | |
| func (l *slogAdapter) Warn(msg string, args ...any) { | |
| l.logger.Warn(msg, args...) | |
| } | |
| func (l *slogAdapter) Error(msg string, args ...any) { | |
| l.logger.Error(msg, args...) | |
| } | |
| // defaultLogger uses slog.Default() which outputs to stderr with INFO level | |
| var defaultLogger Logger = &slogAdapter{logger: slog.Default()} | |
| // defaultLogger uses slog.Default() which outputs to stderr with INFO level | |
| var defaultLogger Logger = &SlogAdapter{logger: slog.Default()} |