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...) }