Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion span-stacktrace/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ dependencies {

compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator")
compileOnly("io.opentelemetry.instrumentation:opentelemetry-declarative-config-bridge")
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
Expand All @@ -30,4 +29,7 @@ dependencies {
testCompileOnly("com.google.auto.service:auto-service-annotations")

testImplementation("io.opentelemetry:opentelemetry-exporter-logging")

// allows to test inferred spans that should be filtered-out
testCompileOnly(project(":inferred-spans"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ public void onEnding(ReadWriteSpan span) {
if (!filterPredicate.test(span)) {
return;
}

// Inferred spans are generated from sampling, so this span processor is not actually called
// when the span is active, and stack trace collection should be skipped.
//
// We only get such spans when the inferred spans processor executes before this span
// processor, which may be considered a configuration error.
boolean isInferred = span.getInstrumentationScopeInfo().getName().equals("inferred-spans");
if (isInferred) {
Comment on lines +68 to +69
return;
}

span.setAttribute(CodeAttributes.CODE_STACKTRACE, generateSpanEndStacktrace());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
import io.opentelemetry.contrib.inferredspans.InferredSpansProcessor;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
Expand Down Expand Up @@ -49,10 +50,10 @@ void durationAndFiltering() {
// over duration threshold
checkSpanWithStackTrace("1ms", msToNs(2));
// under duration threshold
checkSpanWithoutStackTrace(YesPredicate.class, "2ms", msToNs(1));
checkSpanWithoutStackTrace(YesPredicate.class, "2ms", msToNs(1), "test");

// filtering out span
checkSpanWithoutStackTrace(NoPredicate.class, "1ms", msToNs(20));
checkSpanWithoutStackTrace(NoPredicate.class, "1ms", msToNs(20), "test");
}

public static class YesPredicate implements Predicate<ReadableSpan> {
Expand All @@ -75,12 +76,12 @@ void defaultConfig() {
long expectedDefault = msToNs(5);
checkSpanWithStackTrace(null, expectedDefault);
checkSpanWithStackTrace(null, expectedDefault + 1);
checkSpanWithoutStackTrace(YesPredicate.class, null, expectedDefault - 1);
checkSpanWithoutStackTrace(YesPredicate.class, null, expectedDefault - 1, "test");
}

@Test
void disabledConfig() {
checkSpanWithoutStackTrace(YesPredicate.class, "-1", 5);
checkSpanWithoutStackTrace(YesPredicate.class, "-1", 5, "test");
}

@Test
Expand All @@ -90,7 +91,13 @@ void spanWithExistingStackTrace() {
"1ms",
Duration.ofMillis(1).toNanos(),
sb -> sb.setAttribute(CodeAttributes.CODE_STACKTRACE, "hello"),
stacktrace -> assertThat(stacktrace).isEqualTo("hello"));
stacktrace -> assertThat(stacktrace).isEqualTo("hello"),
"test");
}

@Test
void spanFromInferredSpansIgnored() {
checkSpanWithoutStackTrace(null, "1ms", msToNs(1), InferredSpansProcessor.TRACER_NAME);
}

private static void checkSpanWithStackTrace(String minDurationString, long spanDurationNanos) {
Expand All @@ -102,27 +109,31 @@ private static void checkSpanWithStackTrace(String minDurationString, long spanD
(stackTrace) ->
assertThat(stackTrace)
.describedAs("span stack trace should contain caller class name")
.contains(StackTraceSpanProcessorTest.class.getCanonicalName()));
.contains(StackTraceSpanProcessorTest.class.getCanonicalName()),
"test");
}

private static void checkSpanWithoutStackTrace(
Class<? extends Predicate<?>> predicateClass,
String minDurationString,
long spanDurationNanos) {
long spanDurationNanos,
String scopeName) {
Comment on lines 116 to +120
checkSpan(
predicateClass,
minDurationString,
spanDurationNanos,
Function.identity(),
(stackTrace) -> assertThat(stackTrace).describedAs("no stack trace expected").isNull());
(stackTrace) -> assertThat(stackTrace).describedAs("no stack trace expected").isNull(),
scopeName);
}

private static void checkSpan(
Class<? extends Predicate<?>> predicateClass,
String minDurationString,
long spanDurationNanos,
Function<SpanBuilder, SpanBuilder> customizeSpanBuilder,
Consumer<String> stackTraceCheck) {
Consumer<String> stackTraceCheck,
String scopeName) {

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

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

Tracer tracer = sdk.getTracer("test");
Tracer tracer = sdk.getTracer(scopeName);

Instant start = Instant.now();
Instant end = start.plusNanos(spanDurationNanos);
Expand Down
Loading