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

Configure Feed

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

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