1212import io .opentelemetry .api .trace .Tracer ;
1313import io .opentelemetry .context .Scope ;
1414import io .opentelemetry .sdk .OpenTelemetrySdk ;
15- import io .opentelemetry .sdk .autoconfigure .spi .internal .DefaultConfigProperties ;
15+ import io .opentelemetry .sdk .autoconfigure .AutoConfiguredOpenTelemetrySdk ;
16+ import io .opentelemetry .sdk .autoconfigure .AutoConfiguredOpenTelemetrySdkBuilder ;
1617import io .opentelemetry .sdk .testing .exporter .InMemorySpanExporter ;
1718import io .opentelemetry .sdk .trace .ReadableSpan ;
18- import io .opentelemetry .sdk .trace .SdkTracerProvider ;
19- import io .opentelemetry .sdk .trace .SpanProcessor ;
2019import io .opentelemetry .sdk .trace .data .SpanData ;
21- import io .opentelemetry .sdk .trace .export .SimpleSpanProcessor ;
20+ import io .opentelemetry .sdk .trace .export .SpanExporter ;
2221import io .opentelemetry .semconv .incubating .CodeIncubatingAttributes ;
2322import java .time .Duration ;
2423import java .time .Instant ;
@@ -39,43 +38,57 @@ private static long msToNs(int ms) {
3938 @ Test
4039 void durationAndFiltering () {
4140 // on duration threshold
42- checkSpanWithStackTrace (span -> true , "1ms" , msToNs (1 ));
41+ checkSpanWithStackTrace ("1ms" , msToNs (1 ));
4342 // over duration threshold
44- checkSpanWithStackTrace (span -> true , "1ms" , msToNs (2 ));
43+ checkSpanWithStackTrace ("1ms" , msToNs (2 ));
4544 // under duration threshold
46- checkSpanWithoutStackTrace (span -> true , "2ms" , msToNs (1 ));
45+ checkSpanWithoutStackTrace (YesPredicate . class , "2ms" , msToNs (1 ));
4746
4847 // filtering out span
49- checkSpanWithoutStackTrace (span -> false , "1ms" , 20 );
48+ checkSpanWithoutStackTrace (NoPredicate .class , "1ms" , 20 );
49+ }
50+
51+ public static class YesPredicate implements Predicate <ReadableSpan > {
52+
53+ @ Override
54+ public boolean test (ReadableSpan readableSpan ) {
55+ return true ;
56+ }
57+ }
58+
59+ public static class NoPredicate implements Predicate <ReadableSpan > {
60+ @ Override
61+ public boolean test (ReadableSpan readableSpan ) {
62+ return false ;
63+ }
5064 }
5165
5266 @ Test
5367 void defaultConfig () {
5468 long expectedDefault = msToNs (5 );
55- checkSpanWithStackTrace (span -> true , null , expectedDefault );
56- checkSpanWithStackTrace (span -> true , null , expectedDefault + 1 );
57- checkSpanWithoutStackTrace (span -> true , null , expectedDefault - 1 );
69+ checkSpanWithStackTrace (null , expectedDefault );
70+ checkSpanWithStackTrace (null , expectedDefault + 1 );
71+ checkSpanWithoutStackTrace (YesPredicate . class , null , expectedDefault - 1 );
5872 }
5973
6074 @ Test
6175 void disabledConfig () {
62- checkSpanWithoutStackTrace (span -> true , "-1" , 5 );
76+ checkSpanWithoutStackTrace (YesPredicate . class , "-1" , 5 );
6377 }
6478
6579 @ Test
6680 void spanWithExistingStackTrace () {
6781 checkSpan (
68- span -> true ,
82+ YesPredicate . class ,
6983 "1ms" ,
7084 Duration .ofMillis (1 ).toNanos (),
7185 sb -> sb .setAttribute (CodeIncubatingAttributes .CODE_STACKTRACE , "hello" ),
7286 stacktrace -> assertThat (stacktrace ).isEqualTo ("hello" ));
7387 }
7488
75- private static void checkSpanWithStackTrace (
76- Predicate <ReadableSpan > filterPredicate , String minDurationString , long spanDurationNanos ) {
89+ private static void checkSpanWithStackTrace (String minDurationString , long spanDurationNanos ) {
7790 checkSpan (
78- filterPredicate ,
91+ YesPredicate . class ,
7992 minDurationString ,
8093 spanDurationNanos ,
8194 Function .identity (),
@@ -86,43 +99,49 @@ private static void checkSpanWithStackTrace(
8699 }
87100
88101 private static void checkSpanWithoutStackTrace (
89- Predicate <ReadableSpan > filterPredicate , String minDurationString , long spanDurationNanos ) {
102+ Class <? extends Predicate <?>> predicateClass , String minDurationString ,
103+ long spanDurationNanos ) {
90104 checkSpan (
91- filterPredicate ,
105+ predicateClass ,
92106 minDurationString ,
93107 spanDurationNanos ,
94108 Function .identity (),
95109 (stackTrace ) -> assertThat (stackTrace ).describedAs ("no stack trace expected" ).isNull ());
96110 }
97111
98112 private static void checkSpan (
99- Predicate <ReadableSpan > filterPredicate ,
113+ Class <? extends Predicate <?>> predicateClass ,
100114 String minDurationString ,
101115 long spanDurationNanos ,
102116 Function <SpanBuilder , SpanBuilder > customizeSpanBuilder ,
103117 Consumer <String > stackTraceCheck ) {
104118
105- // they must be re-created as they are shutdown when the span processor is closed
119+ // must be re-created on every test as exporter is shut down on span processor close
106120 InMemorySpanExporter spansExporter = InMemorySpanExporter .create ();
107- SpanProcessor exportProcessor = SimpleSpanProcessor .create (spansExporter );
108121
109- Map <String , String > configMap = new HashMap <>();
110- if (minDurationString != null ) {
111- configMap .put ("otel.java.experimental.span-stacktrace.min.duration" , minDurationString );
112- }
113- long minDuration =
114- StackTraceAutoConfig .getMinDuration (DefaultConfigProperties .createFromMap (configMap ));
115-
116- StackTraceSpanProcessor processor = new StackTraceSpanProcessor (minDuration , filterPredicate );
117-
118- try (OpenTelemetrySdk sdk =
119- OpenTelemetrySdk .builder ()
120- .setTracerProvider (
121- SdkTracerProvider .builder ()
122- .addSpanProcessor (processor )
123- .addSpanProcessor (exportProcessor )
124- .build ())
125- .build ()) {
122+ AutoConfiguredOpenTelemetrySdkBuilder sdkBuilder = AutoConfiguredOpenTelemetrySdk .builder ();
123+ sdkBuilder .addPropertiesSupplier (() -> {
124+ Map <String , String > configMap = new HashMap <>();
125+
126+ configMap .put ("otel.metrics.exporter" , "none" );
127+ configMap .put ("otel.traces.exporter" , "logging" );
128+ configMap .put ("otel.logs.exporter" , "none" );
129+
130+ if (minDurationString != null ) {
131+ configMap .put ("otel.java.experimental.span-stacktrace.min.duration" , minDurationString );
132+ }
133+ if (predicateClass != null ) {
134+ configMap .put ("otel.java.experimental.span-stacktrace.filter" , predicateClass .getName ());
135+ }
136+ return configMap ;
137+ });
138+ // duplicate export to our in-memory span exporter
139+ sdkBuilder .addSpanExporterCustomizer (
140+ (exporter , config ) -> SpanExporter .composite (exporter , spansExporter ));
141+
142+ new StackTraceAutoConfig ().customize (sdkBuilder );
143+
144+ try (OpenTelemetrySdk sdk = sdkBuilder .build ().getOpenTelemetrySdk ()) {
126145
127146 Tracer tracer = sdk .getTracer ("test" );
128147
0 commit comments