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  }