diff --git a/go.mod b/go.mod index 9a725cb167..6dbb12b93a 100644 --- a/go.mod +++ b/go.mod @@ -120,6 +120,7 @@ require ( github.com/onsi/gomega v1.34.0 github.com/prometheus-community/prom-label-proxy v0.8.1-0.20240127162815-c1195f9aabc0 github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 + github.com/tjhop/slog-gokit v0.1.2 go.opentelemetry.io/contrib/propagators/autoprop v0.54.0 go4.org/intern v0.0.0-20230525184215-6c62f75575cb golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 diff --git a/go.sum b/go.sum index 9933abda40..3139bfe868 100644 --- a/go.sum +++ b/go.sum @@ -2263,6 +2263,8 @@ github.com/themihai/gomemcache v0.0.0-20180902122335-24332e2d58ab h1:7ZR3hmisBWw github.com/themihai/gomemcache v0.0.0-20180902122335-24332e2d58ab/go.mod h1:eheTFp954zcWZXCU8d0AT76ftsQOTo4DTqkN/h3k1MY= github.com/tinylib/msgp v1.1.5 h1:2gXmtWueD2HefZHQe1QOy9HVzmFrLOVvsXwXBQ0ayy0= github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= +github.com/tjhop/slog-gokit v0.1.2 h1:pmQI4SvU9h4gA0vIQsdhJQSqQg4mOmsPykG2/PM3j1I= +github.com/tjhop/slog-gokit v0.1.2/go.mod h1:8fhlcp8C8ELbg3GCyKv06tgt4B5sDq2P1r2DQAu1HuM= github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek= github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= diff --git a/pkg/logging/logger.go b/pkg/logging/logger.go index cca8853da5..0e420ad1c5 100644 --- a/pkg/logging/logger.go +++ b/pkg/logging/logger.go @@ -4,10 +4,12 @@ package logging import ( + "log/slog" "os" "github.com/go-kit/log" "github.com/go-kit/log/level" + sloggk "github.com/tjhop/slog-gokit" ) const ( @@ -15,6 +17,11 @@ const ( LogFormatJSON = "json" ) +type LevelLogger struct { + log.Logger + logLevel string +} + // NewLogger returns a log.Logger that prints in the provided format at the // provided level with a UTC timestamp and the caller of the log entry. If non // empty, the debug name is also appended as a field to all log lines. Panics @@ -55,5 +62,29 @@ func NewLogger(logLevel, logFormat, debugName string) log.Logger { logger = log.With(logger, "name", debugName) } - return logger + return LevelLogger{ + Logger: logger, + logLevel: logLevel, + } +} + +// GoKitLogToSlog convert go-kit/log to slog. +func GoKitLogToSlog(logger log.Logger) *slog.Logger { + levelVar := slog.LevelVar{} + levelLogger, ok := logger.(LevelLogger) + if !ok { + levelVar.Set(slog.LevelDebug) + } else { + switch levelLogger.logLevel { + case "debug": + levelVar.Set(slog.LevelDebug) + case "info": + levelVar.Set(slog.LevelInfo) + case "warn": + levelVar.Set(slog.LevelWarn) + case "error": + levelVar.Set(slog.LevelError) + } + } + return slog.New(sloggk.NewGoKitHandler(logger, &levelVar)) } diff --git a/pkg/logging/logger_test.go b/pkg/logging/logger_test.go index 2e4eb3f73f..0c6a7250c8 100644 --- a/pkg/logging/logger_test.go +++ b/pkg/logging/logger_test.go @@ -4,9 +4,12 @@ package logging import ( + "context" + "log/slog" "testing" "github.com/go-kit/log/level" + "github.com/stretchr/testify/require" ) func BenchmarkDisallowedLogLevels(b *testing.B) { @@ -17,3 +20,41 @@ func BenchmarkDisallowedLogLevels(b *testing.B) { level.Debug(logger).Log("hello", "world", "number", i) } } + +func Test_GoKitLogToSlog(t *testing.T) { + ctx := context.Background() + logLevels := []string{"debug", "info", "warn", "error"} + slogLevels := []slog.Level{slog.LevelDebug, slog.LevelInfo, slog.LevelWarn, slog.LevelError} + + for _, logFormat := range []string{"logfmt", "json"} { + for i, lv := range logLevels { + logger := NewLogger(lv, logFormat, "test") + + slog := GoKitLogToSlog(logger) + for j, slogLv := range slogLevels { + if i <= j { + t.Logf("[logFormat: %v, go-kit log level: %v, slog level: %v] slog should be enabled", logFormat, lv, slogLv) + require.True(t, slog.Enabled(ctx, slogLv)) + } else { + t.Logf("[logFormat: %v, go-kit log level: %v, slog level: %v] slog should be disabled", logFormat, lv, slogLv) + require.False(t, slog.Enabled(ctx, slogLv)) + } + + switch lv { + case "debug": + level.Debug(logger).Log("msg", "message", "debug", lv) + slog.Debug("message", "debug", lv) + case "info": + level.Info(logger).Log("msg", "message", "info", lv) + slog.Info("message", "info", lv) + case "warn": + level.Warn(logger).Log("msg", "message", "warn", lv) + slog.Warn("message", "warn", lv) + case "error": + level.Error(logger).Log("msg", "message", "error", lv) + slog.Error("message", "error", lv) + } + } + } + } +}