From 187a4764aa1a6a6cd95dccdd535d4c902faac579 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 28 Nov 2024 06:20:55 +0100 Subject: [PATCH 01/13] bump OTel to 2.10.0 --- buildSrc/src/main/java/Config.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index dd62348342..5ec54e22d6 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -156,11 +156,11 @@ object Config { val sentryNativeNdk = "io.sentry:sentry-native-ndk:0.7.14" object OpenTelemetry { - val otelVersion = "1.41.0" + val otelVersion = "1.44.1" val otelAlphaVersion = "$otelVersion-alpha" - val otelInstrumentationVersion = "2.7.0" + val otelInstrumentationVersion = "2.10.0" val otelInstrumentationAlphaVersion = "$otelInstrumentationVersion-alpha" - val otelSemanticConvetionsVersion = "1.25.0-alpha" // check https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/dependencyManagement/build.gradle.kts#L49 for release version above to find a compatible version + val otelSemanticConvetionsVersion = "1.28.0-alpha" // check https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/dependencyManagement/build.gradle.kts#L49 for release version above to find a compatible version val otelSdk = "io.opentelemetry:opentelemetry-sdk:$otelVersion" val otelSemconv = "io.opentelemetry.semconv:opentelemetry-semconv:$otelSemanticConvetionsVersion" From 9a5dfc0ed525a681c1dd2b8d6de7c80f2b05a8ee Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 28 Nov 2024 12:52:23 +0100 Subject: [PATCH 02/13] support DB_QUERY_TEXT --- .../opentelemetry/SpanDescriptionExtractor.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SpanDescriptionExtractor.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SpanDescriptionExtractor.java index 56acea238b..2047bd37f8 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SpanDescriptionExtractor.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SpanDescriptionExtractor.java @@ -96,7 +96,14 @@ private OtelSpanInfo descriptionForHttpMethod( private OtelSpanInfo descriptionForDbSystem(final @NotNull SpanData otelSpan) { final @NotNull Attributes attributes = otelSpan.getAttributes(); @Nullable String dbStatement = attributes.get(DbIncubatingAttributes.DB_STATEMENT); - @NotNull String description = dbStatement != null ? dbStatement : otelSpan.getName(); - return new OtelSpanInfo("db", description, TransactionNameSource.TASK); + if (dbStatement != null) { + return new OtelSpanInfo("db", dbStatement, TransactionNameSource.TASK); + } + @Nullable String dbQueryText = attributes.get(DbIncubatingAttributes.DB_QUERY_TEXT); + if (dbQueryText != null) { + return new OtelSpanInfo("db", dbQueryText, TransactionNameSource.TASK); + } + + return new OtelSpanInfo("db", otelSpan.getName(), TransactionNameSource.TASK); } } From c1b125755315d7ea2bbfa05e42a4aae6dceebaac Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 28 Nov 2024 12:53:04 +0100 Subject: [PATCH 03/13] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0c11a9cb3..2dab3467c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - Extract OpenTelemetry `URL_PATH` span attribute into description ([#3933](https://github.com/getsentry/sentry-java/pull/3933)) +### Dependencies + +- Bump OpenTelemetry to 1.44.1, OpenTelemetry Java Agent to 2.10.0 and Semantic Conventions to 1.28.0 ([#3935](https://github.com/getsentry/sentry-java/pull/3935)) + ## 8.0.0-beta.3 ### Features From ad9b417d5436b587da689014aa40fba2aa8e0c00 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 28 Nov 2024 13:59:12 +0100 Subject: [PATCH 04/13] change bom version for otel --- buildSrc/src/main/java/Config.kt | 1 + .../build.gradle.kts | 2 +- .../build.gradle.kts | 6 ------ .../build.gradle.kts | 6 ++++++ 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 5ec54e22d6..e6ebe9f193 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -170,6 +170,7 @@ object Config { val otelJavaAgentTooling = "io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:$otelInstrumentationAlphaVersion" val otelExtensionAutoconfigureSpi = "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:$otelVersion" val otelExtensionAutoconfigure = "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:$otelVersion" + val otelInstrumentationBom = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:$otelInstrumentationVersion" } } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts index e0f82ad781..dfa17eb952 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts @@ -71,7 +71,7 @@ dependencies { dependencyManagement { imports { - mavenBom("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.7.0") + mavenBom(Config.Libs.OpenTelemetry.otelInstrumentationBom) } } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts index 2dd6f2574b..fe5dec4415 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts @@ -68,12 +68,6 @@ dependencies { testImplementation(Config.Libs.apolloKotlin) } -dependencyManagement { - imports { - mavenBom("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.7.0") - } -} - configure { test { java.srcDir("src/test/java") diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts index 2eab2bb10e..a7a879f0dd 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts @@ -70,6 +70,12 @@ dependencies { testImplementation("org.apache.httpcomponents:httpclient") } +dependencyManagement { + imports { + mavenBom(Config.Libs.OpenTelemetry.otelInstrumentationBom) + } +} + configure { test { java.srcDir("src/test/java") From df3ae7b16dd46fc3b44dff172326d5d9d373d44c Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 29 Nov 2024 07:24:20 +0100 Subject: [PATCH 05/13] Replace OTel ContextStorage wrapper with ContextStorageProvider --- .../api/sentry-opentelemetry-bootstrap.api | 5 +++++ .../opentelemetry/OtelContextScopesStorage.java | 5 ++--- .../opentelemetry/SentryContextStorageProvider.java | 12 ++++++++++++ .../io.opentelemetry.context.ContextStorageProvider | 1 + 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/SentryContextStorageProvider.java create mode 100644 sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api index 0e061c84c0..38ce3b8803 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api +++ b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api @@ -103,6 +103,11 @@ public final class io/sentry/opentelemetry/SentryContextStorage : io/opentelemet public fun current ()Lio/opentelemetry/context/Context; } +public final class io/sentry/opentelemetry/SentryContextStorageProvider : io/opentelemetry/context/ContextStorageProvider { + public fun ()V + public fun get ()Lio/opentelemetry/context/ContextStorage; +} + public final class io/sentry/opentelemetry/SentryContextWrapper : io/opentelemetry/context/Context { public fun get (Lio/opentelemetry/context/ContextKey;)Ljava/lang/Object; public fun toString ()Ljava/lang/String; diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelContextScopesStorage.java b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelContextScopesStorage.java index cd63187178..143ebb6c16 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelContextScopesStorage.java +++ b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelContextScopesStorage.java @@ -3,7 +3,6 @@ import static io.sentry.opentelemetry.SentryOtelKeys.SENTRY_SCOPES_KEY; import io.opentelemetry.context.Context; -import io.opentelemetry.context.ContextStorage; import io.opentelemetry.context.Scope; import io.sentry.IScopes; import io.sentry.IScopesStorage; @@ -27,8 +26,8 @@ public void init() { * should try to use OTels StorageProvider mechanism instead. */ // ContextStorage.addWrapper((storage) -> new SentryContextStorage(storage)); - ContextStorage.addWrapper( - (storage) -> new SentryContextStorage(new SentryOtelThreadLocalStorage())); + // ContextStorage.addWrapper( + // (storage) -> new SentryContextStorage(new SentryOtelThreadLocalStorage())); } @Override diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/SentryContextStorageProvider.java b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/SentryContextStorageProvider.java new file mode 100644 index 0000000000..42fc8a202d --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/SentryContextStorageProvider.java @@ -0,0 +1,12 @@ +package io.sentry.opentelemetry; + +import io.opentelemetry.context.ContextStorage; +import io.opentelemetry.context.ContextStorageProvider; + +public final class SentryContextStorageProvider implements ContextStorageProvider { + @Override + public ContextStorage get() { + System.out.println("hello from SentryContextStorageProvider"); + return new SentryContextStorage(new SentryOtelThreadLocalStorage()); + } +} diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider new file mode 100644 index 0000000000..87a43eea48 --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/resources/META-INF/services/io.opentelemetry.context.ContextStorageProvider @@ -0,0 +1 @@ +io.sentry.opentelemetry.SentryContextStorageProvider From 96314d99d6055c6d971eb632da3d71e43c54e8a2 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 29 Nov 2024 09:25:10 +0100 Subject: [PATCH 06/13] bump spring boot 3.4 --- buildSrc/src/main/java/Config.kt | 2 +- .../apollo3/SentryApollo3InterceptorTest.kt | 10 ++++---- ...ntryApollo3InterceptorWithVariablesTest.kt | 4 +++- .../apollo/SentryApolloInterceptorTest.kt | 6 +++-- .../okhttp/SentryOkHttpEventListenerTest.kt | 6 +++-- .../okhttp/SentryOkHttpInterceptorTest.kt | 16 +++++++------ .../sentry/openfeign/SentryFeignClientTest.kt | 12 ++++++---- .../SentrySpanRestClientCustomizerTest.kt | 24 ++++++++++++------- .../SentrySpanRestTemplateCustomizerTest.kt | 12 ++++++---- .../SentrySpanWebClientCustomizerTest.kt | 10 ++++---- .../SentrySpanRestTemplateCustomizerTest.kt | 12 ++++++---- .../boot/SentrySpanWebClientCustomizerTest.kt | 10 ++++---- .../api/sentry-test-support.api | 1 + .../src/main/kotlin/io/sentry/Assertions.kt | 2 ++ 14 files changed, 79 insertions(+), 48 deletions(-) diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index e6ebe9f193..5b4e907e29 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -7,7 +7,7 @@ object Config { val kotlinStdLib = "stdlib-jdk8" val springBootVersion = "2.7.5" - val springBoot3Version = "3.3.2" + val springBoot3Version = "3.4.0" val kotlinCompatibleLanguageVersion = "1.4" val composeVersion = "1.5.3" diff --git a/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt b/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt index 3b836f45b9..e5cb93eb3d 100644 --- a/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt +++ b/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt @@ -24,6 +24,7 @@ import io.sentry.TraceContext import io.sentry.TracesSamplingDecision import io.sentry.TransactionContext import io.sentry.apollo3.SentryApollo3HttpInterceptor.BeforeSpanCallback +import io.sentry.mockServerRequestTimeoutMillis import io.sentry.protocol.SdkVersion import io.sentry.protocol.SentryTransaction import io.sentry.util.Apollo3PlatformTestManipulator @@ -40,6 +41,7 @@ import org.mockito.kotlin.doAnswer import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import java.util.concurrent.TimeUnit import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -192,7 +194,7 @@ class SentryApollo3InterceptorTest { fixture.options.setTracePropagationTargets(listOf("some-host-that-does-not-exist")) executeQuery(isSpanActive = false) - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -201,7 +203,7 @@ class SentryApollo3InterceptorTest { fun `when there is no active span, does not add sentry trace header to the request`() { executeQuery(isSpanActive = false) - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -209,7 +211,7 @@ class SentryApollo3InterceptorTest { @Test fun `when there is an active span, adds sentry trace headers to the request`() { executeQuery() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -217,7 +219,7 @@ class SentryApollo3InterceptorTest { @Test fun `when there is an active span, existing baggage headers are merged with sentry baggage into single header`() { executeQuery(sut = fixture.getSut(addThirdPartyBaggageHeader = true)) - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) diff --git a/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorWithVariablesTest.kt b/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorWithVariablesTest.kt index 3ac3d80d7d..dc9a94f184 100644 --- a/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorWithVariablesTest.kt +++ b/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorWithVariablesTest.kt @@ -12,6 +12,7 @@ import io.sentry.TraceContext import io.sentry.TracesSamplingDecision import io.sentry.TransactionContext import io.sentry.apollo3.SentryApollo3HttpInterceptor.BeforeSpanCallback +import io.sentry.mockServerRequestTimeoutMillis import io.sentry.protocol.SentryTransaction import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -23,6 +24,7 @@ import org.mockito.kotlin.check import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import java.util.concurrent.TimeUnit import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -153,7 +155,7 @@ class SentryApollo3InterceptorWithVariablesTest { @Test fun `internal headers are not sent over the wire`() { executeQuery(fixture.getSut()) - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recorderRequest.headers[SentryApollo3HttpInterceptor.SENTRY_APOLLO_3_VARIABLES]) assertNull(recorderRequest.headers[SentryApollo3HttpInterceptor.SENTRY_APOLLO_3_OPERATION_TYPE]) } diff --git a/sentry-apollo/src/test/java/io/sentry/apollo/SentryApolloInterceptorTest.kt b/sentry-apollo/src/test/java/io/sentry/apollo/SentryApolloInterceptorTest.kt index b1b118c334..1c56af13bd 100644 --- a/sentry-apollo/src/test/java/io/sentry/apollo/SentryApolloInterceptorTest.kt +++ b/sentry-apollo/src/test/java/io/sentry/apollo/SentryApolloInterceptorTest.kt @@ -17,6 +17,7 @@ import io.sentry.SpanStatus import io.sentry.TraceContext import io.sentry.TracesSamplingDecision import io.sentry.TransactionContext +import io.sentry.mockServerRequestTimeoutMillis import io.sentry.protocol.SdkVersion import io.sentry.protocol.SentryTransaction import io.sentry.util.ApolloPlatformTestManipulator @@ -33,6 +34,7 @@ import org.mockito.kotlin.doAnswer import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import java.util.concurrent.TimeUnit import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -154,7 +156,7 @@ class SentryApolloInterceptorTest { fun `when there is no active span, adds sentry trace header to the request from scope`() { executeQuery(isSpanActive = false) - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -162,7 +164,7 @@ class SentryApolloInterceptorTest { @Test fun `when there is an active span, adds sentry trace headers to the request`() { executeQuery() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } diff --git a/sentry-okhttp/src/test/java/io/sentry/okhttp/SentryOkHttpEventListenerTest.kt b/sentry-okhttp/src/test/java/io/sentry/okhttp/SentryOkHttpEventListenerTest.kt index ab179189b4..b1e5fb5226 100644 --- a/sentry-okhttp/src/test/java/io/sentry/okhttp/SentryOkHttpEventListenerTest.kt +++ b/sentry-okhttp/src/test/java/io/sentry/okhttp/SentryOkHttpEventListenerTest.kt @@ -8,6 +8,7 @@ import io.sentry.SentryTracer import io.sentry.SpanDataConvention import io.sentry.SpanStatus import io.sentry.TransactionContext +import io.sentry.mockServerRequestTimeoutMillis import okhttp3.Call import okhttp3.EventListener import okhttp3.OkHttpClient @@ -25,6 +26,7 @@ import org.mockito.kotlin.mock import org.mockito.kotlin.spy import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import java.util.concurrent.TimeUnit import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -111,7 +113,7 @@ class SentryOkHttpEventListenerTest { fun `when there is an active span and the SentryOkHttpInterceptor, adds sentry trace headers to the request`() { val sut = fixture.getSut(useInterceptor = true) sut.newCall(getRequest()).execute() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -121,7 +123,7 @@ class SentryOkHttpEventListenerTest { fun `when there is an active span but no SentryOkHttpInterceptor, sentry trace headers are not added to the request`() { val sut = fixture.getSut() sut.newCall(getRequest()).execute() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } diff --git a/sentry-okhttp/src/test/java/io/sentry/okhttp/SentryOkHttpInterceptorTest.kt b/sentry-okhttp/src/test/java/io/sentry/okhttp/SentryOkHttpInterceptorTest.kt index 8d2feff06e..4bda92f3c4 100644 --- a/sentry-okhttp/src/test/java/io/sentry/okhttp/SentryOkHttpInterceptorTest.kt +++ b/sentry-okhttp/src/test/java/io/sentry/okhttp/SentryOkHttpInterceptorTest.kt @@ -19,6 +19,7 @@ import io.sentry.SpanStatus import io.sentry.TransactionContext import io.sentry.TypeCheckHint import io.sentry.exception.SentryHttpClientException +import io.sentry.mockServerRequestTimeoutMillis import okhttp3.Interceptor import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient @@ -37,6 +38,7 @@ import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import java.io.IOException +import java.util.concurrent.TimeUnit import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse @@ -159,7 +161,7 @@ class SentryOkHttpInterceptorTest { fun `when there is an active span and server is listed in tracing origins, adds sentry trace headers to the request`() { val sut = fixture.getSut() sut.newCall(getRequest()).execute() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -170,7 +172,7 @@ class SentryOkHttpInterceptorTest { val sut = fixture.getSut(keepDefaultTracePropagationTargets = true) sut.newCall(getRequest()).execute() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -180,7 +182,7 @@ class SentryOkHttpInterceptorTest { fun `when there is an active span and server is not listed in tracing origins, does not add sentry trace headers to the request`() { val sut = fixture.getSut(includeMockServerInTracePropagationTargets = false) sut.newCall(Request.Builder().get().url(fixture.server.url("/hello")).build()).execute() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -191,7 +193,7 @@ class SentryOkHttpInterceptorTest { val sut = fixture.getSut() fixture.options.setTracePropagationTargets(emptyList()) sut.newCall(Request.Builder().get().url(fixture.server.url("/hello")).build()).execute() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -200,7 +202,7 @@ class SentryOkHttpInterceptorTest { fun `when there is no active span, adds sentry trace header to the request from scope`() { val sut = fixture.getSut(isSpanActive = false) sut.newCall(getRequest()).execute() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -210,7 +212,7 @@ class SentryOkHttpInterceptorTest { val sut = fixture.getSut(isSpanActive = false) fixture.options.setTracePropagationTargets(listOf("some-host-that-does-not-exist")) sut.newCall(getRequest()).execute() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -219,7 +221,7 @@ class SentryOkHttpInterceptorTest { fun `when there is an active span, existing baggage headers are merged with sentry baggage into single header`() { val sut = fixture.getSut() sut.newCall(getRequestWithBaggageHeader()).execute() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) diff --git a/sentry-openfeign/src/test/kotlin/io/sentry/openfeign/SentryFeignClientTest.kt b/sentry-openfeign/src/test/kotlin/io/sentry/openfeign/SentryFeignClientTest.kt index 959b890d46..28d65da4f1 100644 --- a/sentry-openfeign/src/test/kotlin/io/sentry/openfeign/SentryFeignClientTest.kt +++ b/sentry-openfeign/src/test/kotlin/io/sentry/openfeign/SentryFeignClientTest.kt @@ -16,6 +16,7 @@ import io.sentry.SentryTracer import io.sentry.SpanDataConvention import io.sentry.SpanStatus import io.sentry.TransactionContext +import io.sentry.mockServerRequestTimeoutMillis import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer import org.mockito.kotlin.any @@ -25,6 +26,7 @@ import org.mockito.kotlin.doAnswer import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import java.util.concurrent.TimeUnit import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals @@ -93,7 +95,7 @@ class SentryFeignClientTest { fixture.sentryOptions.dsn = "https://key@sentry.io/proj" val sut = fixture.getSut() sut.getOk() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -106,7 +108,7 @@ class SentryFeignClientTest { sut.getOkWithBaggageHeader(mapOf("baggage" to listOf("thirdPartyBaggage=someValue", "secondThirdPartyBaggage=secondValue; property;propertyKey=propertyValue,anotherThirdPartyBaggage=anotherValue"))) - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) @@ -123,7 +125,7 @@ class SentryFeignClientTest { fixture.sentryOptions.dsn = "https://key@sentry.io/proj" val sut = fixture.getSut(isSpanActive = false) sut.getOk() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -134,7 +136,7 @@ class SentryFeignClientTest { fixture.sentryOptions.dsn = "https://key@sentry.io/proj" val sut = fixture.getSut(isSpanActive = false) sut.getOk() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -146,7 +148,7 @@ class SentryFeignClientTest { fixture.sentryOptions.dsn = "https://key@sentry.io/proj" val sut = fixture.getSut() sut.getOk() - val recorderRequest = fixture.server.takeRequest() + val recorderRequest = fixture.server.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } diff --git a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestClientCustomizerTest.kt b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestClientCustomizerTest.kt index 9ba9bf57d2..545729be33 100644 --- a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestClientCustomizerTest.kt +++ b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestClientCustomizerTest.kt @@ -11,6 +11,7 @@ import io.sentry.SentryTracer import io.sentry.SpanStatus import io.sentry.TracesSamplingDecision import io.sentry.TransactionContext +import io.sentry.mockServerRequestTimeoutMillis import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer import okhttp3.mockwebserver.SocketPolicy @@ -28,12 +29,14 @@ import org.springframework.http.HttpStatus import org.springframework.http.client.HttpComponentsClientHttpRequestFactory import org.springframework.web.client.RestClient import java.time.Duration +import java.util.concurrent.TimeUnit import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue class SentrySpanRestClientCustomizerTest { + class Fixture { val sentryOptions = SentryOptions() val scopes = mock() @@ -104,7 +107,7 @@ class SentrySpanRestClientCustomizerTest { assertThat(span.description).isEqualTo("GET ${fixture.url}") assertThat(span.status).isEqualTo(SpanStatus.OK) - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertThat(recordedRequest.headers["sentry-trace"]!!).startsWith(fixture.transaction.spanContext.traceId.toString()) .endsWith("-1") .doesNotContain(fixture.transaction.spanContext.spanId.toString()) @@ -128,7 +131,7 @@ class SentrySpanRestClientCustomizerTest { .retrieve() .toEntity(String::class.java) - val recorderRequest = fixture.mockServer.takeRequest() + val recorderRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) @@ -147,7 +150,7 @@ class SentrySpanRestClientCustomizerTest { .uri(fixture.url) .retrieve() .toEntity(String::class.java) - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertThat(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]).isNull() } @@ -159,7 +162,7 @@ class SentrySpanRestClientCustomizerTest { .uri(fixture.url) .retrieve() .toEntity(String::class.java) - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertThat(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]).isNotNull() } @@ -184,13 +187,18 @@ class SentrySpanRestClientCustomizerTest { @Test fun `when transaction is active and throws IO exception, creates span with error status around RestClient HTTP call`() { try { - fixture.getSut(isTransactionActive = true, socketPolicy = SocketPolicy.DISCONNECT_AT_START).build() + val sut = fixture.getSut( + isTransactionActive = true, + socketPolicy = SocketPolicy.DISCONNECT_AT_START + ).build() + sut .get() .uri(fixture.url) .retrieve() - } catch (_: Throwable) { + } catch (t: Throwable) { + println(t) } - fixture.mockServer.takeRequest() +// fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertThat(fixture.transaction.spans).hasSize(1) val span = fixture.transaction.spans.first() assertThat(span.operation).isEqualTo("http.client") @@ -227,7 +235,7 @@ class SentrySpanRestClientCustomizerTest { .retrieve() .toEntity(String::class.java) - val recorderRequest = fixture.mockServer.takeRequest() + val recorderRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) diff --git a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestTemplateCustomizerTest.kt b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestTemplateCustomizerTest.kt index 4ab3205b31..f6fe3b69bc 100644 --- a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestTemplateCustomizerTest.kt +++ b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestTemplateCustomizerTest.kt @@ -11,6 +11,7 @@ import io.sentry.SentryTracer import io.sentry.SpanStatus import io.sentry.TracesSamplingDecision import io.sentry.TransactionContext +import io.sentry.mockServerRequestTimeoutMillis import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer import okhttp3.mockwebserver.SocketPolicy @@ -29,6 +30,7 @@ import org.springframework.http.HttpMethod import org.springframework.http.HttpStatus import org.springframework.web.client.RestTemplate import java.time.Duration +import java.util.concurrent.TimeUnit import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -94,7 +96,7 @@ class SentrySpanRestTemplateCustomizerTest { assertThat(span.description).isEqualTo("GET ${fixture.url}") assertThat(span.status).isEqualTo(SpanStatus.OK) - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertThat(recordedRequest.headers["sentry-trace"]!!).startsWith(fixture.transaction.spanContext.traceId.toString()) .endsWith("-1") .doesNotContain(fixture.transaction.spanContext.spanId.toString()) @@ -112,7 +114,7 @@ class SentrySpanRestTemplateCustomizerTest { sut.exchange(fixture.url, HttpMethod.GET, requestEntity, String::class.java) - val recorderRequest = fixture.mockServer.takeRequest() + val recorderRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) @@ -128,7 +130,7 @@ class SentrySpanRestTemplateCustomizerTest { fun `when transaction is active and server is not listed in tracing origins, does not add sentry trace header to the request`() { fixture.getSut(isTransactionActive = true, includeMockServerInTracingOrigins = false) .getForObject(fixture.url, String::class.java) - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertThat(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]).isNull() } @@ -136,7 +138,7 @@ class SentrySpanRestTemplateCustomizerTest { fun `when transaction is active and server is listed in tracing origins, adds sentry trace header to the request`() { fixture.getSut(isTransactionActive = true, includeMockServerInTracingOrigins = true) .getForObject(fixture.url, String::class.java) - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertThat(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]).isNotNull() } @@ -185,7 +187,7 @@ class SentrySpanRestTemplateCustomizerTest { sut.exchange(fixture.url, HttpMethod.GET, requestEntity, String::class.java) - val recorderRequest = fixture.mockServer.takeRequest() + val recorderRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) diff --git a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanWebClientCustomizerTest.kt b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanWebClientCustomizerTest.kt index d3fb5f7d31..decbb68e9e 100644 --- a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanWebClientCustomizerTest.kt +++ b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanWebClientCustomizerTest.kt @@ -12,6 +12,7 @@ import io.sentry.SentryTracer import io.sentry.SpanStatus import io.sentry.TracesSamplingDecision import io.sentry.TransactionContext +import io.sentry.mockServerRequestTimeoutMillis import okhttp3.mockwebserver.Dispatcher import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer @@ -30,6 +31,7 @@ import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.web.reactive.function.BodyInserters import org.springframework.web.reactive.function.client.WebClient +import java.util.concurrent.TimeUnit import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -130,7 +132,7 @@ class SentrySpanWebClientCustomizerTest { .retrieve() .bodyToMono(String::class.java) .block() - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNull(recordedRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -143,7 +145,7 @@ class SentrySpanWebClientCustomizerTest { .retrieve() .bodyToMono(String::class.java) .block() - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNull(recordedRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -156,7 +158,7 @@ class SentrySpanWebClientCustomizerTest { .retrieve() .bodyToMono(String::class.java) .block() - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recordedRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -169,7 +171,7 @@ class SentrySpanWebClientCustomizerTest { .retrieve() .bodyToMono(String::class.java) .block() - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recordedRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } diff --git a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt index 33d7974d8a..5d09db87d5 100644 --- a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt +++ b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt @@ -11,6 +11,7 @@ import io.sentry.SentryTracer import io.sentry.SpanStatus import io.sentry.TracesSamplingDecision import io.sentry.TransactionContext +import io.sentry.mockServerRequestTimeoutMillis import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer import okhttp3.mockwebserver.SocketPolicy @@ -29,6 +30,7 @@ import org.springframework.http.HttpMethod import org.springframework.http.HttpStatus import org.springframework.web.client.RestTemplate import java.time.Duration +import java.util.concurrent.TimeUnit import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -96,7 +98,7 @@ class SentrySpanRestTemplateCustomizerTest { assertThat(span.description).isEqualTo("GET ${fixture.url}") assertThat(span.status).isEqualTo(SpanStatus.OK) - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertThat(recordedRequest.headers["sentry-trace"]!!).startsWith(fixture.transaction.spanContext.traceId.toString()) .endsWith("-1") .doesNotContain(fixture.transaction.spanContext.spanId.toString()) @@ -114,7 +116,7 @@ class SentrySpanRestTemplateCustomizerTest { sut.exchange(fixture.url, HttpMethod.GET, requestEntity, String::class.java) - val recorderRequest = fixture.mockServer.takeRequest() + val recorderRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) @@ -130,7 +132,7 @@ class SentrySpanRestTemplateCustomizerTest { fun `when transaction is active and server is not listed in tracing origins, does not add sentry trace header to the request`() { fixture.getSut(isTransactionActive = true, includeMockServerInTracingOrigins = false) .getForObject(fixture.url, String::class.java) - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertThat(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]).isNull() } @@ -138,7 +140,7 @@ class SentrySpanRestTemplateCustomizerTest { fun `when transaction is active and server is listed in tracing origins, adds sentry trace header to the request`() { fixture.getSut(isTransactionActive = true, includeMockServerInTracingOrigins = true) .getForObject(fixture.url, String::class.java) - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertThat(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]).isNotNull() } @@ -187,7 +189,7 @@ class SentrySpanRestTemplateCustomizerTest { sut.exchange(fixture.url, HttpMethod.GET, requestEntity, String::class.java) - val recorderRequest = fixture.mockServer.takeRequest() + val recorderRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recorderRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recorderRequest.headers[BaggageHeader.BAGGAGE_HEADER]) diff --git a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanWebClientCustomizerTest.kt b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanWebClientCustomizerTest.kt index 4f1f70d75e..ac63805436 100644 --- a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanWebClientCustomizerTest.kt +++ b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentrySpanWebClientCustomizerTest.kt @@ -12,6 +12,7 @@ import io.sentry.SentryTracer import io.sentry.SpanStatus import io.sentry.TracesSamplingDecision import io.sentry.TransactionContext +import io.sentry.mockServerRequestTimeoutMillis import okhttp3.mockwebserver.Dispatcher import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer @@ -30,6 +31,7 @@ import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.web.reactive.function.BodyInserters import org.springframework.web.reactive.function.client.WebClient +import java.util.concurrent.TimeUnit import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -132,7 +134,7 @@ class SentrySpanWebClientCustomizerTest { .retrieve() .bodyToMono(String::class.java) .block() - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNull(recordedRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -145,7 +147,7 @@ class SentrySpanWebClientCustomizerTest { .retrieve() .bodyToMono(String::class.java) .block() - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNull(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNull(recordedRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -158,7 +160,7 @@ class SentrySpanWebClientCustomizerTest { .retrieve() .bodyToMono(String::class.java) .block() - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recordedRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } @@ -171,7 +173,7 @@ class SentrySpanWebClientCustomizerTest { .retrieve() .bodyToMono(String::class.java) .block() - val recordedRequest = fixture.mockServer.takeRequest() + val recordedRequest = fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertNotNull(recordedRequest.headers[SentryTraceHeader.SENTRY_TRACE_HEADER]) assertNotNull(recordedRequest.headers[BaggageHeader.BAGGAGE_HEADER]) } diff --git a/sentry-test-support/api/sentry-test-support.api b/sentry-test-support/api/sentry-test-support.api index 27d7034690..8ef2e78743 100644 --- a/sentry-test-support/api/sentry-test-support.api +++ b/sentry-test-support/api/sentry-test-support.api @@ -5,6 +5,7 @@ public final class io/sentry/AssertionsKt { public static synthetic fun assertEnvelopeTransaction$default (Ljava/util/List;Lio/sentry/ILogger;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/sentry/protocol/SentryTransaction; public static final fun checkEvent (Lkotlin/jvm/functions/Function1;)Lio/sentry/SentryEnvelope; public static final fun checkTransaction (Lkotlin/jvm/functions/Function1;)Lio/sentry/SentryEnvelope; + public static final fun getMockServerRequestTimeoutMillis ()J } public final class io/sentry/SkipError : java/lang/Error { diff --git a/sentry-test-support/src/main/kotlin/io/sentry/Assertions.kt b/sentry-test-support/src/main/kotlin/io/sentry/Assertions.kt index 435030ea3b..6d75810ecc 100644 --- a/sentry-test-support/src/main/kotlin/io/sentry/Assertions.kt +++ b/sentry-test-support/src/main/kotlin/io/sentry/Assertions.kt @@ -99,3 +99,5 @@ If you are using `check` as part of a stubbing, use `argThat` or `argForWhich` i } class SkipError(message: String) : Error(message) + +val mockServerRequestTimeoutMillis = 5000L From 6794a58c5feb130a2ee4f38e7159c1e6408f5350 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 29 Nov 2024 12:31:18 +0100 Subject: [PATCH 07/13] fix twp --- .../io/sentry/systemtest/PersonSystemTest.kt | 66 +++++++++++++++++++ .../sentry/systemtest/util/RestTestClient.kt | 13 ++-- .../SentrySpanRestClientCustomizerTest.kt | 4 +- .../java/io/sentry/TransactionContext.java | 11 ++-- .../java/io/sentry/util/TracingUtils.java | 4 +- sentry/src/test/java/io/sentry/ScopesTest.kt | 17 +++++ .../java/io/sentry/util/TracingUtilsTest.kt | 34 ++++++++++ 7 files changed, 137 insertions(+), 12 deletions(-) diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt index 9309529ce4..2c1b24ba3b 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt @@ -44,4 +44,70 @@ class PersonSystemTest { testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") } } + + @Test + fun `create person creates transaction if no sampled flag in sentry-trace header`() { + val restClient = testHelper.restClient + val person = Person("firstA", "lastB") + val returnedPerson = restClient.createPerson( + person, + mapOf( + "sentry-trace" to "f9118105af4a2d42b4124532cd1065ff-424cffc8f94feeee", + "baggage" to "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rate=1,sentry-trace_id=f9118105af4a2d42b4124532cd1065ff,sentry-transaction=HTTP%20GET" + ) + ) + assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + + assertEquals(person.firstName, returnedPerson!!.firstName) + assertEquals(person.lastName, returnedPerson!!.lastName) + + testHelper.ensureTransactionReceived { transaction -> + testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && + testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") + } + } + + @Test + fun `create person creates transaction if sampled true in sentry-trace header`() { + val restClient = testHelper.restClient + val person = Person("firstA", "lastB") + val returnedPerson = restClient.createPerson( + person, + mapOf( + "sentry-trace" to "f9118105af4a2d42b4124532cd1065ff-424cffc8f94feeee-1", + "baggage" to "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rate=1,sentry-trace_id=f9118105af4a2d42b4124532cd1065ff,sentry-transaction=HTTP%20GET" + ) + ) + assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + + assertEquals(person.firstName, returnedPerson!!.firstName) + assertEquals(person.lastName, returnedPerson!!.lastName) + + testHelper.ensureTransactionReceived { transaction -> + testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && + testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") + } + } + + @Test + fun `create person does not create transaction if sampled false in sentry-trace header`() { + val restClient = testHelper.restClient + val person = Person("firstA", "lastB") + val returnedPerson = restClient.createPerson( + person, + mapOf( + "sentry-trace" to "f9118105af4a2d42b4124532cd1065ff-424cffc8f94feeee-0", + "baggage" to "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rate=1,sentry-trace_id=f9118105af4a2d42b4124532cd1065ff,sentry-transaction=HTTP%20GET" + ) + ) + assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + + assertEquals(person.firstName, returnedPerson!!.firstName) + assertEquals(person.lastName, returnedPerson!!.lastName) + + testHelper.ensureTransactionReceived { transaction -> + testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && + testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") + } + } } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt index f5d5bd7ee3..1c4eef63f7 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt @@ -22,9 +22,9 @@ class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestCl } } - fun createPerson(person: Person): Person? { + fun createPerson(person: Person, extraHeaders: Map? = null): Person? { return try { - val response = restTemplate().exchange("$backendBaseUrl/person/", HttpMethod.POST, entityWithAuth(person), Person::class.java, person) + val response = restTemplate().exchange("$backendBaseUrl/person/", HttpMethod.POST, entityWithAuth(person, extraHeaders), Person::class.java, person) lastKnownStatusCode = response.statusCode response.body } catch (e: HttpStatusCodeException) { @@ -55,9 +55,12 @@ class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestCl } } - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders().also { - it.setBasicAuth("user", "password") + private fun entityWithAuth(request: Any? = null, extraHeaders: Map? = null): HttpEntity { + val headers = HttpHeaders().also { httpHeaders -> + httpHeaders.setBasicAuth("user", "password") + extraHeaders?.forEach { key, value -> + httpHeaders.set(key, value) + } } return HttpEntity(request, headers) diff --git a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestClientCustomizerTest.kt b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestClientCustomizerTest.kt index 545729be33..d32885b41f 100644 --- a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestClientCustomizerTest.kt +++ b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentrySpanRestClientCustomizerTest.kt @@ -28,6 +28,7 @@ import org.springframework.http.HttpHeaders import org.springframework.http.HttpStatus import org.springframework.http.client.HttpComponentsClientHttpRequestFactory import org.springframework.web.client.RestClient +import org.springframework.web.client.toEntity import java.time.Duration import java.util.concurrent.TimeUnit import kotlin.test.Test @@ -195,10 +196,11 @@ class SentrySpanRestClientCustomizerTest { .get() .uri(fixture.url) .retrieve() + .toEntity(String::class.java) } catch (t: Throwable) { println(t) } -// fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! + fixture.mockServer.takeRequest(mockServerRequestTimeoutMillis, TimeUnit.MILLISECONDS)!! assertThat(fixture.transaction.spans).hasSize(1) val span = fixture.transaction.spans.first() assertThat(span.operation).isEqualTo("http.client") diff --git a/sentry/src/main/java/io/sentry/TransactionContext.java b/sentry/src/main/java/io/sentry/TransactionContext.java index 287fcee1fa..aec0b8927d 100644 --- a/sentry/src/main/java/io/sentry/TransactionContext.java +++ b/sentry/src/main/java/io/sentry/TransactionContext.java @@ -30,11 +30,12 @@ public static TransactionContext fromPropagationContext( baggage.freeze(); Double sampleRate = baggage.getSampleRateDouble(); - Boolean sampled = parentSampled != null ? parentSampled.booleanValue() : false; - if (sampleRate != null) { - samplingDecision = new TracesSamplingDecision(sampled, sampleRate); - } else { - samplingDecision = new TracesSamplingDecision(sampled); + if (parentSampled != null) { + if (sampleRate != null) { + samplingDecision = new TracesSamplingDecision(parentSampled.booleanValue(), sampleRate); + } else { + samplingDecision = new TracesSamplingDecision(parentSampled.booleanValue()); + } } } diff --git a/sentry/src/main/java/io/sentry/util/TracingUtils.java b/sentry/src/main/java/io/sentry/util/TracingUtils.java index 5f09a67457..2f0cc4a98e 100644 --- a/sentry/src/main/java/io/sentry/util/TracingUtils.java +++ b/sentry/src/main/java/io/sentry/util/TracingUtils.java @@ -65,7 +65,9 @@ public static void startNewTrace(final @NotNull IScopes scopes) { return new TracingHeaders( new SentryTraceHeader( - propagationContext.getTraceId(), propagationContext.getSpanId(), null), + propagationContext.getTraceId(), + propagationContext.getSpanId(), + propagationContext.isSampled()), baggageHeader); } diff --git a/sentry/src/test/java/io/sentry/ScopesTest.kt b/sentry/src/test/java/io/sentry/ScopesTest.kt index a806ca2175..f0e9833cb8 100644 --- a/sentry/src/test/java/io/sentry/ScopesTest.kt +++ b/sentry/src/test/java/io/sentry/ScopesTest.kt @@ -1968,6 +1968,23 @@ class ScopesTest { assertEquals(parentSpanId, transactionContext!!.parentSpanId) } + @Test + fun `continueTrace creates propagation context from headers and returns transaction context if performance enabled no sampled value`() { + val scopes = generateScopes() + val traceId = SentryId() + val parentSpanId = SpanId() + val transactionContext = scopes.continueTrace("$traceId-$parentSpanId", listOf("sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rate=1,sentry-trace_id=$traceId,sentry-transaction=HTTP%20GET")) + + scopes.configureScope { scope -> + assertEquals(traceId, scope.propagationContext.traceId) + assertEquals(parentSpanId, scope.propagationContext.parentSpanId) + } + + assertEquals(traceId, transactionContext!!.traceId) + assertEquals(parentSpanId, transactionContext!!.parentSpanId) + assertEquals(null, transactionContext!!.parentSamplingDecision) + } + @Test fun `continueTrace creates new propagation context if header invalid and returns transaction context if performance enabled`() { val scopes = generateScopes() diff --git a/sentry/src/test/java/io/sentry/util/TracingUtilsTest.kt b/sentry/src/test/java/io/sentry/util/TracingUtilsTest.kt index 62e2ba0055..096b0a81bd 100644 --- a/sentry/src/test/java/io/sentry/util/TracingUtilsTest.kt +++ b/sentry/src/test/java/io/sentry/util/TracingUtilsTest.kt @@ -58,6 +58,7 @@ class TracingUtilsTest { assertNotNull(headers.baggageHeader) assertEquals(fixture.scope.propagationContext.spanId, headers.sentryTraceHeader.spanId) assertEquals(fixture.scope.propagationContext.traceId, headers.sentryTraceHeader.traceId) + assertEquals(fixture.scope.propagationContext.isSampled, headers.sentryTraceHeader.isSampled) assertTrue(headers.baggageHeader!!.value.contains("some-baggage-key=some-baggage-value")) assertTrue(headers.baggageHeader!!.value.contains("sentry-trace_id=${fixture.scope.propagationContext.traceId}")) assertFalse(fixture.scope.propagationContext.baggage!!.isMutable) @@ -73,6 +74,39 @@ class TracingUtilsTest { assertNotNull(headers.baggageHeader) assertEquals(fixture.scope.propagationContext.spanId, headers.sentryTraceHeader.spanId) assertEquals(fixture.scope.propagationContext.traceId, headers.sentryTraceHeader.traceId) + assertEquals(fixture.scope.propagationContext.isSampled, headers.sentryTraceHeader.isSampled) + assertTrue(headers.baggageHeader!!.value.contains("some-baggage-key=some-baggage-value")) + assertFalse(fixture.scope.propagationContext.baggage!!.isMutable) + } + + @Test + fun `returns headers if allowed from scope if span is noop sampled=true`() { + fixture.setup() + fixture.scope.propagationContext.isSampled = true + + val headers = TracingUtils.traceIfAllowed(fixture.scopes, "https://sentry.io/hello", fixture.preExistingBaggage, NoOpSpan.getInstance()) + + assertNotNull(headers) + assertNotNull(headers.baggageHeader) + assertEquals(fixture.scope.propagationContext.spanId, headers.sentryTraceHeader.spanId) + assertEquals(fixture.scope.propagationContext.traceId, headers.sentryTraceHeader.traceId) + assertEquals(fixture.scope.propagationContext.isSampled, headers.sentryTraceHeader.isSampled) + assertTrue(headers.baggageHeader!!.value.contains("some-baggage-key=some-baggage-value")) + assertFalse(fixture.scope.propagationContext.baggage!!.isMutable) + } + + @Test + fun `returns headers if allowed from scope if span is noop sampled=false`() { + fixture.setup() + fixture.scope.propagationContext.isSampled = false + + val headers = TracingUtils.traceIfAllowed(fixture.scopes, "https://sentry.io/hello", fixture.preExistingBaggage, NoOpSpan.getInstance()) + + assertNotNull(headers) + assertNotNull(headers.baggageHeader) + assertEquals(fixture.scope.propagationContext.spanId, headers.sentryTraceHeader.spanId) + assertEquals(fixture.scope.propagationContext.traceId, headers.sentryTraceHeader.traceId) + assertEquals(fixture.scope.propagationContext.isSampled, headers.sentryTraceHeader.isSampled) assertTrue(headers.baggageHeader!!.value.contains("some-baggage-key=some-baggage-value")) assertFalse(fixture.scope.propagationContext.baggage!!.isMutable) } From 156b915b2baddb4ac18ac1d4595fefb4ce786c43 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 2 Dec 2024 10:59:57 +0100 Subject: [PATCH 08/13] Use null sampled for TwP --- .../api/sentry-opentelemetry-core.api | 1 - .../opentelemetry/OtelSamplingUtil.java | 10 -------- .../OtelSentrySpanProcessor.java | 24 ++++++++++++++----- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api b/sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api index 60e2010e6c..fd2099a730 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api +++ b/sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api @@ -12,7 +12,6 @@ public final class io/sentry/opentelemetry/OtelInternalSpanDetectionUtil { public final class io/sentry/opentelemetry/OtelSamplingUtil { public fun ()V public static fun extractSamplingDecision (Lio/opentelemetry/api/common/Attributes;)Lio/sentry/TracesSamplingDecision; - public static fun extractSamplingDecisionOrDefault (Lio/opentelemetry/api/common/Attributes;)Lio/sentry/TracesSamplingDecision; } public final class io/sentry/opentelemetry/OtelSentryPropagator : io/opentelemetry/context/propagation/TextMapPropagator { diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSamplingUtil.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSamplingUtil.java index 45a8922741..01f414f902 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSamplingUtil.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSamplingUtil.java @@ -9,16 +9,6 @@ @ApiStatus.Internal public final class OtelSamplingUtil { - public static @NotNull TracesSamplingDecision extractSamplingDecisionOrDefault( - final @NotNull Attributes attributes) { - final @Nullable TracesSamplingDecision decision = extractSamplingDecision(attributes); - if (decision != null) { - return decision; - } else { - return new TracesSamplingDecision(false); - } - } - public static @Nullable TracesSamplingDecision extractSamplingDecision( final @NotNull Attributes attributes) { final @Nullable Boolean sampled = attributes.get(InternalSemanticAttributes.SAMPLED); diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java index 569067a856..27149d821f 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java @@ -49,9 +49,9 @@ public void onStart(final @NotNull Context parentContext, final @NotNull ReadWri final @Nullable IOtelSpanWrapper sentryParentSpan = spanStorage.getSentrySpan(otelSpan.getParentSpanContext()); - @NotNull + @Nullable TracesSamplingDecision samplingDecision = - OtelSamplingUtil.extractSamplingDecisionOrDefault(otelSpan.toSpanData().getAttributes()); + OtelSamplingUtil.extractSamplingDecision(otelSpan.toSpanData().getAttributes()); @Nullable Baggage baggage = null; @Nullable SpanId sentryParentSpanId = null; otelSpan.setAttribute(IS_REMOTE_PARENT, otelSpan.getParentSpanContext().isRemote()); @@ -81,10 +81,7 @@ public void onStart(final @NotNull Context parentContext, final @NotNull ReadWri } } - final boolean sampled = - samplingDecision != null - ? samplingDecision.getSampled() - : otelSpan.getSpanContext().isSampled(); + final @Nullable Boolean sampled = isSampled(otelSpan, samplingDecision); final @NotNull PropagationContext propagationContext = sentryTraceHeader == null @@ -111,6 +108,21 @@ public void onStart(final @NotNull Context parentContext, final @NotNull ReadWri spanStorage.storeSentrySpan(spanContext, sentrySpan); } + private @Nullable Boolean isSampled( + final @NotNull ReadWriteSpan otelSpan, + final @Nullable TracesSamplingDecision samplingDecision) { + if (samplingDecision != null) { + return samplingDecision.getSampled(); + } + + if (otelSpan.getSpanContext().isSampled()) { + return true; + } + + // tracing without performance + return null; + } + private static void updatePropagationContext( IScopes scopes, PropagationContext propagationContext) { scopes.configureScope( From a90f3164e0641efff997ac99dd6277e500cc7336 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 2 Dec 2024 11:18:31 +0100 Subject: [PATCH 09/13] make todo url configurable --- .../samples/spring/boot/jakarta/TodoController.java | 12 ++++++++---- .../src/main/resources/application.properties | 1 + test/system-test-spring-server-start.sh | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java index 8d86ddcb86..9648e47c45 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java @@ -7,6 +7,8 @@ import io.sentry.Sentry; import io.sentry.spring.jakarta.webflux.ReactorUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @@ -24,6 +26,9 @@ public class TodoController { private final RestClient restClient; private final Tracer tracer; + @Value("sentry.sample.todo-url") + public @Nullable String todoUrl; + public TodoController( RestTemplate restTemplate, WebClient webClient, RestClient restClient, Tracer tracer) { this.restTemplate = restTemplate; @@ -38,8 +43,7 @@ Todo todo(@PathVariable Long id) { try (final @NotNull Scope spanScope = otelSpan.makeCurrent()) { ISpan sentrySpan = Sentry.getSpan().startChild("todoSpanSentryApi"); try { - return restTemplate.getForObject( - "https://jsonplaceholder.typicode.com/todos/{id}", Todo.class, id); + return restTemplate.getForObject(todoUrl + "/todos/{id}", Todo.class, id); } finally { sentrySpan.finish(); } @@ -58,7 +62,7 @@ Todo todoWebClient(@PathVariable Long id) { x -> webClient .get() - .uri("https://jsonplaceholder.typicode.com/todos/{id}", id) + .uri(todoUrl + "/todos/{id}", id) .retrieve() .bodyToMono(Todo.class) .map(response -> response))) @@ -73,7 +77,7 @@ Todo todoRestClient(@PathVariable Long id) { try { return restClient .get() - .uri("https://jsonplaceholder.typicode.com/todos/{id}", id) + .uri(todoUrl + "/todos/{id}", id) .retrieve() .body(Todo.class); } finally { diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/resources/application.properties b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/resources/application.properties index b588f7979c..06a18603aa 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/resources/application.properties +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/resources/application.properties @@ -16,6 +16,7 @@ sentry.enable-backpressure-handling=true sentry.enable-spotlight=true sentry.enablePrettySerializationOutput=false in-app-includes="io.sentry.samples" +sentry.sample.todo-url=https://jsonplaceholder.typicode.com # Uncomment and set to true to enable aot compatibility # This flag disables all AOP related features (i.e. @SentryTransaction, @SentrySpan) diff --git a/test/system-test-spring-server-start.sh b/test/system-test-spring-server-start.sh index 1a6f3d5a06..b9ba9ed0b0 100755 --- a/test/system-test-spring-server-start.sh +++ b/test/system-test-spring-server-start.sh @@ -15,5 +15,5 @@ fi echo "$JAVA_AGENT_STRING" -SENTRY_DSN="http://502f25099c204a2fbf4cb16edc5975d1@localhost:8000/0" SENTRY_AUTO_INIT=${JAVA_AGENT_AUTO_INIT} SENTRY_TRACES_SAMPLE_RATE=1.0 OTEL_TRACES_EXPORTER=none OTEL_METRICS_EXPORTER=none OTEL_LOGS_EXPORTER=none java ${JAVA_AGENT_STRING} -jar sentry-samples/${SAMPLE_MODULE}/build/libs/${SAMPLE_MODULE}-0.0.1-SNAPSHOT.jar > spring-server.txt 2>&1 & +SENTRY_DSN="http://502f25099c204a2fbf4cb16edc5975d1@localhost:8000/0" SENTRY_SAMPLE_TODO_URL="http://localhost:48080" SENTRY_AUTO_INIT=${JAVA_AGENT_AUTO_INIT} SENTRY_TRACES_SAMPLE_RATE=1.0 OTEL_TRACES_EXPORTER=none OTEL_METRICS_EXPORTER=none OTEL_LOGS_EXPORTER=none java ${JAVA_AGENT_STRING} -jar sentry-samples/${SAMPLE_MODULE}/build/libs/${SAMPLE_MODULE}-0.0.1-SNAPSHOT.jar > spring-server.txt 2>&1 & echo $! > spring-server.pid From 20bd534754334a8a12b2e7c164ce48d4e6767b4a Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 2 Dec 2024 14:45:43 +0100 Subject: [PATCH 10/13] Build PropagationContext from sampling decision in OTel instead of incoming headers --- .../io/sentry/opentelemetry/OtelSentrySpanProcessor.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java index 27149d821f..521bc9020c 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java @@ -84,10 +84,8 @@ public void onStart(final @NotNull Context parentContext, final @NotNull ReadWri final @Nullable Boolean sampled = isSampled(otelSpan, samplingDecision); final @NotNull PropagationContext propagationContext = - sentryTraceHeader == null - ? new PropagationContext( - new SentryId(traceId), sentrySpanId, sentryParentSpanId, baggage, sampled) - : PropagationContext.fromHeaders(sentryTraceHeader, baggage, sentrySpanId); + new PropagationContext( + new SentryId(traceId), sentrySpanId, sentryParentSpanId, baggage, sampled); updatePropagationContext(scopes, propagationContext); } From 4bb2032fa0526114a3b0b33beab6b2bcd640674c Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Mon, 2 Dec 2024 14:27:13 +0000 Subject: [PATCH 11/13] Format code --- .../sentry/samples/spring/boot/jakarta/TodoController.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java index 9648e47c45..09c9eab40e 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java @@ -75,11 +75,7 @@ Todo todoRestClient(@PathVariable Long id) { try (final @NotNull Scope spanScope = span.makeCurrent()) { ISpan sentrySpan = Sentry.getSpan().startChild("todoRestClientSpanSentryApi"); try { - return restClient - .get() - .uri(todoUrl + "/todos/{id}", id) - .retrieve() - .body(Todo.class); + return restClient.get().uri(todoUrl + "/todos/{id}", id).retrieve().body(Todo.class); } finally { sentrySpan.finish(); } From 74ace9cf1145e6b0291938f7755f60663aa10ccc Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 2 Dec 2024 15:29:02 +0100 Subject: [PATCH 12/13] changelog --- CHANGELOG.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85cf84e17d..86d91f8283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - When generating `sentry-trace` header from `PropagationContext` we now copy the `sampled` flag. - In `TransactionContext.fromPropagationContext` when there is no parent sampling decision, keep the decision `null` so a new sampling decision is made instead of defaulting to `false` - Defer sampling decision by setting `sampled` to `null` in `PropagationContext` when using OpenTelemetry in case of an incoming defer sampling `sentry-trace` header. ([#3945](https://github.com/getsentry/sentry-java/pull/3945)) +- Build `PropagationContext` from `SamplingDecision` made by `SentrySampler` instead of parsing headers and potentially ignoring a sampling decision in case a `sentry-trace` header comes in with deferred sampling decision. ([#3947](https://github.com/getsentry/sentry-java/pull/3947)) ## 8.0.0-rc.1 @@ -26,10 +27,6 @@ - Fix testTag not working for Jetpack Compose user interaction tracking ([#3878](https://github.com/getsentry/sentry-java/pull/3878)) -### Dependencies - -- Bump OpenTelemetry to 1.44.1, OpenTelemetry Java Agent to 2.10.0 and Semantic Conventions to 1.28.0 ([#3935](https://github.com/getsentry/sentry-java/pull/3935)) - ## 8.0.0-beta.3 ### Features From ae7c69e7f9f86ed92a5f3c4eaab09939bd9a7bbc Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 2 Dec 2024 15:30:24 +0100 Subject: [PATCH 13/13] Revert "make todo url configurable" This reverts commit a90f3164e0641efff997ac99dd6277e500cc7336. --- .../spring/boot/jakarta/TodoController.java | 16 ++++++++-------- .../src/main/resources/application.properties | 1 - test/system-test-spring-server-start.sh | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java index 09c9eab40e..8d86ddcb86 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java @@ -7,8 +7,6 @@ import io.sentry.Sentry; import io.sentry.spring.jakarta.webflux.ReactorUtils; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @@ -26,9 +24,6 @@ public class TodoController { private final RestClient restClient; private final Tracer tracer; - @Value("sentry.sample.todo-url") - public @Nullable String todoUrl; - public TodoController( RestTemplate restTemplate, WebClient webClient, RestClient restClient, Tracer tracer) { this.restTemplate = restTemplate; @@ -43,7 +38,8 @@ Todo todo(@PathVariable Long id) { try (final @NotNull Scope spanScope = otelSpan.makeCurrent()) { ISpan sentrySpan = Sentry.getSpan().startChild("todoSpanSentryApi"); try { - return restTemplate.getForObject(todoUrl + "/todos/{id}", Todo.class, id); + return restTemplate.getForObject( + "https://jsonplaceholder.typicode.com/todos/{id}", Todo.class, id); } finally { sentrySpan.finish(); } @@ -62,7 +58,7 @@ Todo todoWebClient(@PathVariable Long id) { x -> webClient .get() - .uri(todoUrl + "/todos/{id}", id) + .uri("https://jsonplaceholder.typicode.com/todos/{id}", id) .retrieve() .bodyToMono(Todo.class) .map(response -> response))) @@ -75,7 +71,11 @@ Todo todoRestClient(@PathVariable Long id) { try (final @NotNull Scope spanScope = span.makeCurrent()) { ISpan sentrySpan = Sentry.getSpan().startChild("todoRestClientSpanSentryApi"); try { - return restClient.get().uri(todoUrl + "/todos/{id}", id).retrieve().body(Todo.class); + return restClient + .get() + .uri("https://jsonplaceholder.typicode.com/todos/{id}", id) + .retrieve() + .body(Todo.class); } finally { sentrySpan.finish(); } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/resources/application.properties b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/resources/application.properties index 06a18603aa..b588f7979c 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/resources/application.properties +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/main/resources/application.properties @@ -16,7 +16,6 @@ sentry.enable-backpressure-handling=true sentry.enable-spotlight=true sentry.enablePrettySerializationOutput=false in-app-includes="io.sentry.samples" -sentry.sample.todo-url=https://jsonplaceholder.typicode.com # Uncomment and set to true to enable aot compatibility # This flag disables all AOP related features (i.e. @SentryTransaction, @SentrySpan) diff --git a/test/system-test-spring-server-start.sh b/test/system-test-spring-server-start.sh index b9ba9ed0b0..1a6f3d5a06 100755 --- a/test/system-test-spring-server-start.sh +++ b/test/system-test-spring-server-start.sh @@ -15,5 +15,5 @@ fi echo "$JAVA_AGENT_STRING" -SENTRY_DSN="http://502f25099c204a2fbf4cb16edc5975d1@localhost:8000/0" SENTRY_SAMPLE_TODO_URL="http://localhost:48080" SENTRY_AUTO_INIT=${JAVA_AGENT_AUTO_INIT} SENTRY_TRACES_SAMPLE_RATE=1.0 OTEL_TRACES_EXPORTER=none OTEL_METRICS_EXPORTER=none OTEL_LOGS_EXPORTER=none java ${JAVA_AGENT_STRING} -jar sentry-samples/${SAMPLE_MODULE}/build/libs/${SAMPLE_MODULE}-0.0.1-SNAPSHOT.jar > spring-server.txt 2>&1 & +SENTRY_DSN="http://502f25099c204a2fbf4cb16edc5975d1@localhost:8000/0" SENTRY_AUTO_INIT=${JAVA_AGENT_AUTO_INIT} SENTRY_TRACES_SAMPLE_RATE=1.0 OTEL_TRACES_EXPORTER=none OTEL_METRICS_EXPORTER=none OTEL_LOGS_EXPORTER=none java ${JAVA_AGENT_STRING} -jar sentry-samples/${SAMPLE_MODULE}/build/libs/${SAMPLE_MODULE}-0.0.1-SNAPSHOT.jar > spring-server.txt 2>&1 & echo $! > spring-server.pid