diff --git a/.cursor/rules/e2e_tests.mdc b/.cursor/rules/e2e_tests.mdc index 1785e61b5c1..4063c007838 100644 --- a/.cursor/rules/e2e_tests.mdc +++ b/.cursor/rules/e2e_tests.mdc @@ -74,8 +74,10 @@ it. Gradle runs the two in parallel. customizes, and that the OpenTelemetry starter instruments, so it adds or replaces trace headers on the requests a test sends. Build one outside the context. - Sentry exports OpenTelemetry spans in batches every 5 seconds. In-process, flush the tracer - provider from the server's hook. With the agent this isn't possible, so each test waits for a - batch and negative checks wait at least 6 seconds. + provider from the server's hook. With the agent this isn't possible, so set + `OTEL_BSP_SCHEDULE_DELAY` on the app to shorten the batch delay, and make negative checks wait + well past it. The Boot 2 and Boot 3 agent suites don't set it yet: their tests wait 5 seconds + for a batch and their negative checks wait 6. - Sentry is global, so a second live Spring context in an OpenTelemetry suite takes it over. Keep one live context per JVM (`@DirtiesContext` when a test needs its own). - The async profiler rejects a traces path with a `.` anywhere in its absolute form. Put the path diff --git a/CHANGELOG.md b/CHANGELOG.md index 771b47adf25..9a612c24019 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Support Navigation 3 integration for multi-Activity and multi-Fragment applications, where each Activity or Fragment has its own `SentryNavEffect` ([#6305](https://github.com/getsentry/sentry-java/pull/6305)) - See the [Navigation for Android docs](https://docs.sentry.io/platforms/android/integrations/navigation/#supported-setups) for a detailed list of supported vs unsupported app setups. +- The OpenTelemetry agent now honors `OTEL_BSP_SCHEDULE_DELAY` (`otel.bsp.schedule.delay`) for how often it sends spans to Sentry, instead of always waiting 5 seconds ([#6388](https://github.com/getsentry/sentry-java/pull/6388)) ### Fixes diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java index 5f29f0289a2..e11ae4c72b3 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java +++ b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java @@ -5,11 +5,13 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder; import io.sentry.InitPriority; import io.sentry.Sentry; import io.sentry.SentryOptions; import io.sentry.internal.ManifestVersionReader; import io.sentry.protocol.SdkVersion; +import java.time.Duration; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; @@ -106,7 +108,16 @@ private SdkTracerProviderBuilder configureSdkTracerProvider( return tracerProvider .setSampler(new SentrySampler()) .addSpanProcessor(new OtelSentrySpanProcessor()) - .addSpanProcessor(BatchSpanProcessor.builder(new SentrySpanExporter()).build()); + .addSpanProcessor(createBatchSpanProcessor(config)); + } + + private BatchSpanProcessor createBatchSpanProcessor(ConfigProperties config) { + final BatchSpanProcessorBuilder builder = BatchSpanProcessor.builder(new SentrySpanExporter()); + final @Nullable Duration scheduleDelay = config.getDuration("otel.bsp.schedule.delay"); + if (scheduleDelay != null) { + builder.setScheduleDelay(scheduleDelay); + } + return builder.build(); } private Map getDefaultProperties() { diff --git a/sentry-spring-boot-4/src/integrationTestOtelAgent/kotlin/io/sentry/spring/boot4/otelagentintegrationtest/AgentApp.kt b/sentry-spring-boot-4/src/integrationTestOtelAgent/kotlin/io/sentry/spring/boot4/otelagentintegrationtest/AgentApp.kt index 82961625b3d..d7a7084a74c 100644 --- a/sentry-spring-boot-4/src/integrationTestOtelAgent/kotlin/io/sentry/spring/boot4/otelagentintegrationtest/AgentApp.kt +++ b/sentry-spring-boot-4/src/integrationTestOtelAgent/kotlin/io/sentry/spring/boot4/otelagentintegrationtest/AgentApp.kt @@ -40,6 +40,8 @@ object AgentApp { "SENTRY_PROFILE_LIFECYCLE" to "TRACE", "SENTRY_PROFILING_TRACES_DIR_PATH" to "${System.getProperty("java.io.tmpdir")}/sentry-integration-test/profiling-traces", + // Tests wait for Sentry's span batches, which are 5 seconds apart by default. + "OTEL_BSP_SCHEDULE_DELAY" to "100ms", "OTEL_TRACES_EXPORTER" to "none", "OTEL_METRICS_EXPORTER" to "none", "OTEL_LOGS_EXPORTER" to "none", diff --git a/sentry-spring-boot-4/src/integrationTestOtelAgent/kotlin/io/sentry/spring/boot4/otelagentintegrationtest/DistributedTracingIntegrationTest.kt b/sentry-spring-boot-4/src/integrationTestOtelAgent/kotlin/io/sentry/spring/boot4/otelagentintegrationtest/DistributedTracingIntegrationTest.kt index 353e6d62fd8..ad7025146b6 100644 --- a/sentry-spring-boot-4/src/integrationTestOtelAgent/kotlin/io/sentry/spring/boot4/otelagentintegrationtest/DistributedTracingIntegrationTest.kt +++ b/sentry-spring-boot-4/src/integrationTestOtelAgent/kotlin/io/sentry/spring/boot4/otelagentintegrationtest/DistributedTracingIntegrationTest.kt @@ -47,8 +47,8 @@ class DistributedTracingIntegrationTest : IntegrationTest() { ) assertThat(status).isEqualTo(500) - // Longer than the 5 seconds the app's spans can wait for their batch to be exported. - server.assertNoEnvelope(millis = 6_000) { isForRequest(it, id) } + // Ten times the app's batch delay, so the request's spans would have been exported. + server.assertNoEnvelope(millis = 1_000) { isForRequest(it, id) } } @Test