Compare commits

...

6 Commits

Author SHA1 Message Date
79438f11e0 logger: slog break import cycle
All checks were successful
/ autoupdate (push) Successful in 1m13s
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-10-17 01:48:50 +03:00
8d19abfebd small fixes
Some checks are pending
/ autoupdate (push) Has started running
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-10-17 01:11:35 +03:00
77f3731329 change dep
Some checks are pending
/ autoupdate (push) Waiting to run
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-10-17 01:10:52 +03:00
dbcf6bb74a logger: use key names from opts (#271)
All checks were successful
/ autoupdate (push) Successful in 1m14s
Reviewed-on: #271
2023-10-17 01:05:55 +03:00
17698440ed Merge pull request 'logger: improvements' (#270) from logtrace into master
All checks were successful
/ autoupdate (push) Successful in 1m13s
Reviewed-on: #270
2023-10-17 01:00:20 +03:00
eb8851ab58 logger: improvements
Some checks failed
lint / lint (pull_request) Successful in 1m8s
pr / test (pull_request) Failing after 1m5s
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-10-17 01:00:00 +03:00
8 changed files with 310 additions and 91 deletions

View File

@@ -17,7 +17,7 @@ func TestFSMStart(t *testing.T) {
wrapper := func(next StateFunc) StateFunc {
return func(sctx context.Context, s State, opts ...StateOption) (State, error) {
sctx = logger.NewContext(sctx, logger.Fields("state", s.Name()))
sctx = logger.NewContext(sctx, logger.Attrs("state", s.Name()))
return next(sctx, s, opts...)
}
}

View File

@@ -1,26 +1,25 @@
// Package logger provides a log interface
package logger // import "go.unistack.org/micro/v4/logger"
package logger
import (
"context"
"os"
"go.unistack.org/micro/v4/options"
)
var (
// DefaultLogger variable
DefaultLogger = NewLogger(WithLevel(ParseLevel(os.Getenv("MICRO_LOG_LEVEL"))))
// DefaultLevel used by logger
DefaultLevel = InfoLevel
// DefaultCallerSkipCount used by logger
DefaultCallerSkipCount = 2
)
type ContextAttrFunc func(ctx context.Context) []interface{}
var DefaultContextAttrFuncs []ContextAttrFunc
var (
// DefaultLogger variable
DefaultLogger = NewLogger()
// DefaultLevel used by logger
DefaultLevel = InfoLevel
// DefaultCallerSkipCount used by logger
DefaultCallerSkipCount = 2
)
// Logger is a generic logging interface
type Logger interface {
// Init initialises options

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

@@ -2,7 +2,9 @@ package logger
import (
"context"
"fmt"
"io"
"log/slog"
"os"
"reflect"
@@ -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
}
}

View File

@@ -1,4 +1,4 @@
package logger
package slog
import (
"context"
@@ -8,7 +8,9 @@ import (
"strconv"
"time"
"go.unistack.org/micro/v4/logger"
"go.unistack.org/micro/v4/options"
"go.unistack.org/micro/v4/tracer"
)
var (
@@ -20,29 +22,32 @@ var (
fatalValue = slog.StringValue("fatal")
)
var renameAttr = func(_ []string, a slog.Attr) slog.Attr {
func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
switch a.Key {
case slog.SourceKey:
source := a.Value.Any().(*slog.Source)
a.Value = slog.StringValue(source.File + ":" + strconv.Itoa(source.Line))
a.Key = "caller"
a.Key = s.opts.SourceKey
case slog.TimeKey:
a.Key = "timestamp"
a.Key = s.opts.TimeKey
case slog.MessageKey:
a.Key = s.opts.MessageKey
case slog.LevelKey:
level := a.Value.Any().(slog.Level)
lvl := slogToLoggerLevel(level)
a.Key = s.opts.LevelKey
switch {
case lvl < DebugLevel:
case lvl < logger.DebugLevel:
a.Value = traceValue
case lvl < InfoLevel:
case lvl < logger.InfoLevel:
a.Value = debugValue
case lvl < WarnLevel:
case lvl < logger.WarnLevel:
a.Value = infoValue
case lvl < ErrorLevel:
case lvl < logger.ErrorLevel:
a.Value = warnValue
case lvl < FatalLevel:
case lvl < logger.FatalLevel:
a.Value = errorValue
case lvl >= FatalLevel:
case lvl >= logger.FatalLevel:
a.Value = fatalValue
default:
a.Value = infoValue
@@ -55,10 +60,10 @@ var renameAttr = func(_ []string, a slog.Attr) slog.Attr {
type slogLogger struct {
slog *slog.Logger
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
for _, o := range opts {
@@ -69,14 +74,16 @@ func (s *slogLogger) Clone(opts ...options.Option) Logger {
opts: options,
}
/*
if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok {
l.slog = slog
return nil
}
*/
l.leveler = new(slog.LevelVar)
handleOpt := &slog.HandlerOptions{
ReplaceAttr: renameAttr,
ReplaceAttr: s.renameAttr,
Level: l.leveler,
AddSource: true,
}
@@ -87,25 +94,25 @@ func (s *slogLogger) Clone(opts ...options.Option) Logger {
return l
}
func (s *slogLogger) V(level Level) bool {
func (s *slogLogger) V(level logger.Level) bool {
return s.opts.Level.Enabled(level)
}
func (s *slogLogger) Level(level Level) {
func (s *slogLogger) Level(level logger.Level) {
s.leveler.Set(loggerToSlogLevel(level))
}
func (s *slogLogger) Options() Options {
func (s *slogLogger) Options() logger.Options {
return s.opts
}
func (s *slogLogger) Attrs(attrs ...interface{}) Logger {
func (s *slogLogger) Attrs(attrs ...interface{}) logger.Logger {
nl := &slogLogger{opts: s.opts}
nl.leveler = new(slog.LevelVar)
nl.leveler.Set(s.leveler.Level())
handleOpt := &slog.HandlerOptions{
ReplaceAttr: renameAttr,
ReplaceAttr: nl.renameAttr,
Level: s.leveler,
AddSource: true,
}
@@ -117,20 +124,25 @@ func (s *slogLogger) Attrs(attrs ...interface{}) Logger {
}
func (s *slogLogger) Init(opts ...options.Option) error {
if len(s.opts.ContextAttrFuncs) == 0 {
s.opts.ContextAttrFuncs = logger.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
}
*/
s.leveler = new(slog.LevelVar)
handleOpt := &slog.HandlerOptions{
ReplaceAttr: renameAttr,
ReplaceAttr: s.renameAttr,
Level: s.leveler,
AddSource: true,
}
@@ -141,7 +153,7 @@ func (s *slogLogger) Init(opts ...options.Option) error {
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) {
return
}
@@ -149,77 +161,86 @@ 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)
}
func (s *slogLogger) Info(ctx context.Context, msg string, attrs ...interface{}) {
if !s.V(InfoLevel) {
if !s.V(logger.InfoLevel) {
return
}
var pcs [1]uintptr
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)
}
func (s *slogLogger) Debug(ctx context.Context, msg string, attrs ...interface{}) {
if !s.V(InfoLevel) {
if !s.V(logger.DebugLevel) {
return
}
var pcs [1]uintptr
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)
}
func (s *slogLogger) Trace(ctx context.Context, msg string, attrs ...interface{}) {
if !s.V(InfoLevel) {
if !s.V(logger.TraceLevel) {
return
}
var pcs [1]uintptr
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)
}
func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{}) {
if !s.V(InfoLevel) {
if !s.V(logger.ErrorLevel) {
return
}
var pcs [1]uintptr
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...)
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)
}
func (s *slogLogger) Fatal(ctx context.Context, msg string, attrs ...interface{}) {
if !s.V(InfoLevel) {
if !s.V(logger.FatalLevel) {
return
}
var pcs [1]uintptr
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)
@@ -227,14 +248,14 @@ func (s *slogLogger) Fatal(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
}
var pcs [1]uintptr
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)
@@ -244,43 +265,43 @@ func (s *slogLogger) String() string {
return "slog"
}
func NewLogger(opts ...options.Option) Logger {
func NewLogger(opts ...options.Option) logger.Logger {
l := &slogLogger{
opts: NewOptions(opts...),
opts: logger.NewOptions(opts...),
}
return l
}
func loggerToSlogLevel(level Level) slog.Level {
func loggerToSlogLevel(level logger.Level) slog.Level {
switch level {
case DebugLevel:
case logger.DebugLevel:
return slog.LevelDebug
case WarnLevel:
case logger.WarnLevel:
return slog.LevelWarn
case ErrorLevel:
case logger.ErrorLevel:
return slog.LevelError
case TraceLevel:
case logger.TraceLevel:
return slog.LevelDebug - 1
case FatalLevel:
case logger.FatalLevel:
return slog.LevelError + 1
default:
return slog.LevelInfo
}
}
func slogToLoggerLevel(level slog.Level) Level {
func slogToLoggerLevel(level slog.Level) logger.Level {
switch level {
case slog.LevelDebug:
return DebugLevel
return logger.DebugLevel
case slog.LevelWarn:
return WarnLevel
return logger.WarnLevel
case slog.LevelError:
return ErrorLevel
return logger.ErrorLevel
case slog.LevelDebug - 1:
return TraceLevel
return logger.TraceLevel
case slog.LevelError + 1:
return FatalLevel
return logger.FatalLevel
default:
return InfoLevel
return logger.InfoLevel
}
}

View File

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

View File

@@ -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) {

28
tracer/tracer_test.go Normal file
View File

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