···316316 // Trim the number of results after collating and sorting the
317317 // results
318318 MaxDocDisplayCount int
319319+320320+ // Trace turns on opentracing for this request if true and if the Jaeger address was provided as
321321+ // a command-line flag
322322+ Trace bool
323323+324324+ // SpanContext is the opentracing span context, if it exists, from the zoekt client
325325+ SpanContext map[string]string
319326}
320327321328func (s *SearchOptions) String() string {
+46
cmd/zoekt-webserver/main.go
···2828 "net/http"
2929 "os"
3030 "path/filepath"
3131+ "reflect"
3232+ "strconv"
3133 "strings"
3234 "syscall"
3335 "time"
···3840 "github.com/google/zoekt/query"
3941 "github.com/google/zoekt/shards"
4042 "github.com/google/zoekt/web"
4343+ "github.com/opentracing/opentracing-go"
4144 "github.com/prometheus/client_golang/prometheus"
4245 "go.uber.org/automaxprocs/maxprocs"
4646+4747+ "github.com/uber/jaeger-client-go"
4848+ jaegercfg "github.com/uber/jaeger-client-go/config"
4949+ jaegerlog "github.com/uber/jaeger-client-go/log"
5050+ jaegermetrics "github.com/uber/jaeger-lib/metrics"
4351)
44524553const logFormat = "2006-01-02T15-04-05.999999999Z07"
···125133 dumpTemplates := flag.Bool("dump_templates", false, "dump templates into --template_dir and exit.")
126134 version := flag.Bool("version", false, "Print version number")
127135 flag.Parse()
136136+137137+ initializeJaeger()
128138129139 if *version {
130140 fmt.Printf("zoekt-webserver version %q\n", zoekt.Version)
···314324 }
315325 return sr, err
316326}
327327+328328+func initializeJaeger() {
329329+ jaegerDisabled := os.Getenv("JAEGER_DISABLED")
330330+ if jaegerDisabled == "" {
331331+ return
332332+ }
333333+ isJaegerDisabled, err := strconv.ParseBool(jaegerDisabled)
334334+ if err != nil {
335335+ log.Printf("EROR: failed to parse JAEGER_DISABLED: %s", err)
336336+ return
337337+ }
338338+ if isJaegerDisabled {
339339+ return
340340+ }
341341+ cfg, err := jaegercfg.FromEnv()
342342+ cfg.ServiceName = "zoekt"
343343+ if err != nil {
344344+ log.Printf("EROR: could not initialize jaeger tracer from env, error: %v", err.Error())
345345+ return
346346+ }
347347+ if reflect.DeepEqual(cfg.Sampler, &jaegercfg.SamplerConfig{}) {
348348+ // Default sampler configuration for when it is not specified via
349349+ // JAEGER_SAMPLER_* env vars. In most cases, this is sufficient
350350+ // enough to connect to Jaeger without any env vars.
351351+ cfg.Sampler.Type = jaeger.SamplerTypeConst
352352+ cfg.Sampler.Param = 1
353353+ }
354354+ tracer, _, err := cfg.NewTracer(
355355+ jaegercfg.Logger(jaegerlog.StdLogger),
356356+ jaegercfg.Metrics(jaegermetrics.NullFactory),
357357+ )
358358+ if err != nil {
359359+ log.Printf("could not initialize jaeger tracer, error: %v", err.Error())
360360+ }
361361+ opentracing.SetGlobalTracer(tracer)
362362+}
···11+package trace
22+33+import (
44+ "context"
55+66+ "github.com/opentracing/opentracing-go"
77+)
88+99+type key int
1010+1111+const (
1212+ enableOpenTracingKey key = iota
1313+)
1414+1515+// isOpenTracingEnabled returns true if the enableOpenTracingKey context value is true.
1616+func isOpenTracingEnabled(ctx context.Context) bool {
1717+ v, ok := ctx.Value(enableOpenTracingKey).(bool)
1818+ if !ok {
1919+ return false
2020+ }
2121+ return v
2222+}
2323+2424+func WithOpenTracingEnabled(ctx context.Context, enableOpenTracing bool) context.Context {
2525+ return context.WithValue(ctx, enableOpenTracingKey, enableOpenTracing)
2626+}
2727+2828+// GetOpenTracer returns the tracer to actually use depending on whether isOpenTracingEnabled(ctx)
2929+// returns true or false. If false, this returns the NoopTracer.
3030+func GetOpenTracer(ctx context.Context, tracer opentracing.Tracer) opentracing.Tracer {
3131+ if !isOpenTracingEnabled(ctx) {
3232+ return opentracing.NoopTracer{}
3333+ }
3434+ if tracer == nil {
3535+ return opentracing.GlobalTracer()
3636+ }
3737+ return tracer
3838+}
3939+4040+// StartSpanFromContext starts a span using the tracer returned by invoking GetOpenTracer with the
4141+// passed-in tracer.
4242+func StartSpanFromContextWithTracer(ctx context.Context, tracer opentracing.Tracer, operationName string, opts ...opentracing.StartSpanOption) (opentracing.Span, context.Context) {
4343+ return opentracing.StartSpanFromContextWithTracer(ctx, GetOpenTracer(ctx, tracer), operationName, opts...)
4444+}
4545+4646+// StartSpanFromContext starts a span using the tracer returned by GetOpenTracer.
4747+func StartSpanFromContext(ctx context.Context, operationName string, opts ...opentracing.StartSpanOption) (opentracing.Span, context.Context) {
4848+ return StartSpanFromContextWithTracer(ctx, GetOpenTracer(ctx, nil), operationName, opts...)
4949+}
+187
trace/trace.go
···11+// Package trace provides a tracing API that in turn invokes both the `golang.org/x/net/trace` API
22+// and creates an opentracing span if appropriate.
33+//
44+// This is similar to the github.com/sourcegraph/sourcegraph/internal/trace package in the main repo,
55+// and it may make sense to factor both out into a common package at some point.
66+package trace
77+88+import (
99+ "context"
1010+ "fmt"
1111+ "strconv"
1212+ "strings"
1313+1414+ "github.com/opentracing/opentracing-go"
1515+ "github.com/opentracing/opentracing-go/ext"
1616+ "github.com/opentracing/opentracing-go/log"
1717+ nettrace "golang.org/x/net/trace"
1818+)
1919+2020+// A Tracer for trace creation, parameterised over an
2121+// opentracing.Tracer. Use this if you don't want to use
2222+// the global tracer.
2323+type Tracer struct {
2424+ Tracer opentracing.Tracer
2525+}
2626+2727+func New(ctx context.Context, family, title string) (*Trace, context.Context) {
2828+ tr := Tracer{Tracer: GetOpenTracer(ctx, nil)}
2929+ return tr.New(ctx, family, title)
3030+}
3131+3232+// New returns a new Trace with the specified family and title.
3333+func (t Tracer) New(ctx context.Context, family, title string) (*Trace, context.Context) {
3434+ span, ctx := StartSpanFromContextWithTracer(
3535+ ctx,
3636+ t.Tracer,
3737+ family,
3838+ opentracing.Tag{Key: "title", Value: title},
3939+ )
4040+ tr := nettrace.New(family, title)
4141+ trace := &Trace{span: span, trace: tr, family: family}
4242+ if parent := TraceFromContext(ctx); parent != nil {
4343+ tr.LazyPrintf("parent: %s", parent.family)
4444+ trace.family = parent.family + " > " + family
4545+ }
4646+ return trace, ContextWithTrace(ctx, trace)
4747+}
4848+4949+// Trace is a combined version of golang.org/x/net/trace.Trace and
5050+// opentracing.Span. Use New to construct one.
5151+type Trace struct {
5252+ trace nettrace.Trace
5353+ span opentracing.Span
5454+ family string
5555+}
5656+5757+// LazyPrintf evaluates its arguments with fmt.Sprintf each time the
5858+// /debug/requests page is rendered. Any memory referenced by a will be
5959+// pinned until the trace is finished and later discarded.
6060+func (t *Trace) LazyPrintf(format string, a ...interface{}) {
6161+ t.span.LogFields(Printf("log", format, a...))
6262+ t.trace.LazyPrintf(format, a...)
6363+}
6464+6565+func (t *Trace) LazyLog(x fmt.Stringer, sensitive bool) {
6666+ t.trace.LazyLog(x, sensitive)
6767+}
6868+6969+// LogFields logs fields to the opentracing.Span
7070+// as well as the nettrace.Trace.
7171+func (t *Trace) LogFields(fields ...log.Field) {
7272+ t.span.LogFields(fields...)
7373+ t.trace.LazyLog(fieldsStringer(fields), false)
7474+}
7575+7676+// SetError declares that this trace and span resulted in an error.
7777+func (t *Trace) SetError(err error) {
7878+ if err == nil {
7979+ return
8080+ }
8181+ t.trace.LazyPrintf("error: %v", err)
8282+ t.trace.SetError()
8383+ t.span.LogFields(log.Error(err))
8484+ ext.Error.Set(t.span, true)
8585+}
8686+8787+// Finish declares that this trace and span is complete.
8888+// The trace should not be used after calling this method.
8989+func (t *Trace) Finish() {
9090+ t.trace.Finish()
9191+ t.span.Finish()
9292+}
9393+9494+// Printf is an opentracing log.Field which is a LazyLogger. So the format
9595+// string will only be evaluated if the trace is collected. In the case of
9696+// net/trace, it will only be evaluated on page load.
9797+func Printf(key, f string, args ...interface{}) log.Field {
9898+ return log.Lazy(func(fv log.Encoder) {
9999+ fv.EmitString(key, fmt.Sprintf(f, args...))
100100+ })
101101+}
102102+103103+type traceContextKey string
104104+105105+const traceKey = traceContextKey("trace")
106106+107107+// ContextWithTrace returns a new context.Context that holds a reference to
108108+// trace's SpanContext.
109109+func ContextWithTrace(ctx context.Context, tr *Trace) context.Context {
110110+ ctx = opentracing.ContextWithSpan(ctx, tr.span)
111111+ ctx = context.WithValue(ctx, traceKey, tr)
112112+ return ctx
113113+}
114114+115115+// TraceFromContext returns the Trace previously associated with ctx, or
116116+// nil if no such Trace could be found.
117117+func TraceFromContext(ctx context.Context) *Trace {
118118+ tr, _ := ctx.Value(traceKey).(*Trace)
119119+ return tr
120120+}
121121+122122+// fieldsStringer lazily marshals a slice of log.Field into a string for
123123+// printing in net/trace.
124124+type fieldsStringer []log.Field
125125+126126+func (fs fieldsStringer) String() string {
127127+ var e encoder
128128+ for _, f := range fs {
129129+ f.Marshal(&e)
130130+ }
131131+ return e.Builder.String()
132132+}
133133+134134+// encoder is a log.Encoder used by fieldsStringer.
135135+type encoder struct {
136136+ strings.Builder
137137+ prefixNewline bool
138138+}
139139+140140+func (e *encoder) EmitString(key, value string) {
141141+ if e.prefixNewline {
142142+ // most times encoder is used is for one field
143143+ e.Builder.WriteString("\n")
144144+ }
145145+ if !e.prefixNewline {
146146+ e.prefixNewline = true
147147+ }
148148+149149+ e.Builder.Grow(len(key) + 1 + len(value))
150150+ e.Builder.WriteString(key)
151151+ e.Builder.WriteString(":")
152152+ e.Builder.WriteString(value)
153153+}
154154+155155+func (e *encoder) EmitBool(key string, value bool) {
156156+ e.EmitString(key, strconv.FormatBool(value))
157157+}
158158+159159+func (e *encoder) EmitInt(key string, value int) {
160160+ e.EmitString(key, strconv.Itoa(value))
161161+}
162162+163163+func (e *encoder) EmitInt32(key string, value int32) {
164164+ e.EmitString(key, strconv.FormatInt(int64(value), 10))
165165+}
166166+func (e *encoder) EmitInt64(key string, value int64) {
167167+ e.EmitString(key, strconv.FormatInt(value, 10))
168168+}
169169+func (e *encoder) EmitUint32(key string, value uint32) {
170170+ e.EmitString(key, strconv.FormatUint(uint64(value), 10))
171171+}
172172+func (e *encoder) EmitUint64(key string, value uint64) {
173173+ e.EmitString(key, strconv.FormatUint(value, 10))
174174+}
175175+func (e *encoder) EmitFloat32(key string, value float32) {
176176+ e.EmitString(key, strconv.FormatFloat(float64(value), 'E', -1, 64))
177177+}
178178+func (e *encoder) EmitFloat64(key string, value float64) {
179179+ e.EmitString(key, strconv.FormatFloat(value, 'E', -1, 64))
180180+}
181181+func (e *encoder) EmitObject(key string, value interface{}) {
182182+ e.EmitString(key, fmt.Sprintf("%+v", value))
183183+}
184184+185185+func (e *encoder) EmitLazyLogger(value log.LazyLogger) {
186186+ value(e)
187187+}