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