-
Notifications
You must be signed in to change notification settings - Fork 289
/
span.go
129 lines (104 loc) · 3.77 KB
/
span.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package tracetools
import (
"context"
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
ddext "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
)
const (
BackendDatadog = "datadog"
BackendOpenTelemetry = "opentelemetry"
BackendNone = ""
)
var ValidTracingBackends = map[string]struct{}{
BackendDatadog: {},
BackendOpenTelemetry: {},
BackendNone: {},
}
// StartSpanFromContext will start a span appropriate to the given tracing backend from the given context with the given
// operation name. It will also do some common/repeated setup on the span to keep code a little more DRY.
// If an unknown tracing backend is specified, it will return a span that noops on every operation
func StartSpanFromContext(ctx context.Context, operation string, tracingBackend string) (Span, context.Context) {
switch tracingBackend {
case BackendDatadog:
span, ctx := opentracing.StartSpanFromContext(ctx, operation)
span.SetTag(ddext.AnalyticsEvent, true) // Make the span available for analytics in Datadog
return NewOpenTracingSpan(span), ctx
case BackendOpenTelemetry:
ctx, span := otel.Tracer("buildkite-agent").Start(ctx, operation)
span.SetAttributes(attribute.String("analytics.event", "true"))
return &OpenTelemetrySpan{Span: span}, ctx
case BackendNone:
fallthrough
default:
return &NoopSpan{}, ctx
}
}
type Span interface {
AddAttributes(map[string]string)
FinishWithError(error)
RecordError(error)
}
type OpenTracingSpan struct {
Span opentracing.Span
}
func NewOpenTracingSpan(base opentracing.Span) *OpenTracingSpan {
return &OpenTracingSpan{Span: base}
}
// AddAttributes adds the given map of attributes to the span as OpenTracing tags
func (s *OpenTracingSpan) AddAttributes(attributes map[string]string) {
for k, v := range attributes {
s.Span.SetTag(k, v)
}
}
// FinishWithError adds error information to the OpenTracingSpan if error isn't nil, and records the span as having finished
func (s *OpenTracingSpan) FinishWithError(err error) {
s.RecordError(err)
s.Span.Finish()
}
// RecordError records an error on the given span
func (s *OpenTracingSpan) RecordError(err error) {
if err == nil {
return
}
ext.LogError(s.Span, err)
}
type OpenTelemetrySpan struct {
Span trace.Span
}
func NewOpenTelemetrySpan(base trace.Span) *OpenTelemetrySpan {
return &OpenTelemetrySpan{Span: base}
}
// AddAttributes adds the given attributes to the OpenTelemetry span. Only string attributes are accepted.
func (s *OpenTelemetrySpan) AddAttributes(attributes map[string]string) {
for k, v := range attributes {
s.Span.SetAttributes(attribute.String(k, v))
}
}
// FinishWithError adds error information to the OpenTelemetry span if error isn't nil, and records the span as having finished
func (s *OpenTelemetrySpan) FinishWithError(err error) {
s.RecordError(err)
s.Span.End()
}
// RecordError records an error on the given OpenTelemetry span. No-op when error is nil
func (s *OpenTelemetrySpan) RecordError(err error) {
if err == nil {
return
}
s.Span.RecordError(err)
s.Span.SetStatus(codes.Error, "failed")
}
// NoopSpan is an implementation of the Span interface that does nothing for every method implemented
// The intended use case is for instances where the user doesn't have tracing enabled - using NoopSpan, we can still act
// as though tracing is enabled, but every time we do something tracing related, nothing happens.
type NoopSpan struct{}
// AddAttributes is a noop
func (s *NoopSpan) AddAttributes(attributes map[string]string) {}
// FinishWithError is a noop
func (s *NoopSpan) FinishWithError(err error) {}
// RecordError is a noop
func (s *NoopSpan) RecordError(err error) {}