From 1e045390dc42cd08614cafa787b5424b75fad0fd Mon Sep 17 00:00:00 2001 From: Marcus Dunn Date: Fri, 21 Mar 2025 14:50:58 -0700 Subject: [PATCH 1/5] added url template. --- .../api/semconv/http/HttpClientAttributesGetter.java | 4 +++- .../api/semconv/http/HttpSpanNameExtractor.java | 3 ++- .../api/semconv/url/UrlAttributesGetter.java | 10 ++++++++++ .../url/internal/InternalUrlAttributesExtractor.java | 3 +++ .../ktor/v2_0/common/KtorHttpClientAttributesGetter.kt | 4 ++++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesGetter.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesGetter.java index d81eb582f2a0..e0e7533ebd14 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesGetter.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesGetter.java @@ -7,6 +7,7 @@ import io.opentelemetry.instrumentation.api.semconv.network.NetworkAttributesGetter; import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesGetter; +import io.opentelemetry.instrumentation.api.semconv.url.UrlAttributesGetter; import javax.annotation.Nullable; /** @@ -21,7 +22,8 @@ public interface HttpClientAttributesGetter extends HttpCommonAttributesGetter, NetworkAttributesGetter, - ServerAttributesGetter { + ServerAttributesGetter, + UrlAttributesGetter { /** * Returns the absolute URL describing a network resource according to implements SpanNameExtractor { @Override public String extract(REQUEST request) { String method = getter.getHttpRequestMethod(request); + String template = getter.getUrlTemplate(request); if (method == null || !knownMethods.contains(method)) { return "HTTP"; } - return method; + return template == null ? method : method + " " + template; } } diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/UrlAttributesGetter.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/UrlAttributesGetter.java index 3d04836bebd2..30acfdec0c16 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/UrlAttributesGetter.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/UrlAttributesGetter.java @@ -50,4 +50,14 @@ default String getUrlPath(REQUEST request) { default String getUrlQuery(REQUEST request) { return null; } + + /** + * Returns the template used to build the full URL (if available) + * + *

Examples: {@code /users/{id}}; {@code /users?q={query}}

+ */ + @Nullable + default String getUrlTemplate(REQUEST request) { + return null; + } } diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/internal/InternalUrlAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/internal/InternalUrlAttributesExtractor.java index 37103b0c6983..f259c8ab80ee 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/internal/InternalUrlAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/internal/InternalUrlAttributesExtractor.java @@ -7,6 +7,7 @@ import static io.opentelemetry.instrumentation.api.internal.AttributesExtractorUtil.internalSet; +import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.instrumentation.api.semconv.url.UrlAttributesGetter; import io.opentelemetry.semconv.UrlAttributes; @@ -31,10 +32,12 @@ public void onStart(AttributesBuilder attributes, REQUEST request) { String urlScheme = getUrlScheme(request); String urlPath = getter.getUrlPath(request); String urlQuery = getter.getUrlQuery(request); + String urlTemplate = getter.getUrlTemplate(request); internalSet(attributes, UrlAttributes.URL_SCHEME, urlScheme); internalSet(attributes, UrlAttributes.URL_PATH, urlPath); internalSet(attributes, UrlAttributes.URL_QUERY, urlQuery); + internalSet(attributes, AttributeKey.stringKey("url.template"), urlTemplate); } private String getUrlScheme(REQUEST request) { diff --git a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/KtorHttpClientAttributesGetter.kt b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/KtorHttpClientAttributesGetter.kt index 64df11c673e6..0f624158b04e 100644 --- a/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/KtorHttpClientAttributesGetter.kt +++ b/instrumentation/ktor/ktor-2-common/library/src/main/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/common/KtorHttpClientAttributesGetter.kt @@ -7,6 +7,7 @@ package io.opentelemetry.instrumentation.ktor.v2_0.common import io.ktor.client.request.* import io.ktor.client.statement.* +import io.ktor.util.AttributeKey import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter internal object KtorHttpClientAttributesGetter : HttpClientAttributesGetter { @@ -34,4 +35,7 @@ internal object KtorHttpClientAttributesGetter : HttpClientAttributesGetter("URL_TEMPLATE") + override fun getUrlTemplate(request: HttpRequestData): String? = request.attributes.getOrNull(urlTemplateAttributeKey) } From 053472131bcf59f359bee3b175eb12a7a50e73f8 Mon Sep 17 00:00:00 2001 From: Marcus Dunn Date: Fri, 21 Mar 2025 14:57:43 -0700 Subject: [PATCH 2/5] added a test --- .../api/semconv/http/HttpSpanNameExtractorTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractorTest.java b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractorTest.java index 0c59545984a2..d87568ba2979 100644 --- a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractorTest.java +++ b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractorTest.java @@ -46,4 +46,11 @@ void nothing() { assertThat(HttpSpanNameExtractor.create(clientGetter).extract(Collections.emptyMap())) .isEqualTo("HTTP"); } + + @Test + void templateAndMethod() { + when(clientGetter.getUrlTemplate(anyMap())).thenReturn("/cats/{id}"); + when(clientGetter.getHttpRequestMethod(anyMap())).thenReturn("GET"); + assertThat(HttpSpanNameExtractor.create(clientGetter).extract(Collections.emptyMap())).isEqualTo("GET /cats/{id}"); + } } From ae719d52614d57a7e07836b9b0840821873a1359 Mon Sep 17 00:00:00 2001 From: Marcus Dunn Date: Fri, 21 Mar 2025 14:58:00 -0700 Subject: [PATCH 3/5] added source compatability check --- .../opentelemetry-instrumentation-api.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt b/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt index d1692462b6fd..c5846e2d2586 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt @@ -1,2 +1,10 @@ Comparing source compatibility of opentelemetry-instrumentation-api-2.15.0-SNAPSHOT.jar against opentelemetry-instrumentation-api-2.14.0.jar -No changes. \ No newline at end of file +*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + GENERIC TEMPLATES: === REQUEST:java.lang.Object, === RESPONSE:java.lang.Object + +++ NEW INTERFACE: io.opentelemetry.instrumentation.api.semconv.url.UrlAttributesGetter +*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.instrumentation.api.semconv.url.UrlAttributesGetter (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + GENERIC TEMPLATES: === REQUEST:java.lang.Object + +++ NEW METHOD: PUBLIC(+) java.lang.String getUrlTemplate(java.lang.Object) + +++ NEW ANNOTATION: javax.annotation.Nullable From 2b8828f1f6cb7b92fc740b58afdd52fc8e2b6f5a Mon Sep 17 00:00:00 2001 From: Marcus Dunn Date: Fri, 21 Mar 2025 15:20:06 -0700 Subject: [PATCH 4/5] spotless --- .../instrumentation/api/semconv/url/UrlAttributesGetter.java | 2 +- .../api/semconv/http/HttpSpanNameExtractorTest.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/UrlAttributesGetter.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/UrlAttributesGetter.java index 30acfdec0c16..844e3654fba4 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/UrlAttributesGetter.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/url/UrlAttributesGetter.java @@ -54,7 +54,7 @@ default String getUrlQuery(REQUEST request) { /** * Returns the template used to build the full URL (if available) * - *

Examples: {@code /users/{id}}; {@code /users?q={query}}

+ *

Examples: {@code /users/{id}}; {@code /users?q={query}} */ @Nullable default String getUrlTemplate(REQUEST request) { diff --git a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractorTest.java b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractorTest.java index d87568ba2979..51adf205c52b 100644 --- a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractorTest.java +++ b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractorTest.java @@ -51,6 +51,7 @@ void nothing() { void templateAndMethod() { when(clientGetter.getUrlTemplate(anyMap())).thenReturn("/cats/{id}"); when(clientGetter.getHttpRequestMethod(anyMap())).thenReturn("GET"); - assertThat(HttpSpanNameExtractor.create(clientGetter).extract(Collections.emptyMap())).isEqualTo("GET /cats/{id}"); + assertThat(HttpSpanNameExtractor.create(clientGetter).extract(Collections.emptyMap())) + .isEqualTo("GET /cats/{id}"); } } From 55c026737c3b7976c1fb0f890186c16f062f2cde Mon Sep 17 00:00:00 2001 From: Marcus Dunn Date: Sat, 22 Mar 2025 09:04:33 -0700 Subject: [PATCH 5/5] do not fetch template if there will be an early return --- .../instrumentation/api/semconv/http/HttpSpanNameExtractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractor.java index d676c337baff..7ee0085c37f3 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpSpanNameExtractor.java @@ -70,10 +70,10 @@ static final class Client implements SpanNameExtractor { @Override public String extract(REQUEST request) { String method = getter.getHttpRequestMethod(request); - String template = getter.getUrlTemplate(request); if (method == null || !knownMethods.contains(method)) { return "HTTP"; } + String template = getter.getUrlTemplate(request); return template == null ? method : method + " " + template; } }