From 3f6f6363ccf0d0cab858b8f0191fd6b9fe382ffd Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 17 Aug 2023 09:02:01 +0200 Subject: [PATCH] Send `http.request.method` in span data (#2896) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sentry Github Bot --- CHANGELOG.md | 1 + .../java/io/sentry/android/okhttp/SentryOkHttpEvent.kt | 3 ++- .../java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt | 4 +++- .../java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt | 4 +++- .../main/java/io/sentry/apollo/SentryApolloInterceptor.kt | 7 +++++++ .../java/io/sentry/apollo/SentryApolloInterceptorTest.kt | 3 +++ .../main/java/io/sentry/openfeign/SentryFeignClient.java | 5 ++++- .../kotlin/io/sentry/openfeign/SentryFeignClientTest.kt | 1 + .../tracing/SentrySpanClientHttpRequestInterceptor.java | 2 ++ .../jakarta/tracing/SentrySpanClientWebRequestFilter.java | 5 ++++- .../tracing/SentrySpanClientHttpRequestInterceptor.java | 2 ++ .../spring/tracing/SentrySpanClientWebRequestFilter.java | 5 ++++- sentry/src/main/java/io/sentry/SpanDataConvention.java | 2 +- 13 files changed, 37 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c144697113..fc75708ecb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Features - Send `db.system` and `db.name` in span data ([#2894](https://github.com/getsentry/sentry-java/pull/2894)) +- Send `http.request.method` in span data ([#2896](https://github.com/getsentry/sentry-java/pull/2896)) ## 6.28.0 diff --git a/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpEvent.kt b/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpEvent.kt index e96829e12e..8a3414b663 100644 --- a/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpEvent.kt +++ b/sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpEvent.kt @@ -17,6 +17,7 @@ import io.sentry.android.okhttp.SentryOkHttpEventListener.Companion.SECURE_CONNE import io.sentry.util.UrlUtils import okhttp3.Request import okhttp3.Response +import java.util.Locale import java.util.concurrent.ConcurrentHashMap private const val PROTOCOL_KEY = "protocol" @@ -50,7 +51,7 @@ internal class SentryOkHttpEvent(private val hub: IHub, private val request: Req callRootSpan?.setData("url", url) callRootSpan?.setData("host", host) callRootSpan?.setData("path", encodedPath) - callRootSpan?.setData(SpanDataConvention.HTTP_METHOD_KEY, method) + callRootSpan?.setData(SpanDataConvention.HTTP_METHOD_KEY, method.toUpperCase(Locale.ROOT)) } /** diff --git a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt index 906af7c8c6..2276272fe7 100644 --- a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt +++ b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt @@ -20,6 +20,7 @@ import io.sentry.SentryIntegrationPackageStorage import io.sentry.SentryLevel import io.sentry.SentryOptions.DEFAULT_PROPAGATION_TARGETS import io.sentry.SpanDataConvention +import io.sentry.SpanDataConvention.HTTP_METHOD_KEY import io.sentry.SpanStatus import io.sentry.TypeCheckHint.APOLLO_REQUEST import io.sentry.TypeCheckHint.APOLLO_RESPONSE @@ -34,6 +35,7 @@ import io.sentry.util.UrlUtils import io.sentry.vendor.Base64 import okio.Buffer import org.jetbrains.annotations.ApiStatus +import java.util.Locale private const val TRACE_ORIGIN = "auto.graphql.apollo3" @@ -171,7 +173,7 @@ class SentryApollo3HttpInterceptor @JvmOverloads constructor( variables?.let { setData("variables", it) } - setData("http.method", method) + setData(HTTP_METHOD_KEY, method.toUpperCase(Locale.ROOT)) } } 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 d197eeae4a..5b9ab99886 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 @@ -18,6 +18,7 @@ import io.sentry.SentryOptions.DEFAULT_PROPAGATION_TARGETS import io.sentry.SentryTraceHeader import io.sentry.SentryTracer import io.sentry.SpanDataConvention +import io.sentry.SpanDataConvention.HTTP_METHOD_KEY import io.sentry.SpanStatus import io.sentry.TraceContext import io.sentry.TracesSamplingDecision @@ -154,6 +155,7 @@ class SentryApollo3InterceptorTest { verify(fixture.hub).captureTransaction( check { assertTransactionDetails(it, httpStatusCode = 404, contentLength = null) + assertEquals("POST", it.spans.first().data?.get(SpanDataConvention.HTTP_METHOD_KEY)) assertEquals(404, it.spans.first().data?.get(SpanDataConvention.HTTP_STATUS_CODE_KEY)) assertEquals(SpanStatus.NOT_FOUND, it.spans.first().status) }, @@ -314,7 +316,7 @@ class SentryApollo3InterceptorTest { assertTrue { httpClientSpan.description?.startsWith("Post LaunchDetails") == true } assertNotNull(httpClientSpan.data) { assertNotNull(it["operationId"]) - assertEquals("Post", it["http.method"]) + assertEquals("POST", it[HTTP_METHOD_KEY]) httpStatusCode?.let { code -> assertEquals(code, it[SpanDataConvention.HTTP_STATUS_CODE_KEY]) } diff --git a/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt b/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt index bc8e37d83e..0a11e1b762 100644 --- a/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt +++ b/sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt @@ -26,6 +26,7 @@ import io.sentry.SpanStatus import io.sentry.TypeCheckHint.APOLLO_REQUEST import io.sentry.TypeCheckHint.APOLLO_RESPONSE import io.sentry.util.TracingUtils +import java.util.Locale import java.util.concurrent.Executor private const val TRACE_ORIGIN = "auto.graphql.apollo" @@ -72,6 +73,12 @@ class SentryApolloInterceptor( } else { span.status = SpanStatus.UNKNOWN } + response.httpResponse.map { it.request().method() }.orNull()?.let { + span.setData( + SpanDataConvention.HTTP_METHOD_KEY, + it.toUpperCase(Locale.ROOT) + ) + } finish(span, requestWithHeader, response) callBack.onResponse(response) 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 67e19112ca..f45c310601 100644 --- a/sentry-apollo/src/test/java/io/sentry/apollo/SentryApolloInterceptorTest.kt +++ b/sentry-apollo/src/test/java/io/sentry/apollo/SentryApolloInterceptorTest.kt @@ -100,6 +100,7 @@ class SentryApolloInterceptorTest { check { assertTransactionDetails(it) assertEquals(SpanStatus.OK, it.spans.first().status) + assertEquals("POST", it.spans.first().data?.get(SpanDataConvention.HTTP_METHOD_KEY)) }, anyOrNull(), anyOrNull(), @@ -116,6 +117,8 @@ class SentryApolloInterceptorTest { assertTransactionDetails(it) assertEquals(SpanStatus.PERMISSION_DENIED, it.spans.first().status) assertEquals(403, it.spans.first().data?.get(SpanDataConvention.HTTP_STATUS_CODE_KEY)) + // we do not have access to the request and method in case of an error + assertNull(it.spans.first().data?.get(SpanDataConvention.HTTP_METHOD_KEY)) }, anyOrNull(), anyOrNull(), diff --git a/sentry-openfeign/src/main/java/io/sentry/openfeign/SentryFeignClient.java b/sentry-openfeign/src/main/java/io/sentry/openfeign/SentryFeignClient.java index ca93bd8832..cb8aa3d9e0 100644 --- a/sentry-openfeign/src/main/java/io/sentry/openfeign/SentryFeignClient.java +++ b/sentry-openfeign/src/main/java/io/sentry/openfeign/SentryFeignClient.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.Locale; import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -56,7 +57,9 @@ public Response execute(final @NotNull Request request, final @NotNull Request.O ISpan span = activeSpan.startChild("http.client"); span.getSpanContext().setOrigin(TRACE_ORIGIN); final @NotNull UrlUtils.UrlDetails urlDetails = UrlUtils.parse(request.url()); - span.setDescription(request.httpMethod().name() + " " + urlDetails.getUrlOrFallback()); + final @NotNull String method = request.httpMethod().name(); + span.setDescription(method + " " + urlDetails.getUrlOrFallback()); + span.setData(SpanDataConvention.HTTP_METHOD_KEY, method.toUpperCase(Locale.ROOT)); urlDetails.applyToSpan(span); final @NotNull Request modifiedRequest = maybeAddTracingHeaders(request, span); 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 07e5910523..65e56ab02b 100644 --- a/sentry-openfeign/src/test/kotlin/io/sentry/openfeign/SentryFeignClientTest.kt +++ b/sentry-openfeign/src/test/kotlin/io/sentry/openfeign/SentryFeignClientTest.kt @@ -167,6 +167,7 @@ class SentryFeignClientTest { assertEquals("http.client", httpClientSpan.operation) assertEquals("GET ${fixture.server.url("/status/200")}", httpClientSpan.description) assertEquals(201, httpClientSpan.data[SpanDataConvention.HTTP_STATUS_CODE_KEY]) + assertEquals("GET", httpClientSpan.data[SpanDataConvention.HTTP_METHOD_KEY]) assertEquals(SpanStatus.OK, httpClientSpan.status) assertEquals("auto.http.openfeign", httpClientSpan.spanContext.origin) assertTrue(httpClientSpan.isFinished) diff --git a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/tracing/SentrySpanClientHttpRequestInterceptor.java b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/tracing/SentrySpanClientHttpRequestInterceptor.java index 1190d4c995..d190a0427d 100644 --- a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/tracing/SentrySpanClientHttpRequestInterceptor.java +++ b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/tracing/SentrySpanClientHttpRequestInterceptor.java @@ -16,6 +16,7 @@ import io.sentry.util.TracingUtils; import io.sentry.util.UrlUtils; import java.io.IOException; +import java.util.Locale; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.http.HttpRequest; @@ -53,6 +54,7 @@ public SentrySpanClientHttpRequestInterceptor(final @NotNull IHub hub) { request.getMethod() != null ? request.getMethod().name() : "unknown"; final @NotNull UrlUtils.UrlDetails urlDetails = UrlUtils.parse(request.getURI().toString()); span.setDescription(methodName + " " + urlDetails.getUrlOrFallback()); + span.setData(SpanDataConvention.HTTP_METHOD_KEY, methodName.toUpperCase(Locale.ROOT)); urlDetails.applyToSpan(span); maybeAddTracingHeaders(request, span); diff --git a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/tracing/SentrySpanClientWebRequestFilter.java b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/tracing/SentrySpanClientWebRequestFilter.java index 4e90a48759..4ac511721e 100644 --- a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/tracing/SentrySpanClientWebRequestFilter.java +++ b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/tracing/SentrySpanClientWebRequestFilter.java @@ -13,6 +13,7 @@ import io.sentry.SpanStatus; import io.sentry.util.Objects; import io.sentry.util.TracingUtils; +import java.util.Locale; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.web.reactive.function.client.ClientRequest; @@ -42,7 +43,9 @@ public SentrySpanClientWebRequestFilter(final @NotNull IHub hub) { final ISpan span = activeSpan.startChild("http.client"); span.getSpanContext().setOrigin(TRACE_ORIGIN); - span.setDescription(request.method().name() + " " + request.url()); + final @NotNull String method = request.method().name(); + span.setDescription(method + " " + request.url()); + span.setData(SpanDataConvention.HTTP_METHOD_KEY, method.toUpperCase(Locale.ROOT)); final @NotNull ClientRequest modifiedRequest = maybeAddTracingHeaders(request, span); diff --git a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientHttpRequestInterceptor.java b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientHttpRequestInterceptor.java index da3dffc3cb..4067c69c8c 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientHttpRequestInterceptor.java +++ b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientHttpRequestInterceptor.java @@ -16,6 +16,7 @@ import io.sentry.util.TracingUtils; import io.sentry.util.UrlUtils; import java.io.IOException; +import java.util.Locale; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.http.HttpRequest; @@ -54,6 +55,7 @@ public SentrySpanClientHttpRequestInterceptor(final @NotNull IHub hub) { final @NotNull UrlUtils.UrlDetails urlDetails = UrlUtils.parse(request.getURI().toString()); urlDetails.applyToSpan(span); span.setDescription(methodName + " " + urlDetails.getUrlOrFallback()); + span.setData(SpanDataConvention.HTTP_METHOD_KEY, methodName.toUpperCase(Locale.ROOT)); maybeAddTracingHeaders(request, span); diff --git a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientWebRequestFilter.java b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientWebRequestFilter.java index 1fce033a9d..00ad91bbb0 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientWebRequestFilter.java +++ b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientWebRequestFilter.java @@ -14,6 +14,7 @@ import io.sentry.util.Objects; import io.sentry.util.TracingUtils; import io.sentry.util.UrlUtils; +import java.util.Locale; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.web.reactive.function.client.ClientRequest; @@ -43,7 +44,9 @@ public SentrySpanClientWebRequestFilter(final @NotNull IHub hub) { final ISpan span = activeSpan.startChild("http.client"); span.getSpanContext().setOrigin(TRACE_ORIGIN); final @NotNull UrlUtils.UrlDetails urlDetails = UrlUtils.parse(request.url().toString()); - span.setDescription(request.method().name() + " " + urlDetails.getUrlOrFallback()); + final @NotNull String method = request.method().name(); + span.setDescription(method + " " + urlDetails.getUrlOrFallback()); + span.setData(SpanDataConvention.HTTP_METHOD_KEY, method.toUpperCase(Locale.ROOT)); urlDetails.applyToSpan(span); final ClientRequest clientRequestWithSentryTraceHeader = maybeAddHeaders(request, span); diff --git a/sentry/src/main/java/io/sentry/SpanDataConvention.java b/sentry/src/main/java/io/sentry/SpanDataConvention.java index bffae1206a..e08736d646 100644 --- a/sentry/src/main/java/io/sentry/SpanDataConvention.java +++ b/sentry/src/main/java/io/sentry/SpanDataConvention.java @@ -10,7 +10,7 @@ public interface SpanDataConvention { String DB_NAME_KEY = "db.name"; String HTTP_QUERY_KEY = "http.query"; String HTTP_FRAGMENT_KEY = "http.fragment"; - String HTTP_METHOD_KEY = "http.method"; + String HTTP_METHOD_KEY = "http.request.method"; String HTTP_STATUS_CODE_KEY = "http.response.status_code"; String HTTP_RESPONSE_CONTENT_LENGTH_KEY = "http.response_content_length"; String BLOCKED_MAIN_THREAD_KEY = "blocked_main_thread";