diff --git a/logger/slog/slog.go b/logger/slog/slog.go index 76a7e1bb..c703955f 100644 --- a/logger/slog/slog.go +++ b/logger/slog/slog.go @@ -15,6 +15,9 @@ import ( "go.unistack.org/micro/v3/tracer" ) +const badKey = "!BADKEY" +const emptyMSg = "!EMPTYMSG" + var reTrace = regexp.MustCompile(`.*/slog/logger\.go.*\n`) var ( @@ -155,6 +158,9 @@ func (s *slogLogger) Log(ctx context.Context, lvl logger.Level, attrs ...interfa if !s.V(lvl) { return } + + attrs = prepareAttributes(attrs) + var pcs [1]uintptr runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(s.opts.TimeFunc(), loggerToSlogLevel(lvl), fmt.Sprintf("%s", attrs[0]), pcs[0]) @@ -235,6 +241,9 @@ func (s *slogLogger) Info(ctx context.Context, attrs ...interface{}) { if !s.V(logger.InfoLevel) { return } + + attrs = prepareAttributes(attrs) + var pcs [1]uintptr runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(s.opts.TimeFunc(), slog.LevelInfo, fmt.Sprintf("%s", attrs[0]), pcs[0]) @@ -279,6 +288,9 @@ func (s *slogLogger) Debug(ctx context.Context, attrs ...interface{}) { if !s.V(logger.DebugLevel) { return } + + attrs = prepareAttributes(attrs) + var pcs [1]uintptr runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(s.opts.TimeFunc(), slog.LevelDebug, fmt.Sprintf("%s", attrs[0]), pcs[0]) @@ -323,6 +335,9 @@ func (s *slogLogger) Trace(ctx context.Context, attrs ...interface{}) { if !s.V(logger.TraceLevel) { return } + + attrs = prepareAttributes(attrs) + var pcs [1]uintptr runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(s.opts.TimeFunc(), slog.LevelDebug-1, fmt.Sprintf("%s", attrs[0]), pcs[0]) @@ -367,6 +382,9 @@ func (s *slogLogger) Error(ctx context.Context, attrs ...interface{}) { if !s.V(logger.ErrorLevel) { return } + + attrs = prepareAttributes(attrs) + var pcs [1]uintptr runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(s.opts.TimeFunc(), slog.LevelError, fmt.Sprintf("%s", attrs[0]), pcs[0]) @@ -447,6 +465,9 @@ func (s *slogLogger) Fatal(ctx context.Context, attrs ...interface{}) { if !s.V(logger.FatalLevel) { return } + + attrs = prepareAttributes(attrs) + var pcs [1]uintptr runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(s.opts.TimeFunc(), slog.LevelError+1, fmt.Sprintf("%s", attrs[0]), pcs[0]) @@ -493,6 +514,9 @@ func (s *slogLogger) Warn(ctx context.Context, attrs ...interface{}) { if !s.V(logger.WarnLevel) { return } + + attrs = prepareAttributes(attrs) + var pcs [1]uintptr runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(s.opts.TimeFunc(), slog.LevelWarn, fmt.Sprintf("%s", attrs[0]), pcs[0]) @@ -581,3 +605,18 @@ func slogToLoggerLevel(level slog.Level) logger.Level { return logger.InfoLevel } } + +func prepareAttributes(attrs []interface{}) []interface{} { + if len(attrs) == 0 { + return append(attrs, emptyMSg) + } else if len(attrs) == 1 { + return attrs + } + + if len(attrs)%2 == 1 { + attrs = append(attrs, badKey) + attrs[len(attrs)-1], attrs[len(attrs)-2] = attrs[len(attrs)-2], attrs[len(attrs)-1] + } + + return attrs +} diff --git a/logger/slog/slog_test.go b/logger/slog/slog_test.go index 93c63c79..f1b9ad44 100644 --- a/logger/slog/slog_test.go +++ b/logger/slog/slog_test.go @@ -95,10 +95,15 @@ func TestFromContextWithFields(t *testing.T) { t.Fatalf("context does not have logger") } - l.Info(ctx, "message") + l.Info(ctx) if !bytes.Contains(buf.Bytes(), []byte(`"key":"val"`)) { t.Fatalf("logger fields not works, buf contains: %s", buf.Bytes()) } + + l.Info(ctx, "test", "uncorrected number attributes") + if !bytes.Contains(buf.Bytes(), []byte(`"!BADKEY":"uncorrected number attributes"`)) { + t.Fatalf("logger fields not works, buf contains: %s", buf.Bytes()) + } } func TestClone(t *testing.T) {