fork of https://github.com/sourcegraph/zoekt
0

Configure Feed

Select the types of activity you want to include in your feed.

1// Package trace provides a tracing API that in turn invokes both the `golang.org/x/net/trace` API 2// and creates an opentracing span if appropriate. 3// 4// This is similar to the github.com/sourcegraph/sourcegraph/internal/trace package in the main repo, 5// and it may make sense to factor both out into a common package at some point. 6package trace 7 8import ( 9 "context" 10 "fmt" 11 "strconv" 12 "strings" 13 14 "github.com/opentracing/opentracing-go" 15 "github.com/opentracing/opentracing-go/ext" 16 "github.com/opentracing/opentracing-go/log" 17 nettrace "golang.org/x/net/trace" 18) 19 20// A Tracer for trace creation, parameterised over an 21// opentracing.Tracer. Use this if you don't want to use 22// the global tracer. 23type Tracer struct { 24 Tracer opentracing.Tracer 25} 26 27func New(ctx context.Context, family, title string) (*Trace, context.Context) { 28 tr := Tracer{Tracer: GetOpenTracer(ctx, nil)} 29 return tr.New(ctx, family, title) 30} 31 32// New returns a new Trace with the specified family and title. 33func (t Tracer) New(ctx context.Context, family, title string) (*Trace, context.Context) { 34 span, ctx := StartSpanFromContextWithTracer( 35 ctx, 36 t.Tracer, 37 family, 38 opentracing.Tag{Key: "title", Value: title}, 39 ) 40 tr := nettrace.New(family, title) 41 trace := &Trace{span: span, trace: tr, family: family} 42 if parent := TraceFromContext(ctx); parent != nil { 43 tr.LazyPrintf("parent: %s", parent.family) 44 trace.family = parent.family + " > " + family 45 } 46 return trace, ContextWithTrace(ctx, trace) 47} 48 49// Trace is a combined version of golang.org/x/net/trace.Trace and 50// opentracing.Span. Use New to construct one. 51type Trace struct { 52 trace nettrace.Trace 53 span opentracing.Span 54 family string 55} 56 57// LazyPrintf evaluates its arguments with fmt.Sprintf each time the 58// /debug/requests page is rendered. Any memory referenced by a will be 59// pinned until the trace is finished and later discarded. 60func (t *Trace) LazyPrintf(format string, a ...any) { 61 t.span.LogFields(Printf("log", format, a...)) 62 t.trace.LazyPrintf(format, a...) 63} 64 65func (t *Trace) LazyLog(x fmt.Stringer, sensitive bool) { 66 t.trace.LazyLog(x, sensitive) 67} 68 69// LogFields logs fields to the opentracing.Span 70// as well as the nettrace.Trace. 71func (t *Trace) LogFields(fields ...log.Field) { 72 t.span.LogFields(fields...) 73 t.trace.LazyLog(fieldsStringer(fields), false) 74} 75 76// SetError declares that this trace and span resulted in an error. 77func (t *Trace) SetError(err error) { 78 if err == nil { 79 return 80 } 81 t.trace.LazyPrintf("error: %v", err) 82 t.trace.SetError() 83 t.span.LogFields(log.Error(err)) 84 ext.Error.Set(t.span, true) 85} 86 87// Finish declares that this trace and span is complete. 88// The trace should not be used after calling this method. 89func (t *Trace) Finish() { 90 t.trace.Finish() 91 t.span.Finish() 92} 93 94// Printf is an opentracing log.Field which is a LazyLogger. So the format 95// string will only be evaluated if the trace is collected. In the case of 96// net/trace, it will only be evaluated on page load. 97func Printf(key, f string, args ...any) log.Field { 98 return log.Lazy(func(fv log.Encoder) { 99 fv.EmitString(key, fmt.Sprintf(f, args...)) 100 }) 101} 102 103type traceContextKey string 104 105const traceKey = traceContextKey("trace") 106 107// ContextWithTrace returns a new context.Context that holds a reference to 108// trace's SpanContext. 109func ContextWithTrace(ctx context.Context, tr *Trace) context.Context { 110 ctx = opentracing.ContextWithSpan(ctx, tr.span) 111 ctx = context.WithValue(ctx, traceKey, tr) 112 return ctx 113} 114 115// TraceFromContext returns the Trace previously associated with ctx, or 116// nil if no such Trace could be found. 117func TraceFromContext(ctx context.Context) *Trace { 118 tr, _ := ctx.Value(traceKey).(*Trace) 119 return tr 120} 121 122// fieldsStringer lazily marshals a slice of log.Field into a string for 123// printing in net/trace. 124type fieldsStringer []log.Field 125 126func (fs fieldsStringer) String() string { 127 var e encoder 128 for _, f := range fs { 129 f.Marshal(&e) 130 } 131 return e.Builder.String() 132} 133 134// encoder is a log.Encoder used by fieldsStringer. 135type encoder struct { 136 strings.Builder 137 prefixNewline bool 138} 139 140func (e *encoder) EmitString(key, value string) { 141 if e.prefixNewline { 142 // most times encoder is used is for one field 143 e.Builder.WriteString("\n") 144 } 145 if !e.prefixNewline { 146 e.prefixNewline = true 147 } 148 149 e.Builder.Grow(len(key) + 1 + len(value)) 150 e.Builder.WriteString(key) 151 e.Builder.WriteString(":") 152 e.Builder.WriteString(value) 153} 154 155func (e *encoder) EmitBool(key string, value bool) { 156 e.EmitString(key, strconv.FormatBool(value)) 157} 158 159func (e *encoder) EmitInt(key string, value int) { 160 e.EmitString(key, strconv.Itoa(value)) 161} 162 163func (e *encoder) EmitInt32(key string, value int32) { 164 e.EmitString(key, strconv.FormatInt(int64(value), 10)) 165} 166 167func (e *encoder) EmitInt64(key string, value int64) { 168 e.EmitString(key, strconv.FormatInt(value, 10)) 169} 170 171func (e *encoder) EmitUint32(key string, value uint32) { 172 e.EmitString(key, strconv.FormatUint(uint64(value), 10)) 173} 174 175func (e *encoder) EmitUint64(key string, value uint64) { 176 e.EmitString(key, strconv.FormatUint(value, 10)) 177} 178 179func (e *encoder) EmitFloat32(key string, value float32) { 180 e.EmitString(key, strconv.FormatFloat(float64(value), 'E', -1, 64)) 181} 182 183func (e *encoder) EmitFloat64(key string, value float64) { 184 e.EmitString(key, strconv.FormatFloat(value, 'E', -1, 64)) 185} 186 187func (e *encoder) EmitObject(key string, value any) { 188 e.EmitString(key, fmt.Sprintf("%+v", value)) 189} 190 191func (e *encoder) EmitLazyLogger(value log.LazyLogger) { 192 value(e) 193}