github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/conf/log/logger_span.go (about) 1 package log 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "go.opentelemetry.io/otel" 9 "go.opentelemetry.io/otel/attribute" 10 "go.opentelemetry.io/otel/codes" 11 "go.opentelemetry.io/otel/trace" 12 13 "github.com/machinefi/w3bstream/pkg/depends/kit/metax" 14 "github.com/machinefi/w3bstream/pkg/depends/x/ptrx" 15 "github.com/machinefi/w3bstream/pkg/depends/x/textx" 16 ) 17 18 func Span(tracer string, s trace.Span) Logger { 19 return &span{lvl: DebugLevel, tracer: tracer, span: s} 20 } 21 22 func SpanContext(ctx context.Context, tracer string) (context.Context, Logger) { 23 ctx, sp := otel.Tracer(tracer).Start(ctx, tracer, trace.WithTimestamp(time.Now())) 24 l := Span(tracer, sp) 25 return WithLogger(ctx, l), l 26 } 27 28 type span struct { 29 lvl Level 30 tracer string 31 span trace.Span 32 attrs []attribute.KeyValue 33 } 34 35 func (l *span) SetLevel(lvl Level) Logger { 36 logger := ptrx.Ptr(*l) 37 logger.lvl = lvl 38 return logger 39 } 40 41 func (l *span) Start(ctx context.Context, name string, kvs ...interface{}) (context.Context, Logger) { 42 sp := trace.SpanFromContext(ctx) 43 meta := metax.GetMetaFrom(ctx) 44 45 if len(meta) > 0 { 46 kvs = append(kvs, "meta", meta) 47 } 48 ctx, sp = sp.TracerProvider().Tracer(l.tracer).Start( 49 ctx, name, 50 trace.WithAttributes(toAttributes(kvs...)...), 51 trace.WithTimestamp(time.Now()), 52 ) 53 return ctx, &span{span: sp, tracer: l.tracer, lvl: l.lvl} 54 } 55 56 func (l *span) End() { l.span.End(trace.WithTimestamp(time.Now())) } 57 58 func (l *span) WithValues(kvs ...interface{}) Logger { 59 return &span{ 60 tracer: l.tracer, 61 span: l.span, 62 attrs: append(l.attrs, toAttributes(kvs...)...), 63 lvl: l.lvl, 64 } 65 } 66 67 func (l *span) Trace(format string, args ...interface{}) { 68 l.info(TraceLevel, &printer{format, args}) 69 } 70 71 func (l *span) Debug(format string, args ...interface{}) { 72 l.info(DebugLevel, &printer{format, args}) 73 } 74 75 func (l *span) Info(format string, args ...interface{}) { 76 l.info(InfoLevel, &printer{format, args}) 77 } 78 79 func (l *span) Warn(err error) { l.error(WarnLevel, err) } 80 81 func (l *span) Error(err error) { l.error(ErrorLevel, err) } 82 83 func (l *span) Fatal(err error) { l.error(FatalLevel, err) } 84 85 func (l *span) Panic(err error) { l.error(PanicLevel, err); panic(err) } 86 87 func (l *span) info(lvl Level, msg *printer) { 88 if lvl > l.lvl { 89 return 90 } 91 92 l.span.AddEvent( 93 "@"+lvl.String(), 94 trace.WithTimestamp(time.Now()), 95 trace.WithAttributes(l.attrs...), 96 trace.WithAttributes(attribute.Stringer("message", msg)), 97 ) 98 } 99 func (l *span) error(lvl Level, err error) { 100 if lvl > l.lvl { 101 return 102 } 103 104 if l.span == nil || err == nil || !l.span.IsRecording() { 105 return 106 } 107 108 attrs := append(l.attrs, attribute.String("message", err.Error())) 109 110 if lvl <= ErrorLevel { 111 attrs = append(attrs, attribute.String("stack", fmt.Sprintf("%+v", err))) 112 } 113 114 l.span.SetStatus(codes.Error, "") 115 l.span.AddEvent( 116 "@"+lvl.String(), 117 trace.WithTimestamp(time.Now()), 118 trace.WithAttributes(attrs...), 119 ) 120 } 121 122 func toAttributes(kvs ...interface{}) []attribute.KeyValue { 123 n := len(kvs) 124 if n > 0 && n%2 == 0 { 125 attrs := make([]attribute.KeyValue, n/2) 126 for i := range attrs { 127 k, v := kvs[2*i], kvs[2*i+1] 128 129 ks, ok := k.(string) 130 if !ok { 131 continue 132 } 133 vs, err := textx.MarshalText(v) 134 if err != nil { 135 continue 136 } 137 attrs[i] = attribute.String(ks, string(vs)) 138 } 139 return attrs 140 } 141 return nil 142 143 } 144 145 type printer struct { 146 format string 147 args []interface{} 148 } 149 150 func (p *printer) String() string { return fmt.Sprintf(p.format, p.args...) }