logger: slog break import cycle
All checks were successful
/ autoupdate (push) Successful in 1m13s

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2023-10-17 01:48:50 +03:00
parent 8d19abfebd
commit 79438f11e0
5 changed files with 156 additions and 67 deletions

View File

@ -3,7 +3,6 @@ package logger
import ( import (
"context" "context"
"os"
"go.unistack.org/micro/v4/options" "go.unistack.org/micro/v4/options"
) )
@ -14,10 +13,7 @@ var DefaultContextAttrFuncs []ContextAttrFunc
var ( var (
// DefaultLogger variable // DefaultLogger variable
DefaultLogger = NewLogger( DefaultLogger = NewLogger()
WithLevel(ParseLevel(os.Getenv("MICRO_LOG_LEVEL"))),
WithContextAttrFuncs(DefaultContextAttrFuncs...),
)
// DefaultLevel used by logger // DefaultLevel used by logger
DefaultLevel = InfoLevel DefaultLevel = InfoLevel
// DefaultCallerSkipCount used by logger // DefaultCallerSkipCount used by logger

71
logger/noop.go Normal file
View File

@ -0,0 +1,71 @@
package logger
import (
"context"
"go.unistack.org/micro/v4/options"
)
type noopLogger struct {
opts Options
}
func NewLogger(opts ...options.Option) Logger {
options := NewOptions(opts...)
return &noopLogger{opts: options}
}
func (l *noopLogger) V(lvl Level) bool {
return false
}
func (l *noopLogger) Level(lvl Level) {
}
func (l *noopLogger) Init(opts ...options.Option) error {
for _, o := range opts {
o(&l.opts)
}
return nil
}
func (l *noopLogger) Clone(opts ...options.Option) Logger {
nl := &noopLogger{opts: l.opts}
for _, o := range opts {
o(&nl.opts)
}
return nl
}
func (l *noopLogger) Attrs(attrs ...interface{}) Logger {
return l
}
func (l *noopLogger) Options() Options {
return l.opts
}
func (l *noopLogger) String() string {
return "noop"
}
func (l *noopLogger) Log(ctx context.Context, lvl Level, msg string, attrs ...interface{}) {
}
func (l *noopLogger) Info(ctx context.Context, msg string, attrs ...interface{}) {
}
func (l *noopLogger) Debug(ctx context.Context, msg string, attrs ...interface{}) {
}
func (l *noopLogger) Error(ctx context.Context, msg string, attrs ...interface{}) {
}
func (l *noopLogger) Trace(ctx context.Context, msg string, attrs ...interface{}) {
}
func (l *noopLogger) Warn(ctx context.Context, msg string, attrs ...interface{}) {
}
func (l *noopLogger) Fatal(ctx context.Context, msg string, attrs ...interface{}) {
}

View File

@ -1,4 +1,4 @@
package logger package slog
import ( import (
"context" "context"
@ -8,7 +8,9 @@ import (
"strconv" "strconv"
"time" "time"
"go.unistack.org/micro/v4/logger"
"go.unistack.org/micro/v4/options" "go.unistack.org/micro/v4/options"
"go.unistack.org/micro/v4/tracer"
) )
var ( var (
@ -35,17 +37,17 @@ func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
lvl := slogToLoggerLevel(level) lvl := slogToLoggerLevel(level)
a.Key = s.opts.LevelKey a.Key = s.opts.LevelKey
switch { switch {
case lvl < DebugLevel: case lvl < logger.DebugLevel:
a.Value = traceValue a.Value = traceValue
case lvl < InfoLevel: case lvl < logger.InfoLevel:
a.Value = debugValue a.Value = debugValue
case lvl < WarnLevel: case lvl < logger.WarnLevel:
a.Value = infoValue a.Value = infoValue
case lvl < ErrorLevel: case lvl < logger.ErrorLevel:
a.Value = warnValue a.Value = warnValue
case lvl < FatalLevel: case lvl < logger.FatalLevel:
a.Value = errorValue a.Value = errorValue
case lvl >= FatalLevel: case lvl >= logger.FatalLevel:
a.Value = fatalValue a.Value = fatalValue
default: default:
a.Value = infoValue a.Value = infoValue
@ -58,10 +60,10 @@ func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
type slogLogger struct { type slogLogger struct {
slog *slog.Logger slog *slog.Logger
leveler *slog.LevelVar leveler *slog.LevelVar
opts Options opts logger.Options
} }
func (s *slogLogger) Clone(opts ...options.Option) Logger { func (s *slogLogger) Clone(opts ...options.Option) logger.Logger {
options := s.opts options := s.opts
for _, o := range opts { for _, o := range opts {
@ -72,10 +74,12 @@ func (s *slogLogger) Clone(opts ...options.Option) Logger {
opts: options, opts: options,
} }
/*
if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok { if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok {
l.slog = slog l.slog = slog
return nil return nil
} }
*/
l.leveler = new(slog.LevelVar) l.leveler = new(slog.LevelVar)
handleOpt := &slog.HandlerOptions{ handleOpt := &slog.HandlerOptions{
@ -90,19 +94,19 @@ func (s *slogLogger) Clone(opts ...options.Option) Logger {
return l return l
} }
func (s *slogLogger) V(level Level) bool { func (s *slogLogger) V(level logger.Level) bool {
return s.opts.Level.Enabled(level) return s.opts.Level.Enabled(level)
} }
func (s *slogLogger) Level(level Level) { func (s *slogLogger) Level(level logger.Level) {
s.leveler.Set(loggerToSlogLevel(level)) s.leveler.Set(loggerToSlogLevel(level))
} }
func (s *slogLogger) Options() Options { func (s *slogLogger) Options() logger.Options {
return s.opts return s.opts
} }
func (s *slogLogger) Attrs(attrs ...interface{}) Logger { func (s *slogLogger) Attrs(attrs ...interface{}) logger.Logger {
nl := &slogLogger{opts: s.opts} nl := &slogLogger{opts: s.opts}
nl.leveler = new(slog.LevelVar) nl.leveler = new(slog.LevelVar)
nl.leveler.Set(s.leveler.Level()) nl.leveler.Set(s.leveler.Level())
@ -121,17 +125,20 @@ func (s *slogLogger) Attrs(attrs ...interface{}) Logger {
func (s *slogLogger) Init(opts ...options.Option) error { func (s *slogLogger) Init(opts ...options.Option) error {
if len(s.opts.ContextAttrFuncs) == 0 { if len(s.opts.ContextAttrFuncs) == 0 {
s.opts.ContextAttrFuncs = DefaultContextAttrFuncs s.opts.ContextAttrFuncs = logger.DefaultContextAttrFuncs
} }
for _, o := range opts { for _, o := range opts {
if err := o(&s.opts); err != nil { if err := o(&s.opts); err != nil {
return err return err
} }
} }
/*
if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok { if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok {
s.slog = slog s.slog = slog
return nil return nil
} }
*/
s.leveler = new(slog.LevelVar) s.leveler = new(slog.LevelVar)
handleOpt := &slog.HandlerOptions{ handleOpt := &slog.HandlerOptions{
@ -146,7 +153,7 @@ func (s *slogLogger) Init(opts ...options.Option) error {
return nil return nil
} }
func (s *slogLogger) Log(ctx context.Context, lvl Level, msg string, attrs ...interface{}) { func (s *slogLogger) Log(ctx context.Context, lvl logger.Level, msg string, attrs ...interface{}) {
if !s.V(lvl) { if !s.V(lvl) {
return return
} }
@ -161,7 +168,7 @@ func (s *slogLogger) Log(ctx context.Context, lvl Level, msg string, attrs ...in
} }
func (s *slogLogger) Info(ctx context.Context, msg string, attrs ...interface{}) { func (s *slogLogger) Info(ctx context.Context, msg string, attrs ...interface{}) {
if !s.V(InfoLevel) { if !s.V(logger.InfoLevel) {
return return
} }
var pcs [1]uintptr var pcs [1]uintptr
@ -175,7 +182,7 @@ func (s *slogLogger) Info(ctx context.Context, msg string, attrs ...interface{})
} }
func (s *slogLogger) Debug(ctx context.Context, msg string, attrs ...interface{}) { func (s *slogLogger) Debug(ctx context.Context, msg string, attrs ...interface{}) {
if !s.V(InfoLevel) { if !s.V(logger.DebugLevel) {
return return
} }
var pcs [1]uintptr var pcs [1]uintptr
@ -189,7 +196,7 @@ func (s *slogLogger) Debug(ctx context.Context, msg string, attrs ...interface{}
} }
func (s *slogLogger) Trace(ctx context.Context, msg string, attrs ...interface{}) { func (s *slogLogger) Trace(ctx context.Context, msg string, attrs ...interface{}) {
if !s.V(InfoLevel) { if !s.V(logger.TraceLevel) {
return return
} }
var pcs [1]uintptr var pcs [1]uintptr
@ -203,7 +210,7 @@ func (s *slogLogger) Trace(ctx context.Context, msg string, attrs ...interface{}
} }
func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{}) { func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{}) {
if !s.V(InfoLevel) { if !s.V(logger.ErrorLevel) {
return return
} }
var pcs [1]uintptr var pcs [1]uintptr
@ -213,11 +220,20 @@ func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{}
attrs = append(attrs, fn(ctx)...) attrs = append(attrs, fn(ctx)...)
} }
r.Add(attrs...) r.Add(attrs...)
r.Attrs(func(a slog.Attr) bool {
if a.Key == "error" {
if span, ok := tracer.SpanFromContext(ctx); ok {
span.SetStatus(tracer.SpanStatusError, a.Value.String())
return false
}
}
return true
})
_ = s.slog.Handler().Handle(ctx, r) _ = s.slog.Handler().Handle(ctx, r)
} }
func (s *slogLogger) Fatal(ctx context.Context, msg string, attrs ...interface{}) { func (s *slogLogger) Fatal(ctx context.Context, msg string, attrs ...interface{}) {
if !s.V(InfoLevel) { if !s.V(logger.FatalLevel) {
return return
} }
var pcs [1]uintptr var pcs [1]uintptr
@ -232,7 +248,7 @@ func (s *slogLogger) Fatal(ctx context.Context, msg string, attrs ...interface{}
} }
func (s *slogLogger) Warn(ctx context.Context, msg string, attrs ...interface{}) { func (s *slogLogger) Warn(ctx context.Context, msg string, attrs ...interface{}) {
if !s.V(InfoLevel) { if !s.V(logger.WarnLevel) {
return return
} }
var pcs [1]uintptr var pcs [1]uintptr
@ -249,43 +265,43 @@ func (s *slogLogger) String() string {
return "slog" return "slog"
} }
func NewLogger(opts ...options.Option) Logger { func NewLogger(opts ...options.Option) logger.Logger {
l := &slogLogger{ l := &slogLogger{
opts: NewOptions(opts...), opts: logger.NewOptions(opts...),
} }
return l return l
} }
func loggerToSlogLevel(level Level) slog.Level { func loggerToSlogLevel(level logger.Level) slog.Level {
switch level { switch level {
case DebugLevel: case logger.DebugLevel:
return slog.LevelDebug return slog.LevelDebug
case WarnLevel: case logger.WarnLevel:
return slog.LevelWarn return slog.LevelWarn
case ErrorLevel: case logger.ErrorLevel:
return slog.LevelError return slog.LevelError
case TraceLevel: case logger.TraceLevel:
return slog.LevelDebug - 1 return slog.LevelDebug - 1
case FatalLevel: case logger.FatalLevel:
return slog.LevelError + 1 return slog.LevelError + 1
default: default:
return slog.LevelInfo return slog.LevelInfo
} }
} }
func slogToLoggerLevel(level slog.Level) Level { func slogToLoggerLevel(level slog.Level) logger.Level {
switch level { switch level {
case slog.LevelDebug: case slog.LevelDebug:
return DebugLevel return logger.DebugLevel
case slog.LevelWarn: case slog.LevelWarn:
return WarnLevel return logger.WarnLevel
case slog.LevelError: case slog.LevelError:
return ErrorLevel return logger.ErrorLevel
case slog.LevelDebug - 1: case slog.LevelDebug - 1:
return TraceLevel return logger.TraceLevel
case slog.LevelError + 1: case slog.LevelError + 1:
return FatalLevel return logger.FatalLevel
default: default:
return InfoLevel return logger.InfoLevel
} }
} }

View File

@ -1,21 +1,23 @@
package logger package slog
import ( import (
"bytes" "bytes"
"context" "context"
"log" "log"
"testing" "testing"
"go.unistack.org/micro/v4/logger"
) )
func TestContext(t *testing.T) { func TestContext(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
l := NewLogger(WithLevel(TraceLevel), WithOutput(buf)) l := NewLogger(logger.WithLevel(logger.TraceLevel), logger.WithOutput(buf))
if err := l.Init(); err != nil { if err := l.Init(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
nl, ok := FromContext(NewContext(ctx, l.Attrs("key", "val"))) nl, ok := logger.FromContext(logger.NewContext(ctx, l.Attrs("key", "val")))
if !ok { if !ok {
t.Fatal("context without logger") t.Fatal("context without logger")
} }
@ -28,7 +30,7 @@ func TestContext(t *testing.T) {
func TestAttrs(t *testing.T) { func TestAttrs(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
l := NewLogger(WithLevel(TraceLevel), WithOutput(buf)) l := NewLogger(logger.WithLevel(logger.TraceLevel), logger.WithOutput(buf))
if err := l.Init(); err != nil { if err := l.Init(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -45,15 +47,15 @@ func TestFromContextWithFields(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
var ok bool var ok bool
l := NewLogger(WithLevel(TraceLevel), WithOutput(buf)) l := NewLogger(logger.WithLevel(logger.TraceLevel), logger.WithOutput(buf))
if err := l.Init(); err != nil { if err := l.Init(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
nl := l.Attrs("key", "val") nl := l.Attrs("key", "val")
ctx = NewContext(ctx, nl) ctx = logger.NewContext(ctx, nl)
l, ok = FromContext(ctx) l, ok = logger.FromContext(ctx)
if !ok { if !ok {
t.Fatalf("context does not have logger") t.Fatalf("context does not have logger")
} }
@ -67,11 +69,11 @@ func TestFromContextWithFields(t *testing.T) {
func TestClone(t *testing.T) { func TestClone(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
l := NewLogger(WithLevel(TraceLevel), WithOutput(buf)) l := NewLogger(logger.WithLevel(logger.TraceLevel), logger.WithOutput(buf))
if err := l.Init(); err != nil { if err := l.Init(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
nl := l.Clone(WithLevel(ErrorLevel)) nl := l.Clone(logger.WithLevel(logger.ErrorLevel))
if err := nl.Init(); err != nil { if err := nl.Init(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -87,11 +89,11 @@ func TestClone(t *testing.T) {
func TestRedirectStdLogger(t *testing.T) { func TestRedirectStdLogger(t *testing.T) {
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
l := NewLogger(WithLevel(ErrorLevel), WithOutput(buf)) l := NewLogger(logger.WithLevel(logger.ErrorLevel), logger.WithOutput(buf))
if err := l.Init(); err != nil { if err := l.Init(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
fn := RedirectStdLogger(l, ErrorLevel) fn := logger.RedirectStdLogger(l, logger.ErrorLevel)
defer fn() defer fn()
log.Print("test") log.Print("test")
if !(bytes.Contains(buf.Bytes(), []byte(`"level":"error"`)) && bytes.Contains(buf.Bytes(), []byte(`"msg":"test"`))) { if !(bytes.Contains(buf.Bytes(), []byte(`"level":"error"`)) && bytes.Contains(buf.Bytes(), []byte(`"msg":"test"`))) {
@ -101,11 +103,11 @@ func TestRedirectStdLogger(t *testing.T) {
func TestStdLogger(t *testing.T) { func TestStdLogger(t *testing.T) {
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
l := NewLogger(WithLevel(TraceLevel), WithOutput(buf)) l := NewLogger(logger.WithLevel(logger.TraceLevel), logger.WithOutput(buf))
if err := l.Init(); err != nil { if err := l.Init(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
lg := NewStdLogger(l, ErrorLevel) lg := logger.NewStdLogger(l, logger.ErrorLevel)
lg.Print("test") lg.Print("test")
if !(bytes.Contains(buf.Bytes(), []byte(`"level":"error"`)) && bytes.Contains(buf.Bytes(), []byte(`"msg":"test"`))) { if !(bytes.Contains(buf.Bytes(), []byte(`"level":"error"`)) && bytes.Contains(buf.Bytes(), []byte(`"msg":"test"`))) {
t.Fatalf("logger error, buf %s", buf.Bytes()) t.Fatalf("logger error, buf %s", buf.Bytes())
@ -115,7 +117,7 @@ func TestStdLogger(t *testing.T) {
func TestLogger(t *testing.T) { func TestLogger(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
l := NewLogger(WithLevel(TraceLevel), WithOutput(buf)) l := NewLogger(logger.WithLevel(logger.TraceLevel), logger.WithOutput(buf))
if err := l.Init(); err != nil { if err := l.Init(); err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -1,4 +1,4 @@
package tracer package tracer_test
import ( import (
"bytes" "bytes"
@ -7,16 +7,20 @@ import (
"testing" "testing"
"go.unistack.org/micro/v4/logger" "go.unistack.org/micro/v4/logger"
"go.unistack.org/micro/v4/logger/slog"
"go.unistack.org/micro/v4/tracer"
) )
func TestLoggerWithTracer(t *testing.T) { func TestLoggerWithTracer(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
if err := logger.Init(logger.WithOutput(buf)); err != nil { logger.DefaultLogger = slog.NewLogger(logger.WithOutput(buf))
if err := logger.Init(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
var span Span var span tracer.Span
ctx, span = DefaultTracer.Start(ctx, "test") ctx, span = tracer.DefaultTracer.Start(ctx, "test")
logger.Info(ctx, "msg") logger.Info(ctx, "msg")
if !strings.Contains(buf.String(), span.TraceID()) { if !strings.Contains(buf.String(), span.TraceID()) {
t.Fatalf("log does not contains tracer id") t.Fatalf("log does not contains tracer id")