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 }