github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/tracing/shadow.go (about)

     1  // Copyright 2017 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  //
    11  // A "shadow" tracer can be any opentracing.Tracer implementation that is used
    12  // in addition to the normal functionality of our tracer. It works by attaching
    13  // a shadow span to every span, and attaching a shadow context to every span
    14  // context. When injecting a span context, we encapsulate the shadow context
    15  // inside ours.
    16  
    17  package tracing
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"os"
    23  	"time"
    24  
    25  	"github.com/cockroachdb/cockroach/pkg/util"
    26  	"github.com/cockroachdb/cockroach/pkg/util/timeutil"
    27  	lightstep "github.com/lightstep/lightstep-tracer-go"
    28  	opentracing "github.com/opentracing/opentracing-go"
    29  	zipkin "github.com/openzipkin-contrib/zipkin-go-opentracing"
    30  )
    31  
    32  type shadowTracerManager interface {
    33  	Name() string
    34  	Close(tr opentracing.Tracer)
    35  }
    36  
    37  type lightStepManager struct{}
    38  
    39  func (lightStepManager) Name() string {
    40  	return "lightstep"
    41  }
    42  
    43  func (lightStepManager) Close(tr opentracing.Tracer) {
    44  	lightstep.Close(context.TODO(), tr)
    45  }
    46  
    47  type zipkinManager struct {
    48  	collector zipkin.Collector
    49  }
    50  
    51  func (*zipkinManager) Name() string {
    52  	return "zipkin"
    53  }
    54  
    55  func (m *zipkinManager) Close(tr opentracing.Tracer) {
    56  	_ = m.collector.Close()
    57  }
    58  
    59  type shadowTracer struct {
    60  	opentracing.Tracer
    61  	manager shadowTracerManager
    62  }
    63  
    64  func (st *shadowTracer) Typ() string {
    65  	return st.manager.Name()
    66  }
    67  
    68  func (st *shadowTracer) Close() {
    69  	st.manager.Close(st)
    70  }
    71  
    72  // linkShadowSpan creates and links a Shadow span to the passed-in span (i.e.
    73  // fills in s.shadowTr and s.shadowSpan). This should only be called when
    74  // shadow tracing is enabled.
    75  //
    76  // The Shadow span will have a parent if parentShadowCtx is not nil.
    77  // parentType is ignored if parentShadowCtx is nil.
    78  //
    79  // The tags (including logTags) from s are copied to the Shadow span.
    80  func linkShadowSpan(
    81  	s *span,
    82  	shadowTr *shadowTracer,
    83  	parentShadowCtx opentracing.SpanContext,
    84  	parentType opentracing.SpanReferenceType,
    85  ) {
    86  	// Create the shadow lightstep span.
    87  	var opts []opentracing.StartSpanOption
    88  	// Replicate the options, using the lightstep context in the reference.
    89  	opts = append(opts, opentracing.StartTime(s.startTime))
    90  	if s.logTags != nil {
    91  		opts = append(opts, LogTags(s.logTags))
    92  	}
    93  	if s.mu.tags != nil {
    94  		opts = append(opts, s.mu.tags)
    95  	}
    96  	if parentShadowCtx != nil {
    97  		opts = append(opts, opentracing.SpanReference{
    98  			Type:              parentType,
    99  			ReferencedContext: parentShadowCtx,
   100  		})
   101  	}
   102  	s.shadowTr = shadowTr
   103  	s.shadowSpan = shadowTr.StartSpan(s.operation, opts...)
   104  }
   105  
   106  func createLightStepTracer(token string) (shadowTracerManager, opentracing.Tracer) {
   107  	return lightStepManager{}, lightstep.NewTracer(lightstep.Options{
   108  		AccessToken:      token,
   109  		MaxLogsPerSpan:   maxLogsPerSpan,
   110  		MaxBufferedSpans: 10000,
   111  		UseGRPC:          true,
   112  	})
   113  }
   114  
   115  var zipkinLogEveryN = util.Every(5 * time.Second)
   116  
   117  func createZipkinTracer(collectorAddr string) (shadowTracerManager, opentracing.Tracer) {
   118  	// Create our HTTP collector.
   119  	collector, err := zipkin.NewHTTPCollector(
   120  		fmt.Sprintf("http://%s/api/v1/spans", collectorAddr),
   121  		zipkin.HTTPLogger(zipkin.LoggerFunc(func(keyvals ...interface{}) error {
   122  			if zipkinLogEveryN.ShouldProcess(timeutil.Now()) {
   123  				// These logs are from the collector (e.g. errors sending data, dropped
   124  				// traces). We can't use `log` from this package so print them to stderr.
   125  				toPrint := append([]interface{}{"Zipkin collector"}, keyvals...)
   126  				fmt.Fprintln(os.Stderr, toPrint)
   127  			}
   128  			return nil
   129  		})),
   130  	)
   131  	if err != nil {
   132  		panic(err)
   133  	}
   134  
   135  	// Create our recorder.
   136  	recorder := zipkin.NewRecorder(collector, false /* debug */, "0.0.0.0:0", "cockroach")
   137  
   138  	// Create our tracer.
   139  	zipkinTr, err := zipkin.NewTracer(recorder)
   140  	if err != nil {
   141  		panic(err)
   142  	}
   143  	return &zipkinManager{collector: collector}, zipkinTr
   144  }