From a03d1f8ac624bb152c6d6773d205ea7add0213b3 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 30 Oct 2026 10:58:59 +0100 Subject: [PATCH 1/2] feat(ktor): Add URL data to client spans Apply resolver-filtered query parameters and fragments to Ktor client spans while keeping span descriptions free of URL details. Respect URL query collection deny lists and off mode. Fixes #5984 Co-Authored-By: Claude --- .../ktorClient/SentryKtorClientPlugin.kt | 1 + .../ktorClient/SentryKtorClientPluginTest.kt | 40 +++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/sentry-ktor-client/src/main/java/io/sentry/ktorClient/SentryKtorClientPlugin.kt b/sentry-ktor-client/src/main/java/io/sentry/ktorClient/SentryKtorClientPlugin.kt index 0e4538fb41..b1841b8e1a 100644 --- a/sentry-ktor-client/src/main/java/io/sentry/ktorClient/SentryKtorClientPlugin.kt +++ b/sentry-ktor-client/src/main/java/io/sentry/ktorClient/SentryKtorClientPlugin.kt @@ -118,6 +118,7 @@ public val SentryKtorClientPlugin: ClientPlugin = val urlDetails = UrlUtils.parse(rawUrl, effectiveScopes.options.dataCollectionResolver) val spanDescription = "${request.method.value.toString()} ${urlDetails.urlOrFallback}" val span: ISpan? = parentSpan?.startChild(spanOp, spanDescription) + urlDetails.applyToSpan(span) if (span != null) { span.spanContext.origin = TRACE_ORIGIN request.attributes.put(requestSpanKey, span) diff --git a/sentry-ktor-client/src/test/java/io/sentry/ktorClient/SentryKtorClientPluginTest.kt b/sentry-ktor-client/src/test/java/io/sentry/ktorClient/SentryKtorClientPluginTest.kt index 87d607f255..b2dd7de124 100644 --- a/sentry-ktor-client/src/test/java/io/sentry/ktorClient/SentryKtorClientPluginTest.kt +++ b/sentry-ktor-client/src/test/java/io/sentry/ktorClient/SentryKtorClientPluginTest.kt @@ -556,13 +556,47 @@ class SentryKtorClientPluginTest { } @Test - fun `span description excludes query parameters and fragment`(): Unit = runBlocking { + fun `span description excludes query parameters and fragment while span data includes them`(): + Unit = runBlocking { val sut = fixture.getSut() sut.get(fixture.server.url("/hello?token=secret&page=1#results").toString()) val httpClientSpan = fixture.sentryTracer.children.first() - assertEquals("GET ${fixture.server.url("/hello")}", httpClientSpan.description) - assertNull(httpClientSpan.data[SpanDataConvention.HTTP_QUERY_KEY]) + assertThat(httpClientSpan.description).isEqualTo("GET ${fixture.server.url("/hello")}") + assertThat(httpClientSpan.data[SpanDataConvention.HTTP_QUERY_KEY]) + .isEqualTo("token=secret&page=1") + assertThat(httpClientSpan.data[SpanDataConvention.HTTP_FRAGMENT_KEY]).isEqualTo("results") + } + + @Test + fun `data collection filters span query parameters`(): Unit = runBlocking { + val sut = + fixture.getSut( + optionsConfiguration = + Sentry.OptionsConfiguration { + it.dataCollection.urlQueryParams = KeyValueCollectionBehavior.denyList("token") + } + ) + sut.get(fixture.server.url("/hello?name=value&token=secret").toString()) + + val httpClientSpan = fixture.sentryTracer.children.first() + assertThat(httpClientSpan.data[SpanDataConvention.HTTP_QUERY_KEY]) + .isEqualTo("name=value&token=[Filtered]") + } + + @Test + fun `data collection can disable span query parameters`(): Unit = runBlocking { + val sut = + fixture.getSut( + optionsConfiguration = + Sentry.OptionsConfiguration { + it.dataCollection.urlQueryParams = KeyValueCollectionBehavior.off() + } + ) + sut.get(fixture.server.url("/hello?name=value").toString()) + + val httpClientSpan = fixture.sentryTracer.children.first() + assertThat(httpClientSpan.data).doesNotContainKey(SpanDataConvention.HTTP_QUERY_KEY) } @Test From beb93a51b735fa982689ac7bd124258104a5fd94 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 30 Oct 2026 11:00:58 +0100 Subject: [PATCH 2/2] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eb80a6a29..a06bf9ed50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,10 @@ - Remove deprecated OpenTelemetry integration classes and the legacy `SentrySpanStorage` ([#6243](https://github.com/getsentry/sentry-java/pull/6243)) - Decide whether foregrounding the app starts a new session on a monotonic clock instead of the wall clock, so that a device time change no longer starts a session that should have been resumed, or resumes one that should have ended. This affects session counts ([#6096](https://github.com/getsentry/sentry-java/pull/6096)) +### Features + +- Add policy-controlled URL query parameters and fragments to Ktor HTTP client spans ([#6433](https://github.com/getsentry/sentry-java/pull/6433)) + ## 8.62.0 ### Improvements