From eb8851ab585f1654512faa3fb5dab061e8c48340 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Tue, 17 Oct 2023 01:00:00 +0300 Subject: [PATCH] logger: improvements Signed-off-by: Vasiliy Tolstov --- logger/logger.go | 15 ++++--- logger/options.go | 96 +++++++++++++++++++++++++++++++++++++++++-- logger/slog.go | 18 ++++---- tracer/noop.go | 20 ++++++--- tracer/tracer_test.go | 24 +++++++++++ 5 files changed, 150 insertions(+), 23 deletions(-) create mode 100644 tracer/tracer_test.go diff --git a/logger/logger.go b/logger/logger.go index 3ef835a5..0b8675ab 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -1,5 +1,5 @@ // Package logger provides a log interface -package logger // import "go.unistack.org/micro/v4/logger" +package logger import ( "context" @@ -8,19 +8,22 @@ import ( "go.unistack.org/micro/v4/options" ) +type ContextAttrFunc func(ctx context.Context) []interface{} + +var DefaultContextAttrFuncs []ContextAttrFunc + var ( // DefaultLogger variable - DefaultLogger = NewLogger(WithLevel(ParseLevel(os.Getenv("MICRO_LOG_LEVEL")))) + DefaultLogger = NewLogger( + WithLevel(ParseLevel(os.Getenv("MICRO_LOG_LEVEL"))), + WithContextAttrFuncs(DefaultContextAttrFuncs...), + ) // DefaultLevel used by logger DefaultLevel = InfoLevel // DefaultCallerSkipCount used by logger DefaultCallerSkipCount = 2 ) -type ContextAttrFunc func(ctx context.Context) []interface{} - -var DefaultContextAttrFuncs []ContextAttrFunc - // Logger is a generic logging interface type Logger interface { // Init initialises options diff --git a/logger/options.go b/logger/options.go index f9a8dbcd..9d19756e 100644 --- a/logger/options.go +++ b/logger/options.go @@ -2,12 +2,14 @@ package logger import ( "context" + "fmt" "io" "os" "reflect" "go.unistack.org/micro/v4/options" rutil "go.unistack.org/micro/v4/util/reflect" + "golang.org/x/exp/slog" ) // Options holds logger options @@ -26,6 +28,14 @@ type Options struct { CallerSkipCount int // ContextAttrFuncs contains funcs that executed before log func on context ContextAttrFuncs []ContextAttrFunc + // TimeKey is the key used for the time of the log call + TimeKey string + // LevelKey is the key used for the level of the log call + LevelKey string + // MessageKey is the key used for the message of the log call + MessageKey string + // SourceKey is the key used for the source file and line of the log call + SourceKey string } // NewOptions creates new options struct @@ -38,6 +48,9 @@ func NewOptions(opts ...options.Option) Options { Context: context.Background(), ContextAttrFuncs: DefaultContextAttrFuncs, } + + WithMicroKeys()(&options) + for _, o := range opts { o(&options) } @@ -45,18 +58,19 @@ func NewOptions(opts ...options.Option) Options { } // WithContextAttrFuncs appends default funcs for the context arrts filler -func WithContextAttrFuncs(attrs ...interface{}) options.Option { +func WithContextAttrFuncs(fncs ...ContextAttrFunc) options.Option { return func(src interface{}) error { v, err := options.Get(src, ".ContextAttrFuncs") if err != nil { return err } else if rutil.IsZero(v) { - v = reflect.MakeSlice(reflect.TypeOf(v), 0, len(attrs)).Interface() + v = reflect.MakeSlice(reflect.TypeOf(v), 0, len(fncs)).Interface() } cv := reflect.ValueOf(v) - for _, l := range attrs { + for _, l := range fncs { cv = reflect.Append(cv, reflect.ValueOf(l)) } + fmt.Printf("EEEE %#+v\n", cv.Interface()) return options.Set(src, cv.Interface(), ".ContextAttrFuncs") } } @@ -88,3 +102,79 @@ func WithCallerSkipCount(c int) options.Option { return options.Set(src, c, ".CallerSkipCount") } } + +func WithZapKeys() options.Option { + return func(src interface{}) error { + var err error + if err = options.Set(src, "@timestamp", ".TimeKey"); err != nil { + return err + } + if err = options.Set(src, "level", ".LevelKey"); err != nil { + return err + } + if err = options.Set(src, "msg", ".MessageKey"); err != nil { + return err + } + if err = options.Set(src, "caller", ".SourceKey"); err != nil { + return err + } + return nil + } +} + +func WithZerologKeys() options.Option { + return func(src interface{}) error { + var err error + if err = options.Set(src, "time", ".TimeKey"); err != nil { + return err + } + if err = options.Set(src, "level", ".LevelKey"); err != nil { + return err + } + if err = options.Set(src, "message", ".MessageKey"); err != nil { + return err + } + if err = options.Set(src, "caller", ".SourceKey"); err != nil { + return err + } + return nil + } +} + +func WithSlogKeys() options.Option { + return func(src interface{}) error { + var err error + if err = options.Set(src, slog.TimeKey, ".TimeKey"); err != nil { + return err + } + if err = options.Set(src, slog.LevelKey, ".LevelKey"); err != nil { + return err + } + if err = options.Set(src, slog.MessageKey, ".MessageKey"); err != nil { + return err + } + if err = options.Set(src, slog.SourceKey, ".SourceKey"); err != nil { + return err + } + return nil + } +} + +func WithMicroKeys() options.Option { + return func(src interface{}) error { + var err error + if err = options.Set(src, "timestamp", ".TimeKey"); err != nil { + return err + } + if err = options.Set(src, "level", ".LevelKey"); err != nil { + return err + } + if err = options.Set(src, "msg", ".MessageKey"); err != nil { + return err + } + if err = options.Set(src, "caller", ".SourceKey"); err != nil { + return err + } + return nil + } +} diff --git a/logger/slog.go b/logger/slog.go index fd1d2f80..8174a9e5 100644 --- a/logger/slog.go +++ b/logger/slog.go @@ -117,12 +117,14 @@ func (s *slogLogger) Attrs(attrs ...interface{}) Logger { } func (s *slogLogger) Init(opts ...options.Option) error { + if len(s.opts.ContextAttrFuncs) == 0 { + s.opts.ContextAttrFuncs = DefaultContextAttrFuncs + } for _, o := range opts { if err := o(&s.opts); err != nil { return err } } - if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok { s.slog = slog return nil @@ -149,7 +151,7 @@ func (s *slogLogger) Log(ctx context.Context, lvl Level, msg string, attrs ...in runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(time.Now(), loggerToSlogLevel(lvl), msg, pcs[0]) for _, fn := range s.opts.ContextAttrFuncs { - attrs = append(attrs, fn(ctx)) + attrs = append(attrs, fn(ctx)...) } r.Add(attrs...) _ = s.slog.Handler().Handle(ctx, r) @@ -163,7 +165,7 @@ func (s *slogLogger) Info(ctx context.Context, msg string, attrs ...interface{}) runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(time.Now(), slog.LevelInfo, msg, pcs[0]) for _, fn := range s.opts.ContextAttrFuncs { - attrs = append(attrs, fn(ctx)) + attrs = append(attrs, fn(ctx)...) } r.Add(attrs...) _ = s.slog.Handler().Handle(ctx, r) @@ -177,7 +179,7 @@ func (s *slogLogger) Debug(ctx context.Context, msg string, attrs ...interface{} runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(time.Now(), slog.LevelDebug, msg, pcs[0]) for _, fn := range s.opts.ContextAttrFuncs { - attrs = append(attrs, fn(ctx)) + attrs = append(attrs, fn(ctx)...) } r.Add(attrs...) _ = s.slog.Handler().Handle(ctx, r) @@ -191,7 +193,7 @@ func (s *slogLogger) Trace(ctx context.Context, msg string, attrs ...interface{} runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(time.Now(), slog.LevelDebug-1, msg, pcs[0]) for _, fn := range s.opts.ContextAttrFuncs { - attrs = append(attrs, fn(ctx)) + attrs = append(attrs, fn(ctx)...) } r.Add(attrs...) _ = s.slog.Handler().Handle(ctx, r) @@ -205,7 +207,7 @@ func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{} runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(time.Now(), slog.LevelError, msg, pcs[0]) for _, fn := range s.opts.ContextAttrFuncs { - attrs = append(attrs, fn(ctx)) + attrs = append(attrs, fn(ctx)...) } r.Add(attrs...) _ = s.slog.Handler().Handle(ctx, r) @@ -219,7 +221,7 @@ func (s *slogLogger) Fatal(ctx context.Context, msg string, attrs ...interface{} runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(time.Now(), slog.LevelError+1, msg, pcs[0]) for _, fn := range s.opts.ContextAttrFuncs { - attrs = append(attrs, fn(ctx)) + attrs = append(attrs, fn(ctx)...) } r.Add(attrs...) _ = s.slog.Handler().Handle(ctx, r) @@ -234,7 +236,7 @@ func (s *slogLogger) Warn(ctx context.Context, msg string, attrs ...interface{}) runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof] r := slog.NewRecord(time.Now(), slog.LevelWarn, msg, pcs[0]) for _, fn := range s.opts.ContextAttrFuncs { - attrs = append(attrs, fn(ctx)) + attrs = append(attrs, fn(ctx)...) } r.Add(attrs...) _ = s.slog.Handler().Handle(ctx, r) diff --git a/tracer/noop.go b/tracer/noop.go index 3e293ce6..c2b91c66 100644 --- a/tracer/noop.go +++ b/tracer/noop.go @@ -27,8 +27,8 @@ func (t *noopTracer) Start(ctx context.Context, name string, opts ...options.Opt labels: options.Labels, kind: options.Kind, } - span.spanID, _ = id.New() - span.traceID, _ = id.New() + span.spanID.s, _ = id.New() + span.traceID.s, _ = id.New() if span.ctx == nil { span.ctx = context.Background() } @@ -56,18 +56,26 @@ type noopEvent struct { labels []interface{} } +type noopStringer struct { + s string +} + +func (s noopStringer) String() string { + return s.s +} + type noopSpan struct { ctx context.Context tracer Tracer name string statusMsg string + traceID noopStringer + spanID noopStringer events []*noopEvent labels []interface{} logs []interface{} kind SpanKind status SpanStatus - traceID string - spanID string } func (s *noopSpan) Finish(opts ...options.Option) { @@ -103,11 +111,11 @@ func (s *noopSpan) Kind() SpanKind { } func (s *noopSpan) TraceID() string { - return s.traceID + return s.traceID.String() } func (s *noopSpan) SpanID() string { - return s.spanID + return s.spanID.String() } func (s *noopSpan) Status() (SpanStatus, string) { diff --git a/tracer/tracer_test.go b/tracer/tracer_test.go new file mode 100644 index 00000000..808df112 --- /dev/null +++ b/tracer/tracer_test.go @@ -0,0 +1,24 @@ +package tracer + +import ( + "bytes" + "context" + "strings" + "testing" + + "go.unistack.org/micro/v4/logger" +) + +func TestLoggerWithTracer(t *testing.T) { + ctx := context.TODO() + buf := bytes.NewBuffer(nil) + if err := logger.Init(logger.WithOutput(buf)); err != nil { + t.Fatal(err) + } + var span Span + ctx, span = DefaultTracer.Start(ctx, "test") + logger.Info(ctx, "msg") + if !strings.Contains(buf.String(), span.TraceID()) { + t.Fatalf("log does not contains tracer id") + } +}