17
17
package org .springframework .boot .actuate .autoconfigure .tracing ;
18
18
19
19
import java .util .ArrayList ;
20
+ import java .util .Collection ;
20
21
import java .util .List ;
21
22
22
23
import io .micrometer .tracing .SpanCustomizer ;
35
36
import io .opentelemetry .context .propagation .ContextPropagators ;
36
37
import io .opentelemetry .context .propagation .TextMapPropagator ;
37
38
import io .opentelemetry .extension .trace .propagation .B3Propagator ;
39
+ import io .opentelemetry .sdk .common .CompletableResultCode ;
38
40
import io .opentelemetry .sdk .trace .SdkTracerProvider ;
39
41
import io .opentelemetry .sdk .trace .SpanLimits ;
40
42
import io .opentelemetry .sdk .trace .SpanProcessor ;
43
+ import io .opentelemetry .sdk .trace .data .SpanData ;
44
+ import io .opentelemetry .sdk .trace .export .SpanExporter ;
41
45
import io .opentelemetry .sdk .trace .samplers .Sampler ;
42
46
import org .junit .jupiter .api .Test ;
43
47
import org .junit .jupiter .params .ParameterizedTest ;
@@ -88,6 +92,7 @@ void shouldSupplyBeans() {
88
92
assertThat (context ).hasSingleBean (TextMapPropagator .class );
89
93
assertThat (context ).hasSingleBean (OtelSpanCustomizer .class );
90
94
assertThat (context ).hasSingleBean (SpanProcessors .class );
95
+ assertThat (context ).hasSingleBean (SpanExporters .class );
91
96
});
92
97
}
93
98
@@ -119,6 +124,7 @@ void shouldNotSupplyBeansIfDependencyIsMissing(String packageName) {
119
124
assertThat (context ).doesNotHaveBean (TextMapPropagator .class );
120
125
assertThat (context ).doesNotHaveBean (OtelSpanCustomizer .class );
121
126
assertThat (context ).doesNotHaveBean (SpanProcessors .class );
127
+ assertThat (context ).doesNotHaveBean (SpanExporters .class );
122
128
});
123
129
}
124
130
@@ -151,6 +157,8 @@ void shouldBackOffOnCustomBeans() {
151
157
assertThat (context ).hasSingleBean (SpanCustomizer .class );
152
158
assertThat (context ).hasBean ("customSpanProcessors" );
153
159
assertThat (context ).hasSingleBean (SpanProcessors .class );
160
+ assertThat (context ).hasBean ("customSpanExporters" );
161
+ assertThat (context ).hasSingleBean (SpanExporters .class );
154
162
});
155
163
}
156
164
@@ -164,6 +172,17 @@ void shouldAllowMultipleSpanProcessors() {
164
172
});
165
173
}
166
174
175
+ @ Test
176
+ void shouldAllowMultipleSpanExporters () {
177
+ this .contextRunner .withUserConfiguration (MultipleSpanExporterConfiguration .class ).run ((context ) -> {
178
+ assertThat (context .getBeansOfType (SpanExporter .class )).hasSize (2 );
179
+ assertThat (context ).hasBean ("spanExporter1" );
180
+ assertThat (context ).hasBean ("spanExporter2" );
181
+ SpanExporters spanExporters = context .getBean (SpanExporters .class );
182
+ assertThat (spanExporters ).hasSize (2 );
183
+ });
184
+ }
185
+
167
186
@ Test
168
187
void shouldAllowMultipleTextMapPropagators () {
169
188
this .contextRunner .withUserConfiguration (CustomConfiguration .class ).run ((context ) -> {
@@ -228,15 +247,6 @@ void shouldSupplyW3CPropagationWithoutBaggageWhenDisabled() {
228
247
});
229
248
}
230
249
231
- private List <TextMapPropagator > getInjectors (TextMapPropagator propagator ) {
232
- assertThat (propagator ).as ("propagator" ).isNotNull ();
233
- if (propagator instanceof CompositeTextMapPropagator compositePropagator ) {
234
- return compositePropagator .getInjectors ().stream ().toList ();
235
- }
236
- fail ("Expected CompositeTextMapPropagator, found %s" .formatted (propagator .getClass ()));
237
- throw new AssertionError ("Unreachable" );
238
- }
239
-
240
250
@ Test
241
251
void shouldCustomizeSdkTracerProvider () {
242
252
this .contextRunner .withUserConfiguration (SdkTracerProviderCustomizationConfiguration .class ).run ((context ) -> {
@@ -255,6 +265,15 @@ void defaultSpanProcessorShouldUseMeterProviderIfAvailable() {
255
265
});
256
266
}
257
267
268
+ private List <TextMapPropagator > getInjectors (TextMapPropagator propagator ) {
269
+ assertThat (propagator ).as ("propagator" ).isNotNull ();
270
+ if (propagator instanceof CompositeTextMapPropagator compositePropagator ) {
271
+ return compositePropagator .getInjectors ().stream ().toList ();
272
+ }
273
+ fail ("Expected CompositeTextMapPropagator, found %s" .formatted (propagator .getClass ()));
274
+ throw new AssertionError ("Unreachable" );
275
+ }
276
+
258
277
@ Configuration (proxyBeanMethods = false )
259
278
private static class MeterProviderConfiguration {
260
279
@@ -278,6 +297,21 @@ SpanProcessor customSpanProcessor() {
278
297
279
298
}
280
299
300
+ @ Configuration (proxyBeanMethods = false )
301
+ private static class MultipleSpanExporterConfiguration {
302
+
303
+ @ Bean
304
+ SpanExporter spanExporter1 () {
305
+ return new DummySpanExporter ();
306
+ }
307
+
308
+ @ Bean
309
+ SpanExporter spanExporter2 () {
310
+ return new DummySpanExporter ();
311
+ }
312
+
313
+ }
314
+
281
315
@ Configuration (proxyBeanMethods = false )
282
316
private static class CustomConfiguration {
283
317
@@ -286,6 +320,11 @@ SpanProcessors customSpanProcessors() {
286
320
return SpanProcessors .of (mock (SpanProcessor .class ));
287
321
}
288
322
323
+ @ Bean
324
+ SpanExporters customSpanExporters () {
325
+ return SpanExporters .of (new DummySpanExporter ());
326
+ }
327
+
289
328
@ Bean
290
329
io .micrometer .tracing .Tracer customMicrometerTracer () {
291
330
return mock (io .micrometer .tracing .Tracer .class );
@@ -381,4 +420,23 @@ SdkTracerProviderBuilderCustomizer sdkTracerProviderBuilderCustomizerTwo() {
381
420
382
421
}
383
422
423
+ private static class DummySpanExporter implements SpanExporter {
424
+
425
+ @ Override
426
+ public CompletableResultCode export (Collection <SpanData > spans ) {
427
+ return CompletableResultCode .ofSuccess ();
428
+ }
429
+
430
+ @ Override
431
+ public CompletableResultCode flush () {
432
+ return CompletableResultCode .ofSuccess ();
433
+ }
434
+
435
+ @ Override
436
+ public CompletableResultCode shutdown () {
437
+ return CompletableResultCode .ofSuccess ();
438
+ }
439
+
440
+ }
441
+
384
442
}
0 commit comments