-
Notifications
You must be signed in to change notification settings - Fork 170
/
tracer.go
151 lines (124 loc) · 5.29 KB
/
tracer.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package tracing
import (
"context"
"github.com/azure/azure-dev/cli/azd/internal/tracing/baggage"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
)
// It is often valuable to extend functionality of 3rd-party library types.
// Therefore, we provide extension points for OpenTelemetry tracers here.
// Tracer is the creator of Spans.
//
// This is simply trace.Tracer except returning our Span instead of trace.Span.
type Tracer interface {
Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, Span)
}
// Wrapper around trace.Tracer.
type wrapperTracer struct {
tracer trace.Tracer
}
func (w *wrapperTracer) Start(
ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, Span) {
ctx, span := w.tracer.Start(ctx, spanName, opts...)
// Propagate any baggage in the current context
baggage := baggage.BaggageFromContext(ctx)
span.SetAttributes(baggage.Attributes()...)
return ctx, &wrapperSpan{span}
}
// redefinedSpan is a slightly modified version of trace.Span.
//
// The only change made is to remove functionality around emitting events.
// Events are nested telemetry events that can be fired from a Span.
// We currently do not support this yet (no use case), but this is likely to be changed in the future.
//
// Exact modifications to trace.Span:
// - Removed AddEvent
// - Removed RecordError. This creates an error type event
type redefinedSpan interface {
// End completes the Span. The Span is considered complete and ready to be
// delivered through the rest of the telemetry pipeline after this method
// is called. Therefore, updates to the Span are not allowed after this
// method has been called.
End(options ...trace.SpanEndOption)
// IsRecording returns the recording state of the Span. It will return
// true if the Span is active and events can be recorded.
IsRecording() bool
// SpanContext returns the SpanContext of the Span. The returned SpanContext
// is usable even after the End method has been called for the Span.
SpanContext() trace.SpanContext
// SetStatus sets the status of the Span in the form of a code and a
// description, overriding previous values set. The description is only
// included in a status when the code is for an error.
SetStatus(code codes.Code, description string)
// SetName sets the Span name.
SetName(name string)
// SetAttributes sets kv as attributes of the Span. If a key from kv
// already exists for an attribute of the Span it will be overwritten with
// the value contained in kv.
SetAttributes(kv ...attribute.KeyValue)
// TracerProvider returns a TracerProvider that can be used to generate
// additional Spans on the same telemetry pipeline as the current Span.
TracerProvider() trace.TracerProvider
}
// Span is the individual component of a trace. It represents a single named
// and timed operation of a workflow that is traced. A Tracer is used to
// create a Span and it is then up to the operation the Span represents to
// properly end the Span when the operation itself ends.
type Span interface {
redefinedSpan
// EndWithStatus calls End, but also sets Status based on the value of err (nil mean success).
EndWithStatus(err error, options ...trace.SpanEndOption)
}
type wrapperSpan struct {
span trace.Span
}
// End completes the Span. The Span is considered complete and ready to be
// delivered through the rest of the telemetry pipeline after this method
// is called. Therefore, updates to the Span are not allowed after this
// method has been called.
func (s *wrapperSpan) End(options ...trace.SpanEndOption) {
s.span.SetAttributes(GetGlobalAttributes()...)
s.span.End(options...)
}
func (s *wrapperSpan) EndWithStatus(err error, options ...trace.SpanEndOption) {
if err != nil {
s.span.SetStatus(codes.Error, "UnknownError")
} else {
s.span.SetStatus(codes.Ok, "")
}
s.End(options...)
}
// IsRecording returns the recording state of the Span. It will return
// true if the Span is active and events can be recorded.
func (s *wrapperSpan) IsRecording() bool {
return s.span.IsRecording()
}
// SpanContext returns the SpanContext of the Span. The returned SpanContext
// is usable even after the End method has been called for the Span.
func (s *wrapperSpan) SpanContext() trace.SpanContext {
return s.span.SpanContext()
}
// SetStatus sets the status of the Span in the form of a code and a
// description, overriding previous values set. The description is only
// included in a status when the code is for an error.
func (s *wrapperSpan) SetStatus(code codes.Code, description string) {
s.span.SetStatus(code, description)
}
// SetName sets the Span name.
func (s *wrapperSpan) SetName(name string) {
s.span.SetName(name)
}
// SetAttributes sets kv as attributes of the Span. If a key from kv
// already exists for an attribute of the Span it will be overwritten with
// the value contained in kv.
func (s *wrapperSpan) SetAttributes(kv ...attribute.KeyValue) {
s.span.SetAttributes(kv...)
}
// TracerProvider returns a TracerProvider that can be used to generate
// additional Spans on the same telemetry pipeline as the current Span.
func (s *wrapperSpan) TracerProvider() trace.TracerProvider {
return s.span.TracerProvider()
}