github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/conf/logger/span_logger.go (about) 1 package logger 2 3 import ( 4 "context" 5 "fmt" 6 "log/slog" 7 "time" 8 9 "go.opentelemetry.io/otel" 10 "go.opentelemetry.io/otel/attribute" 11 "go.opentelemetry.io/otel/codes" 12 "go.opentelemetry.io/otel/trace" 13 14 "github.com/machinefi/w3bstream/pkg/depends/kit/logr" 15 "github.com/machinefi/w3bstream/pkg/depends/kit/metax" 16 ) 17 18 func SpanLogger(span trace.Span) logr.Logger { 19 return &spanLogger{span: span} 20 } 21 22 func NewSpanContext(ctx context.Context, name string) (context.Context, logr.Logger) { 23 ctx = trace.ContextWithSpan(ctx, nil) 24 ctx, span := otel.Tracer(name).Start(ctx, name, trace.WithTimestamp(time.Now())) 25 l := SpanLogger(span) 26 return logr.WithLogger(ctx, l), l 27 } 28 29 type spanLogger struct { 30 span trace.Span 31 attr []attribute.KeyValue 32 } 33 34 var _ logr.Logger = (*spanLogger)(nil) 35 36 func (l *spanLogger) Start(ctx context.Context, name string, kvs ...any) (context.Context, logr.Logger) { 37 span := trace.SpanFromContext(ctx) 38 meta := metax.GetMetaFrom(ctx) 39 40 if len(meta) > 0 { 41 kvs = append(kvs, "meta", meta) 42 } 43 44 tp := span.TracerProvider() 45 ctx, span = tp.Tracer(name).Start(ctx, name, 46 trace.WithAttributes(KVsToAttr(kvs...)...), 47 trace.WithTimestamp(time.Now()), 48 ) 49 return ctx, &spanLogger{span: span} 50 } 51 52 func (l *spanLogger) End() { 53 l.span.End(trace.WithTimestamp(time.Now())) 54 } 55 56 func (l *spanLogger) WithValues(kvs ...any) logr.Logger { 57 return &spanLogger{ 58 span: l.span, 59 attr: append(l.attr, KVsToAttr(kvs...)...), 60 } 61 } 62 63 func (l *spanLogger) Debug(format string, args ...any) { 64 l.info(slog.LevelDebug, format, args...) 65 } 66 67 func (l *spanLogger) Info(format string, args ...any) { 68 l.info(slog.LevelInfo, format, args...) 69 } 70 71 func (l *spanLogger) Warn(err error) { 72 l.error(slog.LevelWarn, err) 73 } 74 75 func (l *spanLogger) Error(err error) { 76 l.error(slog.LevelError, err) 77 } 78 79 func (l *spanLogger) info(lv slog.Level, format string, args ...any) { 80 msg := "" 81 if len(args) == 0 { 82 msg = format 83 } 84 msg = fmt.Sprintf(format, args...) 85 86 options := []trace.EventOption{ 87 trace.WithTimestamp(time.Now()), 88 trace.WithAttributes(attribute.String("@msg", msg)), 89 } 90 if len(l.attr) > 0 { 91 options = append(options, trace.WithAttributes(l.attr...)) 92 } 93 94 l.span.AddEvent("@"+lv.String(), options...) 95 } 96 97 func (l *spanLogger) error(lv slog.Level, err error) { 98 if l.span == nil || err == nil || !l.span.IsRecording() { 99 return 100 } 101 102 kvs := append(l.attr, 103 attribute.String("@msg", err.Error()), 104 attribute.String("@stack", fmt.Sprintf("%+v", err)), 105 ) 106 107 l.span.SetStatus(codes.Error, err.Error()) 108 l.span.AddEvent( 109 "@"+lv.String(), 110 trace.WithTimestamp(time.Now()), 111 trace.WithAttributes(kvs...), 112 ) 113 }