1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package global
16
17 import (
18 "context"
19 "sync/atomic"
20 "testing"
21 "time"
22
23 "github.com/stretchr/testify/assert"
24
25 "go.opentelemetry.io/otel/trace"
26 "go.opentelemetry.io/otel/trace/embedded"
27 "go.opentelemetry.io/otel/trace/noop"
28 )
29
30 type fnTracerProvider struct {
31 embedded.TracerProvider
32
33 tracer func(string, ...trace.TracerOption) trace.Tracer
34 }
35
36 func (fn fnTracerProvider) Tracer(instrumentationName string, opts ...trace.TracerOption) trace.Tracer {
37 return fn.tracer(instrumentationName, opts...)
38 }
39
40 type fnTracer struct {
41 embedded.Tracer
42
43 start func(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span)
44 }
45
46 func (fn fnTracer) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
47 return fn.start(ctx, spanName, opts...)
48 }
49
50 func TestTraceProviderDelegation(t *testing.T) {
51 ResetForTest(t)
52
53
54 expected := map[string][]string{
55 "pre": {"span2"},
56 "post": {"span3"},
57 "fromSpan": {"span4"},
58 }
59
60 ctx := context.Background()
61 gtp := TracerProvider()
62 tracer1 := gtp.Tracer("pre")
63
64 _, span1 := tracer1.Start(ctx, "span1")
65
66 SetTracerProvider(fnTracerProvider{
67 tracer: func(name string, opts ...trace.TracerOption) trace.Tracer {
68 spans, ok := expected[name]
69 assert.Truef(t, ok, "invalid tracer: %s", name)
70 return fnTracer{
71 start: func(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
72 if ok {
73 if len(spans) == 0 {
74 t.Errorf("unexpected span: %s", spanName)
75 } else {
76 var want string
77 want, spans = spans[0], spans[1:]
78 assert.Equal(t, want, spanName)
79 }
80 }
81 return noop.NewTracerProvider().Tracer(name).Start(ctx, spanName)
82 },
83 }
84 },
85 })
86
87
88 span1.End()
89
90
91 _, span2 := tracer1.Start(ctx, "span2")
92 span2.End()
93
94
95 tracer2 := gtp.Tracer("post")
96 _, span3 := tracer2.Start(ctx, "span3")
97 span3.End()
98
99
100 _, span4 := span1.TracerProvider().Tracer("fromSpan").Start(ctx, "span4")
101 span4.End()
102 }
103
104 func TestTraceProviderDelegates(t *testing.T) {
105 ResetForTest(t)
106
107
108 gtp := TracerProvider()
109
110
111 called := false
112 SetTracerProvider(fnTracerProvider{
113 tracer: func(name string, opts ...trace.TracerOption) trace.Tracer {
114 called = true
115 assert.Equal(t, "abc", name)
116 return noop.NewTracerProvider().Tracer("")
117 },
118 })
119
120 gtp.Tracer("abc", trace.WithInstrumentationVersion("xyz"))
121 assert.True(t, called, "expected configured TraceProvider to be called")
122 }
123
124 func TestTraceProviderDelegatesConcurrentSafe(t *testing.T) {
125 ResetForTest(t)
126
127
128 gtp := TracerProvider()
129
130 done := make(chan struct{})
131 quit := make(chan struct{})
132 go func() {
133 defer close(done)
134 for {
135 select {
136 case <-time.After(1 * time.Millisecond):
137 gtp.Tracer("abc", trace.WithInstrumentationVersion("xyz"))
138 case <-quit:
139 return
140 }
141 }
142 }()
143
144
145 <-time.After(100 * time.Millisecond)
146
147
148 called := int32(0)
149 SetTracerProvider(fnTracerProvider{
150 tracer: func(name string, opts ...trace.TracerOption) trace.Tracer {
151 newVal := atomic.AddInt32(&called, 1)
152 assert.Equal(t, "abc", name)
153 if newVal == 10 {
154
155 close(quit)
156 }
157 return noop.NewTracerProvider().Tracer("")
158 },
159 })
160
161
162 <-done
163
164 assert.LessOrEqual(t, int32(10), atomic.LoadInt32(&called), "expected configured TraceProvider to be called")
165 }
166
167 func TestTracerDelegatesConcurrentSafe(t *testing.T) {
168 ResetForTest(t)
169
170
171 gtp := TracerProvider()
172 tracer := gtp.Tracer("abc", trace.WithInstrumentationVersion("xyz"))
173
174 done := make(chan struct{})
175 quit := make(chan struct{})
176 go func() {
177 defer close(done)
178 for {
179 select {
180 case <-time.After(1 * time.Millisecond):
181 tracer.Start(context.Background(), "name")
182 case <-quit:
183 return
184 }
185 }
186 }()
187
188
189 <-time.After(100 * time.Millisecond)
190
191
192 called := int32(0)
193 SetTracerProvider(fnTracerProvider{
194 tracer: func(name string, opts ...trace.TracerOption) trace.Tracer {
195 assert.Equal(t, "abc", name)
196 return fnTracer{
197 start: func(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
198 newVal := atomic.AddInt32(&called, 1)
199 assert.Equal(t, "name", spanName)
200 if newVal == 10 {
201
202 close(quit)
203 }
204 return noop.NewTracerProvider().Tracer("").Start(ctx, spanName)
205 },
206 }
207 },
208 })
209
210
211 <-done
212
213 assert.LessOrEqual(t, int32(10), atomic.LoadInt32(&called), "expected configured TraceProvider to be called")
214 }
215
216 func TestTraceProviderDelegatesSameInstance(t *testing.T) {
217 ResetForTest(t)
218
219
220 gtp := TracerProvider()
221 tracer := gtp.Tracer("abc", trace.WithInstrumentationVersion("xyz"))
222 assert.Same(t, tracer, gtp.Tracer("abc", trace.WithInstrumentationVersion("xyz")))
223 assert.Same(t, tracer, gtp.Tracer("abc", trace.WithInstrumentationVersion("xyz")))
224
225 SetTracerProvider(fnTracerProvider{
226 tracer: func(name string, opts ...trace.TracerOption) trace.Tracer {
227 return noop.NewTracerProvider().Tracer("")
228 },
229 })
230
231 assert.NotSame(t, tracer, gtp.Tracer("abc", trace.WithInstrumentationVersion("xyz")))
232 }
233
234 func TestSpanContextPropagatedWithNonRecordingSpan(t *testing.T) {
235 ResetForTest(t)
236
237 sc := trace.NewSpanContext(trace.SpanContextConfig{
238 TraceID: [16]byte{0x01},
239 SpanID: [8]byte{0x01},
240 TraceFlags: trace.FlagsSampled,
241 Remote: true,
242 })
243 ctx := trace.ContextWithSpanContext(context.Background(), sc)
244 _, span := TracerProvider().Tracer("test").Start(ctx, "test")
245
246 assert.Equal(t, sc, span.SpanContext())
247 assert.False(t, span.IsRecording())
248 }
249
View as plain text