-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
Proposal
Add a package-level variable slog.DiscardHandler
(type slog.Handler
) that will discard all log output.
Rationale
I have been happily busying myself integrating log/slog
into old packages and replacing the exp
import in new ones, however I've found myself implementing the same "nop handler" again and again in packages with optional logging APIs.
A common pattern in logging injection is to consume an interface or a pointer to a logging type to allow the dependency to use a derived logger with some field marking the messages as originating from that component, enabling both a standard format as well as per-component level thresholds to keep the output sane. For packages that support slog
, this will likely often end up being a *slog.Logger
or a slog.Handler
, however I've also had to develop a series of log adapters for common dependencies which use their own concrete types, interfaces and callbacks.
In both of these cases, it is helpful to have a default fallback which logs nothing, so that the packages can be tested or used on their own without needing boilerplate guard clauses on every logging method to check for nil values. It's also helpful for less well-behaved dependencies which create their own loggers if one is not provided, some of whom are exceptionally chatty for no good reason. Packages like this are sadly far too common, and we're likely to continue seeing them, so a way to bring some sanity to the process would be very useful.
While it's true that checks for the presence of logging can be reduced by funneling all handler interaction through a single point, this introduces another sort of boilerplate for slog
where Record
s need to be created manually, adjusting their PC to account for the extra frame as seen in the wrapping example. This is a low-level and overly-manual process just to enable conditional logging.
Currently, there doesn't seem to be a great answer for this in slog
:
- there are no guards for a nil receiver on
*Logger
methods - the zero value of
Logger
is not usable and will panic Logger
s initialized with anil
handler will panic- there is no way to modify a logger to change its handler or logging level once it's created, making
slog.Default()
unworkable as a fallback defaultHandler
is unexported, so it cannot act as a fallback, and handlers do not provide aWithLevel
orWithLeveler
method, so it wouldn't work as a fallback even if it were exported.HandlerOptions
, which allows specifying a minimum level, only applies to the built-in handlers, and there is noWithHandlerOptions
that would allow derived handlers to adjust their logging level using this type.
Leaving aside the arguments on the merits of logging in packages, this pattern is nonetheless common enough that it would probably be useful to have a type DisabledHandler struct{}
or even a func DisabledLogger()*Logger
convenience method that could act as a default. when the zero values are nil
.
Metadata
Metadata
Assignees
Type
Projects
Status