github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/tracing/tracer.go (about) 1 package tracing 2 3 import ( 4 "context" 5 6 "go.opentelemetry.io/collector/translator/conventions" 7 "go.opentelemetry.io/otel/api/global" 8 "go.opentelemetry.io/otel/api/propagation" 9 "go.opentelemetry.io/otel/api/trace" 10 "go.opentelemetry.io/otel/codes" 11 "go.opentelemetry.io/otel/label" 12 export "go.opentelemetry.io/otel/sdk/export/trace" 13 "go.opentelemetry.io/otel/sdk/resource" 14 sdktrace "go.opentelemetry.io/otel/sdk/trace" 15 ) 16 17 //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 go.opentelemetry.io/otel/api/trace.Tracer 18 //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 go.opentelemetry.io/otel/api/trace.Provider 19 //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 go.opentelemetry.io/otel/api/trace.Span 20 21 // Configured indicates whether tracing has been configured or not. 22 // 23 // This variable is needed in order to shortcircuit span generation when 24 // tracing hasn't been configured. 25 // 26 // 27 var Configured bool 28 29 type Config struct { 30 ServiceName string `long:"service-name" description:"service name to attach to traces as metadata" default:"concourse-web"` 31 Attributes map[string]string `long:"attribute" description:"attributes to attach to traces as metadata"` 32 Honeycomb Honeycomb 33 Jaeger Jaeger 34 Stackdriver Stackdriver 35 OTLP OTLP 36 } 37 38 func (c Config) resource() *resource.Resource { 39 attributes := []label.KeyValue{ 40 label.String(conventions.AttributeTelemetrySDKName, "opentelemetry"), 41 label.String(conventions.AttributeTelemetrySDKLanguage, "go"), 42 label.String(conventions.AttributeServiceName, c.ServiceName), 43 } 44 45 for key, value := range c.Attributes { 46 attributes = append(attributes, label.String(key, value)) 47 } 48 49 return resource.New(attributes...) 50 } 51 52 func (c Config) TraceProvider(exporter func() (export.SpanSyncer, error)) (trace.Provider, error) { 53 exp, err := exporter() 54 if err != nil { 55 return nil, err 56 } 57 58 provider, err := sdktrace.NewProvider(sdktrace.WithConfig( 59 sdktrace.Config{ 60 DefaultSampler: sdktrace.AlwaysSample(), 61 }), 62 sdktrace.WithSyncer(exp), 63 sdktrace.WithResource(c.resource()), 64 ) 65 if err != nil { 66 return nil, err 67 } 68 69 return provider, nil 70 } 71 72 func (c Config) Prepare() error { 73 var provider trace.Provider 74 var err error 75 76 switch { 77 case c.Honeycomb.IsConfigured(): 78 provider, err = c.TraceProvider(c.Honeycomb.Exporter) 79 case c.Jaeger.IsConfigured(): 80 provider, err = c.TraceProvider(c.Jaeger.Exporter) 81 case c.OTLP.IsConfigured(): 82 provider, err = c.TraceProvider(c.OTLP.Exporter) 83 case c.Stackdriver.IsConfigured(): 84 provider, err = c.TraceProvider(c.Stackdriver.Exporter) 85 } 86 if err != nil { 87 return err 88 } 89 90 if provider != nil { 91 ConfigureTraceProvider(provider) 92 } 93 94 return nil 95 } 96 97 // StartSpan creates a span, giving back a context that has itself added as the 98 // parent span. 99 // 100 // Calls to this function with a context that has been generated from a previous 101 // call to this method will make the resulting span a child of the span that 102 // preceded it. 103 // 104 // For instance: 105 // 106 // ``` 107 // func fn () { 108 // 109 // rootCtx, rootSpan := StartSpan(context.Background(), "foo", nil) 110 // defer rootSpan.End() 111 // 112 // _, childSpan := StartSpan(rootCtx, "bar", nil) 113 // defer childSpan.End() 114 // 115 // } 116 // ``` 117 // 118 // calling `fn()` will lead to the following trace: 119 // 120 // ``` 121 // foo 0--------3 122 // bar 1----2 123 // ``` 124 // 125 // where (0) is the start of the root span, which then gets a child `bar` 126 // initializing at (1), having its end called (2), and then the last span 127 // finalization happening for the root span (3) given how `defer` statements 128 // stack. 129 // 130 func StartSpan( 131 ctx context.Context, 132 component string, 133 attrs Attrs, 134 ) (context.Context, trace.Span) { 135 return startSpan(ctx, component, attrs) 136 } 137 138 func FromContext(ctx context.Context) trace.Span { 139 return trace.SpanFromContext(ctx) 140 } 141 142 func Inject(ctx context.Context, supplier propagation.HTTPSupplier) { 143 trace.TraceContext{}.Inject(ctx, supplier) 144 } 145 146 type WithSpanContext interface { 147 SpanContext() propagation.HTTPSupplier 148 } 149 150 func StartSpanFollowing( 151 ctx context.Context, 152 following WithSpanContext, 153 component string, 154 attrs Attrs, 155 ) (context.Context, trace.Span) { 156 if supplier := following.SpanContext(); supplier != nil { 157 ctx = trace.TraceContext{}.Extract(ctx, supplier) 158 } 159 160 return startSpan(ctx, component, attrs) 161 } 162 163 func StartSpanLinkedToFollowing( 164 linked context.Context, 165 following WithSpanContext, 166 component string, 167 attrs Attrs, 168 ) (context.Context, trace.Span) { 169 ctx := context.Background() 170 if supplier := following.SpanContext(); supplier != nil { 171 ctx = trace.TraceContext{}.Extract(ctx, supplier) 172 } 173 linkedSpanContext := trace.SpanFromContext(linked).SpanContext() 174 175 return startSpan( 176 ctx, 177 component, 178 attrs, 179 trace.LinkedTo(linkedSpanContext), 180 ) 181 } 182 183 func startSpan( 184 ctx context.Context, 185 component string, 186 attrs Attrs, 187 opts ...trace.StartOption, 188 ) (context.Context, trace.Span) { 189 if !Configured { 190 return ctx, trace.NoopSpan{} 191 } 192 193 ctx, span := global.TraceProvider().Tracer("concourse").Start( 194 ctx, 195 component, 196 opts..., 197 ) 198 199 if len(attrs) != 0 { 200 span.SetAttributes(keyValueSlice(attrs)...) 201 } 202 203 return ctx, span 204 } 205 206 func End(span trace.Span, err error) { 207 if !Configured { 208 return 209 } 210 211 if err != nil { 212 span.SetStatus(codes.Internal, "") 213 span.SetAttributes( 214 label.String("error-message", err.Error()), 215 ) 216 } 217 218 span.End() 219 } 220 221 // ConfigureTraceProvider configures the sdk to use a given trace provider. 222 // 223 // By default, a noop tracer is registered, thus, it's safe to call StartSpan 224 // and other related methods even before `ConfigureTracer` it called. 225 // 226 func ConfigureTraceProvider(tp trace.Provider) { 227 global.SetTraceProvider(tp) 228 Configured = true 229 }