Skip to content

Commit 51a5207

Browse files
committed
test(opentelemetry): Add an end-to-end test of the OTLP event linking
OtlpEndToEndTest captures a message, a log and a metric inside an OpenTelemetry span with OpenTelemetryOtlpEventProcessor installed, and checks what reaches MockSentryServer: the event carries the span's trace and span IDs, and the log and the metric arrive. It ports the OTLP-specific part of the console OTLP sample's system test, which never checked the link. The sample's other assertions are the console sample's, which SentryEndToEndTest covers. The sample has no system test left, so it comes off the system-test runner and the backend workflow, whose base row moves to the Spring Boot 4 OTLP sample, and drops the Kotlin plugin it only needed for the test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent db37349 commit 51a5207

7 files changed

Lines changed: 68 additions & 161 deletions

File tree

‎.github/workflows/system-tests-backend.yml‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,9 @@ jobs:
2424
strategy:
2525
fail-fast: false
2626
matrix:
27-
sample: [ "sentry-samples-console-otlp" ]
27+
sample: [ "sentry-samples-spring-boot-4-otlp" ]
2828
agent: [ "false" ]
2929
agent-auto-init: [ "true" ]
30-
include:
31-
- sample: "sentry-samples-spring-boot-4-otlp"
32-
agent: "false"
33-
agent-auto-init: "true"
3430
steps:
3531
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
3632
with:

‎sentry-opentelemetry/sentry-opentelemetry-otlp/build.gradle.kts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ dependencies {
3434
testImplementation(projects.sentryTestSupport)
3535
testImplementation(kotlin(Config.kotlinStdLib))
3636
testImplementation(libs.awaitility.kotlin)
37+
testImplementation(libs.google.truth)
3738
testImplementation(libs.kotlin.test.junit)
3839
testImplementation(libs.mockito.kotlin)
3940

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package io.sentry.opentelemetry.otlp
2+
3+
import com.google.common.truth.Truth.assertThat
4+
import io.opentelemetry.sdk.OpenTelemetrySdk
5+
import io.opentelemetry.sdk.trace.SdkTracerProvider
6+
import io.sentry.Sentry
7+
import io.sentry.test.MockSentryServer
8+
import io.sentry.test.event
9+
import io.sentry.test.hasMetric
10+
import io.sentry.test.initForTest
11+
import io.sentry.test.logs
12+
import io.sentry.test.metrics
13+
import kotlin.test.AfterTest
14+
import kotlin.test.Test
15+
16+
/**
17+
* An app that exports its OpenTelemetry spans over OTLP and reports everything else to Sentry, as
18+
* the console OTLP sample does.
19+
*/
20+
class OtlpEndToEndTest {
21+
private val server = MockSentryServer()
22+
private val openTelemetry =
23+
OpenTelemetrySdk.builder().setTracerProvider(SdkTracerProvider.builder().build()).build()
24+
25+
@AfterTest
26+
fun teardown() {
27+
Sentry.close()
28+
openTelemetry.close()
29+
server.close()
30+
}
31+
32+
@Test
33+
fun `an event inside an OpenTelemetry span is linked to it`() {
34+
initForTest {
35+
it.dsn = server.dsn
36+
it.logs.isEnabled = true
37+
it.addEventProcessor(OpenTelemetryOtlpEventProcessor())
38+
}
39+
40+
val span = openTelemetry.getTracer("otlp-end-to-end-test").spanBuilder("otelSpan").startSpan()
41+
span.makeCurrent().use {
42+
Sentry.captureMessage("this message is connected to the outerSpan")
43+
Sentry.logger().error("Some error log message")
44+
Sentry.metrics().count("invocations")
45+
}
46+
span.end()
47+
Sentry.flush(5000)
48+
49+
val event =
50+
server
51+
.awaitEnvelope {
52+
it.event()?.message?.formatted == "this message is connected to the outerSpan"
53+
}
54+
.event()!!
55+
// The span's trace goes over OTLP, so the event points to it rather than to a Sentry span.
56+
val trace = event.contexts.trace!!
57+
assertThat(trace.traceId.toString()).isEqualTo(span.spanContext.traceId)
58+
assertThat(trace.spanId.toString()).isEqualTo(span.spanContext.spanId)
59+
60+
val logs = server.awaitEnvelope { it.logs() != null }.logs()!!
61+
assertThat(logs.items.map { it.body }).contains("Some error log message")
62+
63+
val metrics = server.awaitEnvelope { it.metrics() != null }.metrics()!!
64+
assertThat(metrics.hasMetric("invocations", "counter", 1.0)).isTrue()
65+
}
66+
}
Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,18 @@
1-
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2-
31
plugins {
42
java
53
application
6-
alias(libs.plugins.kotlin.jvm)
74
alias(libs.plugins.gradle.versions)
85
alias(libs.plugins.shadow)
9-
id("io.sentry.systemtest")
106
}
117

128
application { mainClass.set("io.sentry.samples.console.Main") }
139

14-
tasks.withType<KotlinCompile>().configureEach {
15-
kotlin {
16-
compilerOptions.freeCompilerArgs = listOf("-Xjsr305=strict")
17-
}
18-
}
19-
2010
dependencies {
2111
implementation(projects.sentryOpentelemetry.sentryOpentelemetryOtlp)
2212
implementation(projects.sentryAsyncProfiler)
2313
implementation(libs.otel.semconv)
2414
implementation(libs.otel.semconv.incubating)
2515
implementation(libs.otel.exporter.logging)
26-
27-
testImplementation(kotlin(Config.kotlinStdLib))
28-
testImplementation(projects.sentry)
29-
testImplementation(projects.sentrySystemTestSupport)
30-
testImplementation(libs.kotlin.test.junit)
31-
testImplementation(libs.slf4j.api)
32-
testImplementation(libs.slf4j.jdk14)
3316
}
3417

3518
// Configure the Shadow JAR (executable JAR with all dependencies)
@@ -48,22 +31,3 @@ tasks.jar {
4831

4932
// Fix the startScripts task dependency
5033
tasks.startScripts { dependsOn(tasks.shadowJar) }
51-
52-
tasks.register<Test>("systemTest").configure {
53-
group = "verification"
54-
description = "Runs the System tests"
55-
56-
val test = project.extensions.getByType<SourceSetContainer>()["test"]
57-
testClassesDirs = test.output.classesDirs
58-
classpath = test.runtimeClasspath
59-
60-
maxParallelForks = 1
61-
62-
filter { includeTestsMatching("io.sentry.systemtest*") }
63-
}
64-
65-
tasks.named("test").configure {
66-
require(this is Test)
67-
68-
filter { excludeTestsMatching("io.sentry.systemtest.*") }
69-
}

‎sentry-samples/sentry-samples-console-otlp/src/test/kotlin/io/sentry/DummyTest.kt‎

Lines changed: 0 additions & 12 deletions
This file was deleted.

‎sentry-samples/sentry-samples-console-otlp/src/test/kotlin/io/sentry/systemtest/ConsoleApplicationSystemTest.kt‎

Lines changed: 0 additions & 107 deletions
This file was deleted.

‎test/system-test-runner.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,6 @@ def get_available_modules(self) -> List[ModuleConfig]:
826826
"""Get list of all available test modules."""
827827
return [
828828
ModuleConfig("sentry-samples-spring-boot-4-otlp", "false", "true", "false"),
829-
ModuleConfig("sentry-samples-console-otlp", "false", "true", "false"),
830829
]
831830

832831
def _find_module_number(self, module_name: str, agent: str, auto_init: str) -> int:

0 commit comments

Comments
 (0)