github.com/koko1123/flow-go-1@v0.29.6/module/trace/log_tracer.go (about)

     1  package trace
     2  
     3  import (
     4  	"context"
     5  	"math/rand"
     6  	"time"
     7  
     8  	"github.com/rs/zerolog"
     9  	"go.opentelemetry.io/otel/attribute"
    10  	"go.opentelemetry.io/otel/codes"
    11  	"go.opentelemetry.io/otel/trace"
    12  
    13  	"github.com/koko1123/flow-go-1/model/flow"
    14  )
    15  
    16  type spanKey string
    17  
    18  const activeSpan spanKey = "activeSpan"
    19  
    20  // LogTracer is the implementation of the Tracer interface which passes
    21  // all the traces back to the passed logger and print them
    22  // this is mostly useful for debugging and testing
    23  // TODO(rbtz): make private
    24  type LogTracer struct {
    25  	log      zerolog.Logger
    26  	provider trace.TracerProvider
    27  }
    28  
    29  // NewLogTracer creates a new zerolog-based tracer.
    30  // TODO: Consider switching to go.opentelemetry.io/otel/exporters/stdout/stdouttrace
    31  func NewLogTracer(log zerolog.Logger) *LogTracer {
    32  	t := &LogTracer{
    33  		log: log,
    34  	}
    35  	t.provider = &logTracerProvider{tracer: t}
    36  	return t
    37  }
    38  
    39  func (t *LogTracer) Ready() <-chan struct{} {
    40  	ready := make(chan struct{})
    41  	close(ready)
    42  	return ready
    43  }
    44  
    45  func (t *LogTracer) Done() <-chan struct{} {
    46  	done := make(chan struct{})
    47  	close(done)
    48  	return done
    49  }
    50  
    51  // Start implements trace.Tracer interface.
    52  func (t *LogTracer) Start(
    53  	ctx context.Context,
    54  	spanName string,
    55  	_ ...trace.SpanStartOption,
    56  ) (
    57  	context.Context,
    58  	trace.Span,
    59  ) {
    60  	sp := newLogSpan(t, spanName)
    61  	ctx = context.WithValue(ctx, activeSpan, sp.spanID)
    62  	return ctx, sp
    63  }
    64  
    65  func (t *LogTracer) StartBlockSpan(
    66  	ctx context.Context,
    67  	blockID flow.Identifier,
    68  	spanName SpanName,
    69  	opts ...trace.SpanStartOption,
    70  ) (
    71  	trace.Span,
    72  	context.Context,
    73  ) {
    74  	ctx, sp := t.Start(ctx, string(spanName), opts...)
    75  	return sp, ctx
    76  }
    77  
    78  func (t *LogTracer) StartCollectionSpan(
    79  	ctx context.Context,
    80  	collectionID flow.Identifier,
    81  	spanName SpanName,
    82  	opts ...trace.SpanStartOption,
    83  ) (
    84  	trace.Span,
    85  	context.Context,
    86  ) {
    87  	ctx, sp := t.Start(ctx, string(spanName), opts...)
    88  	return sp, ctx
    89  }
    90  
    91  // StartTransactionSpan starts a span that will be aggregated under the given transaction.
    92  // All spans for the same transaction will be aggregated under a root span
    93  func (t *LogTracer) StartTransactionSpan(
    94  	ctx context.Context,
    95  	transactionID flow.Identifier,
    96  	spanName SpanName,
    97  	opts ...trace.SpanStartOption,
    98  ) (
    99  	trace.Span,
   100  	context.Context,
   101  ) {
   102  	ctx, sp := t.Start(ctx, string(spanName), opts...)
   103  	return sp, ctx
   104  }
   105  
   106  func (t *LogTracer) StartSpanFromContext(
   107  	ctx context.Context,
   108  	operationName SpanName,
   109  	opts ...trace.SpanStartOption,
   110  ) (
   111  	trace.Span,
   112  	context.Context,
   113  ) {
   114  	parentSpanID := ctx.Value(activeSpan).(uint64)
   115  	sp := newLogSpanWithParent(t, operationName, parentSpanID)
   116  	ctx = context.WithValue(ctx, activeSpan, sp.spanID)
   117  	return sp, trace.ContextWithSpan(ctx, sp)
   118  }
   119  
   120  func (t *LogTracer) StartSpanFromParent(
   121  	span trace.Span,
   122  	operationName SpanName,
   123  	opts ...trace.SpanStartOption,
   124  ) trace.Span {
   125  	parentSpan := span.(*logSpan)
   126  	return newLogSpanWithParent(t, operationName, parentSpan.spanID)
   127  }
   128  
   129  // WithSpanFromContext encapsulates executing a function within an span, i.e., it starts a span with the specified SpanName from the context,
   130  // executes the function f, and finishes the span once the function returns.
   131  func (t *LogTracer) WithSpanFromContext(
   132  	ctx context.Context,
   133  	operationName SpanName,
   134  	f func(),
   135  	opts ...trace.SpanStartOption,
   136  ) {
   137  	span, _ := t.StartSpanFromContext(ctx, operationName, opts...)
   138  	defer span.End()
   139  
   140  	f()
   141  }
   142  
   143  var _ trace.Span = &logSpan{}
   144  
   145  type logSpan struct {
   146  	tracer *LogTracer
   147  
   148  	spanID        uint64
   149  	parentID      uint64
   150  	operationName string
   151  	start         time.Time
   152  	end           time.Time
   153  	attrs         map[attribute.Key]attribute.Value
   154  }
   155  
   156  func newLogSpan(tracer *LogTracer, operationName string) *logSpan {
   157  	return &logSpan{
   158  		tracer:        tracer,
   159  		spanID:        rand.Uint64(),
   160  		operationName: operationName,
   161  		start:         time.Now(),
   162  		attrs:         make(map[attribute.Key]attribute.Value),
   163  	}
   164  }
   165  
   166  func newLogSpanWithParent(
   167  	tracer *LogTracer,
   168  	operationName SpanName,
   169  	parentSpanID uint64,
   170  ) *logSpan {
   171  	sp := newLogSpan(tracer, string(operationName))
   172  	sp.parentID = parentSpanID
   173  	return sp
   174  }
   175  
   176  func (s *logSpan) produceLog() {
   177  	s.tracer.log.Info().
   178  		Uint64("spanID", s.spanID).
   179  		Uint64("parent", s.parentID).
   180  		Time("start", s.start).
   181  		Time("end", s.end).
   182  		TimeDiff("duration", s.end, s.start).
   183  		Str("operationName", string(s.operationName)).
   184  		Interface("attrs", s.attrs).
   185  		Msg("span")
   186  }
   187  
   188  func (s *logSpan) End(...trace.SpanEndOption) {
   189  	s.end = time.Now()
   190  	s.produceLog()
   191  }
   192  
   193  func (s *logSpan) SpanContext() trace.SpanContext {
   194  	return trace.SpanContext{}
   195  }
   196  
   197  func (s *logSpan) IsRecording() bool {
   198  	return s.end == time.Time{}
   199  }
   200  
   201  func (s *logSpan) SetStatus(codes.Code, string) {}
   202  
   203  func (s *logSpan) SetError(bool) {}
   204  
   205  func (s *logSpan) SetAttributes(attrs ...attribute.KeyValue) {
   206  	for _, f := range attrs {
   207  		s.attrs[f.Key] = f.Value
   208  	}
   209  }
   210  
   211  func (s *logSpan) RecordError(error, ...trace.EventOption) {}
   212  
   213  func (s *logSpan) AddEvent(string, ...trace.EventOption) {}
   214  
   215  func (s *logSpan) SetName(string) {}
   216  
   217  func (s *logSpan) TracerProvider() trace.TracerProvider {
   218  	return s.tracer.provider
   219  }
   220  
   221  type logTracerProvider struct {
   222  	tracer *LogTracer
   223  }
   224  
   225  func (ltp *logTracerProvider) Tracer(
   226  	instrumentationName string,
   227  	_ ...trace.TracerOption,
   228  ) trace.Tracer {
   229  	return ltp.tracer
   230  }