Skip to content

Commit bd36eea

Browse files
SylvainJugeCopilot
andauthored
make span stacktrace ignore inferred spans by default (#2803)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 225116e commit bd36eea

3 files changed

Lines changed: 35 additions & 11 deletions

File tree

span-stacktrace/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ dependencies {
1515

1616
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
1717
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
18-
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
1918
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator")
2019
compileOnly("io.opentelemetry.instrumentation:opentelemetry-declarative-config-bridge")
2120
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
@@ -30,4 +29,7 @@ dependencies {
3029
testCompileOnly("com.google.auto.service:auto-service-annotations")
3130

3231
testImplementation("io.opentelemetry:opentelemetry-exporter-logging")
32+
33+
// allows to test inferred spans that should be filtered-out
34+
testCompileOnly(project(":inferred-spans"))
3335
}

span-stacktrace/src/main/java/io/opentelemetry/contrib/stacktrace/StackTraceSpanProcessor.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ public void onEnding(ReadWriteSpan span) {
5959
if (!filterPredicate.test(span)) {
6060
return;
6161
}
62+
63+
// Inferred spans are generated from sampling, so this span processor is not actually called
64+
// when the span is active, and stack trace collection should be skipped.
65+
//
66+
// We only get such spans when the inferred spans processor executes before this span
67+
// processor, which may be considered a configuration error.
68+
boolean isInferred = span.getInstrumentationScopeInfo().getName().equals("inferred-spans");
69+
if (isInferred) {
70+
return;
71+
}
72+
6273
span.setAttribute(CodeAttributes.CODE_STACKTRACE, generateSpanEndStacktrace());
6374
}
6475

span-stacktrace/src/test/java/io/opentelemetry/contrib/stacktrace/StackTraceSpanProcessorTest.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.opentelemetry.api.trace.SpanBuilder;
1313
import io.opentelemetry.api.trace.Tracer;
1414
import io.opentelemetry.context.Scope;
15+
import io.opentelemetry.contrib.inferredspans.InferredSpansProcessor;
1516
import io.opentelemetry.sdk.OpenTelemetrySdk;
1617
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
1718
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
@@ -49,10 +50,10 @@ void durationAndFiltering() {
4950
// over duration threshold
5051
checkSpanWithStackTrace("1ms", msToNs(2));
5152
// under duration threshold
52-
checkSpanWithoutStackTrace(YesPredicate.class, "2ms", msToNs(1));
53+
checkSpanWithoutStackTrace(YesPredicate.class, "2ms", msToNs(1), "test");
5354

5455
// filtering out span
55-
checkSpanWithoutStackTrace(NoPredicate.class, "1ms", msToNs(20));
56+
checkSpanWithoutStackTrace(NoPredicate.class, "1ms", msToNs(20), "test");
5657
}
5758

5859
public static class YesPredicate implements Predicate<ReadableSpan> {
@@ -75,12 +76,12 @@ void defaultConfig() {
7576
long expectedDefault = msToNs(5);
7677
checkSpanWithStackTrace(null, expectedDefault);
7778
checkSpanWithStackTrace(null, expectedDefault + 1);
78-
checkSpanWithoutStackTrace(YesPredicate.class, null, expectedDefault - 1);
79+
checkSpanWithoutStackTrace(YesPredicate.class, null, expectedDefault - 1, "test");
7980
}
8081

8182
@Test
8283
void disabledConfig() {
83-
checkSpanWithoutStackTrace(YesPredicate.class, "-1", 5);
84+
checkSpanWithoutStackTrace(YesPredicate.class, "-1", 5, "test");
8485
}
8586

8687
@Test
@@ -90,7 +91,13 @@ void spanWithExistingStackTrace() {
9091
"1ms",
9192
Duration.ofMillis(1).toNanos(),
9293
sb -> sb.setAttribute(CodeAttributes.CODE_STACKTRACE, "hello"),
93-
stacktrace -> assertThat(stacktrace).isEqualTo("hello"));
94+
stacktrace -> assertThat(stacktrace).isEqualTo("hello"),
95+
"test");
96+
}
97+
98+
@Test
99+
void spanFromInferredSpansIgnored() {
100+
checkSpanWithoutStackTrace(null, "1ms", msToNs(1), InferredSpansProcessor.TRACER_NAME);
94101
}
95102

96103
private static void checkSpanWithStackTrace(String minDurationString, long spanDurationNanos) {
@@ -102,27 +109,31 @@ private static void checkSpanWithStackTrace(String minDurationString, long spanD
102109
(stackTrace) ->
103110
assertThat(stackTrace)
104111
.describedAs("span stack trace should contain caller class name")
105-
.contains(StackTraceSpanProcessorTest.class.getCanonicalName()));
112+
.contains(StackTraceSpanProcessorTest.class.getCanonicalName()),
113+
"test");
106114
}
107115

108116
private static void checkSpanWithoutStackTrace(
109117
Class<? extends Predicate<?>> predicateClass,
110118
String minDurationString,
111-
long spanDurationNanos) {
119+
long spanDurationNanos,
120+
String scopeName) {
112121
checkSpan(
113122
predicateClass,
114123
minDurationString,
115124
spanDurationNanos,
116125
Function.identity(),
117-
(stackTrace) -> assertThat(stackTrace).describedAs("no stack trace expected").isNull());
126+
(stackTrace) -> assertThat(stackTrace).describedAs("no stack trace expected").isNull(),
127+
scopeName);
118128
}
119129

120130
private static void checkSpan(
121131
Class<? extends Predicate<?>> predicateClass,
122132
String minDurationString,
123133
long spanDurationNanos,
124134
Function<SpanBuilder, SpanBuilder> customizeSpanBuilder,
125-
Consumer<String> stackTraceCheck) {
135+
Consumer<String> stackTraceCheck,
136+
String scopeName) {
126137

127138
// must be re-created on every test as exporter is shut down on span processor close
128139
InMemorySpanExporter spansExporter = InMemorySpanExporter.create();
@@ -153,7 +164,7 @@ private static void checkSpan(
153164

154165
try (OpenTelemetrySdk sdk = sdkBuilder.build().getOpenTelemetrySdk()) {
155166

156-
Tracer tracer = sdk.getTracer("test");
167+
Tracer tracer = sdk.getTracer(scopeName);
157168

158169
Instant start = Instant.now();
159170
Instant end = start.plusNanos(spanDurationNanos);

0 commit comments

Comments
 (0)