From 09c44945f42f2a6d0d9fa02afc669aa7387da10a Mon Sep 17 00:00:00 2001 From: TJ Hoplock Date: Mon, 2 Sep 2024 16:36:28 -0400 Subject: [PATCH] feat(promslog): add NewWithWriter() to allow logging other than stderr Accepting an `io.Writer` makes it easy to plug-n-play with slog directly while also making the logging output destination configurable. We explicilty make no attempt to manage the underlying writer and leave it to the caller to ensure proper management/cleanup. Example usage to allow writing a JSON file: ```go file, err := os.OpenFile("/tmp/json.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600) if err != nil { panic(err) } defer file.Close() logger := NewWithWriter(&Config{}, file) logger.Info("I'm writing to a file!", "hello", "world") ... ``` Example output: ```bash ~ cat /tmp/json.log time=2024-09-02T16:43:30.925-04:00 level=INFO source=/home/tjhop/go/src/github.com/prometheus/common/promslog/slog_test.go:162 msg="I'm writing to a file!" hello=world ``` Signed-off-by: TJ Hoplock --- promslog/slog.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/promslog/slog.go b/promslog/slog.go index 7fb24d41..00468ad7 100644 --- a/promslog/slog.go +++ b/promslog/slog.go @@ -154,9 +154,7 @@ type Config struct { ioWriter io.Writer } -// New returns a new slog.Logger. Each logged line will be annotated -// with a timestamp. The output always goes to stderr. -func New(config *Config) *slog.Logger { +func newSlogHandlerOptions(config *Config) *slog.HandlerOptions { if config.Level == nil { config.Level = &AllowedLevel{} _ = config.Level.Set("info") @@ -175,8 +173,28 @@ func New(config *Config) *slog.Logger { logHandlerOpts.ReplaceAttr = goKitStyleReplaceAttrFunc } + return logHandlerOpts +} + +// New returns a new slog.Logger. Each logged line will be annotated +// with a timestamp. The output always goes to stderr. +func New(config *Config) *slog.Logger { + logHandlerOpts := newSlogHandlerOptions(config) if config.Format != nil && config.Format.s == "json" { return slog.New(slog.NewJSONHandler(config.ioWriter, logHandlerOpts)) } return slog.New(slog.NewTextHandler(config.ioWriter, logHandlerOpts)) } + +// New returns a new slog.Logger, with the logger's output set to the provided +// `io.Writer`. Management of the writer is beyond the scope of this function +// and is the responsibility of the caller to properly close, if needed. Each +// logged line will be annotated with a timestamp. The output always goes to +// stderr. +func NewWithWriter(config *Config, writer io.Writer) *slog.Logger { + logHandlerOpts := newSlogHandlerOptions(config) + if config.Format != nil && config.Format.s == "json" { + return slog.New(slog.NewJSONHandler(writer, logHandlerOpts)) + } + return slog.New(slog.NewTextHandler(writer, logHandlerOpts)) +}