github.com/grahambrereton-form3/tilt@v0.10.18/internal/tracer/tracer.go (about) 1 package tracer 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "os" 8 "strings" 9 10 "github.com/pkg/errors" 11 12 "github.com/lightstep/lightstep-tracer-go" 13 "github.com/opentracing/opentracing-go" 14 zipkin "github.com/openzipkin/zipkin-go-opentracing" 15 jaeger "github.com/uber/jaeger-client-go" 16 jaegercfg "github.com/uber/jaeger-client-go/config" 17 18 "github.com/windmilleng/tilt/pkg/logger" 19 ) 20 21 const windmillTracerHostPort = "opentracing.windmill.build:9411" 22 23 type TracerBackend int 24 25 const ( 26 Windmill TracerBackend = iota 27 Lightstep 28 Jaeger 29 ) 30 31 type zipkinLogger struct { 32 ctx context.Context 33 } 34 35 func (zl zipkinLogger) Log(keyvals ...interface{}) error { 36 logger.Get(zl.ctx).Debugf("%v", keyvals) 37 return nil 38 } 39 40 var _ zipkin.Logger = zipkinLogger{} 41 42 func Init(ctx context.Context, tracer TracerBackend) (func() error, error) { 43 switch tracer { 44 case Windmill: 45 return initWindmillZipkin(ctx) 46 case Lightstep: 47 return initLightStep(ctx) 48 case Jaeger: 49 return initJaeger(ctx) 50 default: 51 return nil, fmt.Errorf("Init: Invalid Tracer backend: %d", tracer) 52 } 53 } 54 55 func TraceID(ctx context.Context) (string, error) { 56 spanContext := opentracing.SpanFromContext(ctx) 57 if spanContext == nil { 58 return "", errors.New("cannot get traceid - there is no span context") 59 } 60 switch t := spanContext.Context().(type) { 61 case zipkin.SpanContext: 62 return t.TraceID.ToHex(), nil 63 case lightstep.SpanContext: 64 return string(t.TraceID), nil 65 case jaeger.SpanContext: 66 return t.TraceID().String(), nil 67 default: 68 return "", errors.New("cannot get traceid - unknown span type") 69 } 70 } 71 72 // TagStrToMap converts a user-passed string of tags of the form `key1=val1,key2=val2` to a map. 73 func TagStrToMap(tagStr string) map[string]string { 74 if tagStr == "" { 75 return nil 76 } 77 78 res := make(map[string]string) 79 pairs := strings.Split(tagStr, ",") 80 for _, p := range pairs { 81 elems := strings.Split(strings.TrimSpace(p), "=") 82 if len(elems) != 2 { 83 log.Printf("got malformed trace tag: %s", p) 84 continue 85 } 86 res[elems[0]] = elems[1] 87 } 88 return res 89 } 90 91 func StringToTracerBackend(s string) (TracerBackend, error) { 92 switch s { 93 case "windmill": 94 return Windmill, nil 95 case "lightstep": 96 return Lightstep, nil 97 case "jaeger": 98 return Jaeger, nil 99 default: 100 return Windmill, fmt.Errorf("Invalid Tracer backend: %s", s) 101 } 102 } 103 104 func initWindmillZipkin(ctx context.Context) (func() error, error) { 105 collector, err := zipkin.NewHTTPCollector(fmt.Sprintf("http://%s/api/v1/spans", windmillTracerHostPort), zipkin.HTTPLogger(zipkinLogger{ctx})) 106 107 if err != nil { 108 return nil, errors.Wrap(err, "unable to create zipkin collector") 109 } 110 111 recorder := zipkin.NewRecorder(collector, true, "0.0.0.0:0", "tilt") 112 tracer, err := zipkin.NewTracer(recorder) 113 114 if err != nil { 115 return nil, errors.Wrap(err, "unable to create tracer") 116 } 117 118 opentracing.SetGlobalTracer(tracer) 119 120 return collector.Close, nil 121 } 122 123 func initLightStep(ctx context.Context) (func() error, error) { 124 token, ok := os.LookupEnv("LIGHTSTEP_ACCESS_TOKEN") 125 if !ok { 126 return nil, fmt.Errorf("No token found in the LIGHTSTEP_ACCESS_TOKEN environment variable") 127 } 128 lightstepTracer := lightstep.NewTracer(lightstep.Options{ 129 AccessToken: token, 130 }) 131 132 opentracing.SetGlobalTracer(lightstepTracer) 133 134 close := func() error { 135 lightstepTracer.Close(context.Background()) 136 return nil 137 } 138 return close, nil 139 } 140 141 func initJaeger(ctx context.Context) (func() error, error) { 142 cfg := jaegercfg.Configuration{ 143 Sampler: &jaegercfg.SamplerConfig{ 144 Type: "const", 145 Param: 1, 146 }, 147 } 148 closer, err := cfg.InitGlobalTracer("tilt") 149 return closer.Close, err 150 }