diff --git a/logger/slog/slog.go b/logger/slog/slog.go index 76279083..ee1fe17a 100644 --- a/logger/slog/slog.go +++ b/logger/slog/slog.go @@ -192,27 +192,34 @@ func (s *slogLogger) String() string { return "slog" } -func (s *slogLogger) printLog(ctx context.Context, lvl logger.Level, msg string, attrs ...interface{}) { +func (s *slogLogger) printLog(ctx context.Context, lvl logger.Level, msg string, args ...interface{}) { if !s.V(lvl) { return } + var argError error s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", lvl.String()).Inc() - attrs = prepareAttributes(attrs) - - for _, fn := range s.opts.ContextAttrFuncs { - a := prepareAttributes(fn(ctx)) - attrs = append(attrs, a...) + attrs, err := s.argsAttrs(args) + if err != nil { + argError = err + } + if argError != nil { + if span, ok := tracer.SpanFromContext(ctx); ok { + span.SetStatus(tracer.SpanStatusError, argError.Error()) + } } - for _, attr := range attrs { - if ve, hasErr := attr.(error); hasErr && ve != nil { - attrs = append(attrs, slog.String(s.opts.ErrorKey, ve.Error())) - if span, ok := tracer.SpanFromContext(ctx); ok { - span.SetStatus(tracer.SpanStatusError, ve.Error()) - } - break + for _, fn := range s.opts.ContextAttrFuncs { + ctxAttrs, err := s.argsAttrs(fn(ctx)) + if err != nil { + argError = err + } + attrs = append(attrs, ctxAttrs...) + } + if argError != nil { + if span, ok := tracer.SpanFromContext(ctx); ok { + span.SetStatus(tracer.SpanStatusError, argError.Error()) } } @@ -229,7 +236,7 @@ func (s *slogLogger) printLog(ctx context.Context, lvl logger.Level, msg string, var pcs [1]uintptr runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, printLog, LogLvlMethod] r := slog.NewRecord(s.opts.TimeFunc(), loggerToSlogLevel(lvl), msg, pcs[0]) - r.Add(attrs...) + r.AddAttrs(attrs...) _ = s.handler.Handle(ctx, r) } @@ -276,11 +283,26 @@ func slogToLoggerLevel(level slog.Level) logger.Level { } } -func prepareAttributes(attrs []interface{}) []interface{} { - 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] +func (s *slogLogger) argsAttrs(args []interface{}) ([]slog.Attr, error) { + attrs := make([]slog.Attr, 0, len(args)) + var err error + + for idx := 0; idx < len(args); idx++ { + switch arg := args[idx].(type) { + case slog.Attr: + attrs = append(attrs, arg) + case string: + if idx+1 < len(args) { + attrs = append(attrs, slog.Any(arg, args[idx+1])) + idx += 1 + } else { + attrs = append(attrs, slog.String(badKey, arg)) + } + case error: + attrs = append(attrs, slog.String(s.opts.ErrorKey, arg.Error())) + err = arg + } } - return attrs + return attrs, err } diff --git a/logger/slog/slog_test.go b/logger/slog/slog_test.go index f8daace0..fc381892 100644 --- a/logger/slog/slog_test.go +++ b/logger/slog/slog_test.go @@ -5,12 +5,13 @@ import ( "context" "errors" "fmt" - "github.com/google/uuid" - "go.unistack.org/micro/v3/metadata" "log" "strings" "testing" + "github.com/google/uuid" + "go.unistack.org/micro/v3/metadata" + "go.unistack.org/micro/v3/logger" ) @@ -43,9 +44,6 @@ func TestErrorf(t *testing.T) { } l.Log(ctx, logger.ErrorLevel, "message", errors.New("error msg")) - if !bytes.Contains(buf.Bytes(), []byte(`"!BADKEY":"`)) { - t.Fatalf("logger BADKEY not works, buf contains: %s", buf.Bytes()) - } l.Log(ctx, logger.ErrorLevel, "", errors.New("error msg")) if !bytes.Contains(buf.Bytes(), []byte(`"error":"error msg"`)) { @@ -236,5 +234,4 @@ func Test_WithContextAttrFunc(t *testing.T) { if !(bytes.Contains(buf.Bytes(), []byte(`"source-service":"Test-System"`))) { t.Fatalf("logger info, buf %s", buf.Bytes()) } - }