diff --git a/docs/src/main/asciidoc/opentelemetry.adoc b/docs/src/main/asciidoc/opentelemetry.adoc index c4878da8bfc74..fbb182223cda5 100644 --- a/docs/src/main/asciidoc/opentelemetry.adoc +++ b/docs/src/main/asciidoc/opentelemetry.adoc @@ -21,6 +21,7 @@ https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/au with the `quarkus.*` prefix. - Extensions and the libraries they provide, are directly instrumented in Quarkus. The *use of the https://opentelemetry.io/docs/instrumentation/java/automatic/[OpenTelemetry Agent] is not needed nor recommended* due to context propagation issues between imperative and reactive libraries. - If you come from the legacy OpenTracing extension, there is a xref:telemetry-opentracing-to-otel-tutorial.adoc[guide to help with the migration]. +- Current Semantic Conventions for HTTP will soon change and the current conventions are deprecated for removal soon. Please move to the new conventions by seetinh the new property `quarkus.otel.semconv-stability.opt-in` to `http`, for the new conventions or `http/dup` to produce duplicated old and new conventions. Please check the <> for more details and full set of changes at the https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/migration-guide.md#summary-of-changes[HTTP semantic convention stability migration guide]. ==== == Prerequisites diff --git a/extensions/opentelemetry/deployment/pom.xml b/extensions/opentelemetry/deployment/pom.xml index 145fbfdad10d9..bccf605a4dfb5 100644 --- a/extensions/opentelemetry/deployment/pom.xml +++ b/extensions/opentelemetry/deployment/pom.xml @@ -143,6 +143,38 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + + + new-http-semconv + + test + + + + http + + + + + http-dup-semconv + + test + + + + http/dup + + + + + + org.xolstice.maven.plugins protobuf-maven-plugin diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java index 4238f8b615937..b5b404f9f8120 100644 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java +++ b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryProcessor.java @@ -2,6 +2,7 @@ import static io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem.SPI_ROOT; import static io.quarkus.opentelemetry.runtime.OpenTelemetryRecorder.OPEN_TELEMETRY_DRIVER; +import static io.quarkus.opentelemetry.runtime.OpenTelemetryUtil.*; import static java.util.stream.Collectors.toList; import java.io.IOException; @@ -93,6 +94,8 @@ public boolean test(AnnotationInstance annotationInstance) { private static final DotName WITH_SPAN_INTERCEPTOR = DotName.createSimple(WithSpanInterceptor.class.getName()); private static final DotName ADD_SPAN_ATTRIBUTES_INTERCEPTOR = DotName .createSimple(AddingSpanAttributesInterceptor.class.getName()); + private static final String QUARKUS_OTEL_SEMCONV_STABILITY_OPT_IN = "quarkus.otel.semconv-stability.opt-in"; + private static final String OTEL_SEMCONV_STABILITY_OPT_IN = "otel.semconv-stability.opt-in"; @BuildStep AdditionalBeanBuildItem ensureProducerIsRetained() { @@ -109,6 +112,15 @@ AdditionalBeanBuildItem ensureProducerIsRetained() { @BuildStep @Record(ExecutionTime.RUNTIME_INIT) SyntheticBeanBuildItem openTelemetryBean(OpenTelemetryRecorder recorder, OTelRuntimeConfig oTelRuntimeConfig) { + + final String semconvStability = ConfigProvider.getConfig() + .getConfigValue(QUARKUS_OTEL_SEMCONV_STABILITY_OPT_IN) + .getValue(); + if (semconvStability != null && !semconvStability.isEmpty()) { + // yes, they ignore config supplier on this. + System.setProperty(OTEL_SEMCONV_STABILITY_OPT_IN, semconvStability); + } + return SyntheticBeanBuildItem.configure(OpenTelemetry.class) .defaultBean() .setRuntimeInit() @@ -270,7 +282,11 @@ void setupVertx(InstrumentationRecorder recorder, BeanContainerBuildItem beanCon || capabilities.isPresent(Capability.REACTIVE_MYSQL_CLIENT) || capabilities.isPresent(Capability.REACTIVE_ORACLE_CLIENT) || capabilities.isPresent(Capability.REACTIVE_PG_CLIENT); - recorder.setupVertxTracer(beanContainerBuildItem.getValue(), sqlClientAvailable); + recorder.setupVertxTracer(beanContainerBuildItem.getValue(), + sqlClientAvailable, + ConfigProvider.getConfig() + .getConfigValue(QUARKUS_OTEL_SEMCONV_STABILITY_OPT_IN) + .getValue()); } @BuildStep diff --git a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/scheduler/OpenTelemetrySchedulerProcessor.java b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/scheduler/OpenTelemetrySchedulerProcessor.java index ecb8dbdd113f3..b90874320aff4 100644 --- a/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/scheduler/OpenTelemetrySchedulerProcessor.java +++ b/extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/scheduler/OpenTelemetrySchedulerProcessor.java @@ -6,7 +6,7 @@ import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.opentelemetry.deployment.OpenTelemetryEnabled; -import io.quarkus.opentelemetry.runtime.scheduler.OpenTelemetryJobInstrumenter; +import io.quarkus.opentelemetry.runtime.tracing.intrumentation.scheduler.OpenTelemetryJobInstrumenter; public class OpenTelemetrySchedulerProcessor { diff --git a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryTextMapPropagatorCustomizerTest.java b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryTextMapPropagatorCustomizerTest.java index 63236480a6356..caf4b0ccaad5e 100644 --- a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryTextMapPropagatorCustomizerTest.java +++ b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/OpenTelemetryTextMapPropagatorCustomizerTest.java @@ -26,9 +26,9 @@ import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.sdk.trace.data.SpanData; -import io.quarkus.opentelemetry.TextMapPropagatorCustomizer; import io.quarkus.opentelemetry.deployment.common.TestSpanExporter; import io.quarkus.opentelemetry.deployment.common.TestSpanExporterProvider; +import io.quarkus.opentelemetry.runtime.propagation.TextMapPropagatorCustomizer; import io.quarkus.test.QuarkusUnitTest; public class OpenTelemetryTextMapPropagatorCustomizerTest { diff --git a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/common/SemconvResolver.java b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/common/SemconvResolver.java new file mode 100644 index 0000000000000..ca6f18bc99d49 --- /dev/null +++ b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/common/SemconvResolver.java @@ -0,0 +1,138 @@ +package io.quarkus.opentelemetry.deployment.common; + +import static io.opentelemetry.api.common.AttributeType.LONG; +import static io.opentelemetry.api.common.AttributeType.STRING; +import static io.opentelemetry.semconv.SemanticAttributes.HTTP_TARGET; +import static io.opentelemetry.semconv.SemanticAttributes.URL_PATH; +import static io.opentelemetry.semconv.SemanticAttributes.URL_QUERY; +import static io.quarkus.opentelemetry.runtime.config.runtime.SemconvStabilityType.HTTP; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.HashMap; +import java.util.Map; + +import org.jboss.logging.Logger; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.quarkus.opentelemetry.runtime.OpenTelemetryUtil; +import io.quarkus.opentelemetry.runtime.config.runtime.SemconvStabilityType; + +public class SemconvResolver { + + public static final SemconvStabilityType SEMCONV_STABILITY_TYPE; + private static final Map conventionsMapper = new HashMap<>(); + private static final Logger log = Logger.getLogger(SemconvResolver.class); + + static { + SEMCONV_STABILITY_TYPE = OpenTelemetryUtil.getSemconvStabilityOptin( + System.getProperty("quarkus.otel.semconv-stability.opt-in", "stable")); + + log.info("Using semantic convention stability type: " + SEMCONV_STABILITY_TYPE); + + conventionsMapper.put("http.method", "http.request.method"); + conventionsMapper.put("http.status_code", "http.response.status_code"); + conventionsMapper.put("http.request_content_length", "http.request.body.size"); + conventionsMapper.put("http.response_content_length", "http.request.body.size"); + conventionsMapper.put("net.protocol.name", "network.protocol.name"); + conventionsMapper.put("net.protocol.version", "network.protocol.version"); + // net.sock.family removed + conventionsMapper.put("net.sock.peer.addr", "network.peer.address"); + conventionsMapper.put("net.sock.peer.port", "network.peer.port"); + // net.sock.peer.name removed + // New: http.request.method_original + // New: error.type + conventionsMapper.put("http.url", "url.full"); + conventionsMapper.put("http.resend_count", "http.request.resend_count"); + conventionsMapper.put("net.peer.name", "server.address"); + conventionsMapper.put("net.peer.port", "server.port"); + // http.target split into url.path and url.query + conventionsMapper.put("http.scheme", "url.scheme"); + conventionsMapper.put("http.client_ip", "client.address"); + conventionsMapper.put("net.host.name", "server.address"); + conventionsMapper.put("net.host.port", "server.port"); + + } + + SemconvResolver() { + // empty + } + + public static void assertTarget(final SpanData server, final String path, final String query) { + switch (SEMCONV_STABILITY_TYPE) { + case HTTP: + assertEquals(path, server.getAttributes().get(URL_PATH)); + assertEquals(query, server.getAttributes().get(URL_QUERY)); + break; + case HTTP_DUP: + assertEquals(path, server.getAttributes().get(URL_PATH)); + assertEquals(query, server.getAttributes().get(URL_QUERY)); + assertEquals("" + path + (query == null ? "" : "?" + query), server.getAttributes().get(HTTP_TARGET)); + break; + case HTTP_OLD: + assertEquals("" + path + (query == null ? "" : "?" + query), server.getAttributes().get(HTTP_TARGET)); + break; + default: + throw new IllegalArgumentException("Unsupported semantic convention stability type: " + SEMCONV_STABILITY_TYPE); + } + } + + public static void assertSemanticAttribute(final SpanData spanData, final T expected, + final AttributeKey attribute) { + switch (SEMCONV_STABILITY_TYPE) { + case HTTP: + assertEquals(expected, getNewAttribute(spanData, attribute)); + break; + case HTTP_DUP: + assertEquals(expected, getNewAttribute(spanData, attribute)); // assert new semantic convention + assertEquals(expected, spanData.getAttributes().get(attribute)); // assert old semantic convention + break; + case HTTP_OLD: + assertEquals(expected, spanData.getAttributes().get(attribute)); // assert old semantic convention + break; + default: + throw new IllegalArgumentException("Unsupported semantic convention stability type: " + SEMCONV_STABILITY_TYPE); + } + } + + public static void assertNotNullSemanticAttribute(final SpanData spanData, + final AttributeKey attribute) { + switch (SemconvResolver.SEMCONV_STABILITY_TYPE) { + case HTTP: + assertNotNull(getNewAttribute(spanData, attribute)); + break; + case HTTP_DUP: + assertNotNull(getNewAttribute(spanData, attribute)); // assert new semantic convention + assertNotNull(spanData.getAttributes().get(attribute)); // assert old semantic convention + break; + case HTTP_OLD: + assertNotNull(spanData.getAttributes().get(attribute)); // assert old semantic convention + break; + default: + throw new IllegalArgumentException( + "Unsupported semantic convention stability type: " + SemconvResolver.SEMCONV_STABILITY_TYPE); + } + } + + @SuppressWarnings("unchecked") + private static T getNewAttribute(final SpanData data, final AttributeKey legacyAttributeKey) { + if (legacyAttributeKey.getType().equals(LONG)) { + return (T) data.getAttributes().get(resolveLong((AttributeKey) legacyAttributeKey)); + } else if (legacyAttributeKey.getType().equals(STRING)) { + return (T) data.getAttributes().get(resolveString((AttributeKey) legacyAttributeKey)); + } else { + throw new IllegalArgumentException( + "Unsupported attribute: " + legacyAttributeKey.getKey() + + " with type: " + legacyAttributeKey.getKey().getClass()); + } + } + + private static AttributeKey resolveString(final AttributeKey legacyKey) { + return AttributeKey.stringKey(conventionsMapper.get(legacyKey.getKey())); + } + + private static AttributeKey resolveLong(final AttributeKey legacyKey) { + return AttributeKey.longKey(conventionsMapper.get(legacyKey.getKey())); + } +} diff --git a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/GraphQLOpenTelemetryTest.java b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/GraphQLOpenTelemetryTest.java index 0985ac324ac7f..b685abb0ec4c4 100644 --- a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/GraphQLOpenTelemetryTest.java +++ b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/GraphQLOpenTelemetryTest.java @@ -4,6 +4,7 @@ import static io.opentelemetry.semconv.SemanticAttributes.HTTP_METHOD; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_ROUTE; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_STATUS_CODE; +import static io.quarkus.opentelemetry.deployment.common.SemconvResolver.assertSemanticAttribute; import static io.quarkus.opentelemetry.deployment.common.TestSpanExporter.getSpanByKindAndParentId; import static java.net.HttpURLConnection.HTTP_OK; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -45,6 +46,7 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.instrumentation.annotations.WithSpan; import io.opentelemetry.sdk.trace.data.SpanData; +import io.quarkus.opentelemetry.deployment.common.SemconvResolver; import io.quarkus.opentelemetry.deployment.common.TestSpanExporter; import io.quarkus.opentelemetry.deployment.common.TestSpanExporterProvider; import io.quarkus.test.QuarkusUnitTest; @@ -56,7 +58,7 @@ public class GraphQLOpenTelemetryTest { static QuarkusUnitTest test = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClasses(HelloResource.class, CustomCDIBean.class, TestSpanExporterProvider.class, - TestSpanExporter.class) + TestSpanExporter.class, SemconvResolver.class) .addAsResource(new StringAsset("smallrye.graphql.allowGet=true"), "application.properties") .addAsResource(new StringAsset("smallrye.graphql.printDataFetcherException=true"), "application.properties") .addAsResource(new StringAsset("smallrye.graphql.events.enabled=true"), "application.properties") @@ -279,10 +281,9 @@ private void assertTimeForSpans(List spans) { private SpanData assertHttpSpan(List spans) { final SpanData server = getSpanByKindAndParentId(spans, SpanKind.SERVER, "0000000000000000"); assertEquals("POST /graphql", server.getName()); - assertEquals(HTTP_OK, server.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals("POST", server.getAttributes().get(HTTP_METHOD)); + assertSemanticAttribute(server, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(server, "POST", HTTP_METHOD); assertEquals("/graphql", server.getAttributes().get(HTTP_ROUTE)); - return server; } diff --git a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/GrpcOpenTelemetryTest.java b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/GrpcOpenTelemetryTest.java index 44afa0881b142..e9d3d4c42c7b2 100644 --- a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/GrpcOpenTelemetryTest.java +++ b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/GrpcOpenTelemetryTest.java @@ -10,11 +10,11 @@ import static io.opentelemetry.semconv.SemanticAttributes.RPC_METHOD; import static io.opentelemetry.semconv.SemanticAttributes.RPC_SERVICE; import static io.opentelemetry.semconv.SemanticAttributes.RPC_SYSTEM; +import static io.quarkus.opentelemetry.deployment.common.SemconvResolver.assertNotNullSemanticAttribute; import static io.quarkus.opentelemetry.deployment.common.TestSpanExporter.getSpanByKindAndParentId; import static io.quarkus.opentelemetry.runtime.config.build.OTelBuildConfig.INSTRUMENTATION_NAME; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -58,6 +58,7 @@ import io.quarkus.opentelemetry.deployment.StreamingClient; import io.quarkus.opentelemetry.deployment.StreamingGrpc; import io.quarkus.opentelemetry.deployment.StreamingProto; +import io.quarkus.opentelemetry.deployment.common.SemconvResolver; import io.quarkus.opentelemetry.deployment.common.TestSpanExporter; import io.quarkus.opentelemetry.deployment.common.TestSpanExporterProvider; import io.quarkus.test.QuarkusUnitTest; @@ -68,7 +69,7 @@ public class GrpcOpenTelemetryTest { @RegisterExtension static final QuarkusUnitTest TEST = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar - .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class) + .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class, SemconvResolver.class) .addClasses(HelloService.class) .addClasses(GreeterGrpc.class, MutinyGreeterGrpc.class, Greeter.class, GreeterBean.class, GreeterClient.class, @@ -124,8 +125,8 @@ void grpc() { assertEquals("helloworld.Greeter", server.getAttributes().get(RPC_SERVICE)); assertEquals("SayHello", server.getAttributes().get(RPC_METHOD)); assertEquals(Status.Code.OK.value(), server.getAttributes().get(RPC_GRPC_STATUS_CODE)); - assertNotNull(server.getAttributes().get(NET_HOST_PORT)); - assertNotNull(server.getAttributes().get(NET_HOST_NAME)); + assertNotNullSemanticAttribute(server, NET_HOST_PORT); + assertNotNullSemanticAttribute(server, NET_HOST_NAME); final SpanData internal = getSpanByKindAndParentId(spans, INTERNAL, server.getSpanId()); assertEquals("span.internal", internal.getName()); @@ -162,8 +163,8 @@ void error() { assertEquals("helloworld.Greeter", server.getAttributes().get(RPC_SERVICE)); assertEquals("SayHello", server.getAttributes().get(RPC_METHOD)); assertEquals(Status.Code.UNKNOWN.value(), server.getAttributes().get(RPC_GRPC_STATUS_CODE)); - assertNotNull(server.getAttributes().get(NET_HOST_PORT)); - assertNotNull(server.getAttributes().get(NET_HOST_NAME)); + assertNotNullSemanticAttribute(server, NET_HOST_PORT); + assertNotNullSemanticAttribute(server, NET_HOST_NAME); assertEquals(Status.Code.UNKNOWN.value(), server.getAttributes().get(RPC_GRPC_STATUS_CODE)); assertEquals(server.getTraceId(), client.getTraceId()); @@ -213,8 +214,8 @@ void streaming() { assertEquals("streaming.Streaming", server.getAttributes().get(RPC_SERVICE)); assertEquals("Pipe", server.getAttributes().get(RPC_METHOD)); assertEquals(Status.Code.OK.value(), server.getAttributes().get(RPC_GRPC_STATUS_CODE)); - assertNotNull(server.getAttributes().get(NET_HOST_PORT)); - assertNotNull(server.getAttributes().get(NET_HOST_NAME)); + assertNotNullSemanticAttribute(server, NET_HOST_PORT); + assertNotNullSemanticAttribute(server, NET_HOST_NAME); assertEquals("true", server.getAttributes().get(stringKey("grpc.service.propagated"))); assertEquals(server.getTraceId(), client.getTraceId()); @@ -249,8 +250,8 @@ void streamingBlocking() { assertEquals("streaming.Streaming", server.getAttributes().get(RPC_SERVICE)); assertEquals("PipeBlocking", server.getAttributes().get(RPC_METHOD)); assertEquals(Status.Code.OK.value(), server.getAttributes().get(RPC_GRPC_STATUS_CODE)); - assertNotNull(server.getAttributes().get(NET_HOST_PORT)); - assertNotNull(server.getAttributes().get(NET_HOST_NAME)); + assertNotNullSemanticAttribute(server, NET_HOST_PORT); + assertNotNullSemanticAttribute(server, NET_HOST_NAME); assertEquals("true", server.getAttributes().get(stringKey("grpc.service.propagated.blocking"))); assertEquals(server.getTraceId(), client.getTraceId()); diff --git a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/RestClientOpenTelemetryTest.java b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/RestClientOpenTelemetryTest.java index 0ee590b103c22..4cff5b2f144b4 100644 --- a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/RestClientOpenTelemetryTest.java +++ b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/RestClientOpenTelemetryTest.java @@ -5,10 +5,11 @@ import static io.opentelemetry.semconv.SemanticAttributes.HTTP_METHOD; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_ROUTE; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_STATUS_CODE; -import static io.opentelemetry.semconv.SemanticAttributes.HTTP_TARGET; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_URL; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_NAME; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_PORT; +import static io.quarkus.opentelemetry.deployment.common.SemconvResolver.assertSemanticAttribute; +import static io.quarkus.opentelemetry.deployment.common.SemconvResolver.assertTarget; import static io.quarkus.opentelemetry.deployment.common.TestSpanExporter.getSpanByKindAndParentId; import static java.net.HttpURLConnection.HTTP_OK; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -35,6 +36,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import io.opentelemetry.sdk.trace.data.SpanData; +import io.quarkus.opentelemetry.deployment.common.SemconvResolver; import io.quarkus.opentelemetry.deployment.common.TestSpanExporter; import io.quarkus.opentelemetry.deployment.common.TestSpanExporterProvider; import io.quarkus.test.QuarkusUnitTest; @@ -43,7 +45,7 @@ public class RestClientOpenTelemetryTest { @RegisterExtension static final QuarkusUnitTest TEST = new QuarkusUnitTest().withApplicationRoot((jar) -> jar - .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class) + .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class, SemconvResolver.class) .addAsResource(new StringAsset(TestSpanExporterProvider.class.getCanonicalName()), "META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider")) .withConfigurationResource("application-default.properties") @@ -70,18 +72,18 @@ void client() { SpanData client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000"); assertEquals("GET", client.getName()); - assertEquals(HTTP_OK, client.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, client.getAttributes().get(HTTP_METHOD)); - assertEquals(uri.toString() + "hello", client.getAttributes().get(HTTP_URL)); + assertSemanticAttribute(client, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(client, HttpMethod.GET, HTTP_METHOD); + assertSemanticAttribute(client, uri.toString() + "hello", HTTP_URL); SpanData server = getSpanByKindAndParentId(spans, SERVER, client.getSpanId()); assertEquals("GET /hello", server.getName()); - assertEquals(HTTP_OK, server.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, server.getAttributes().get(HTTP_METHOD)); + assertSemanticAttribute(server, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(server, HttpMethod.GET, HTTP_METHOD); assertEquals("/hello", server.getAttributes().get(HTTP_ROUTE)); - assertEquals(uri.getHost(), server.getAttributes().get(NET_HOST_NAME)); - assertEquals(uri.getPort(), server.getAttributes().get(NET_HOST_PORT)); - assertEquals(uri.getPath() + "hello", server.getAttributes().get(HTTP_TARGET)); + assertSemanticAttribute(server, uri.getHost(), NET_HOST_NAME); + assertSemanticAttribute(server, (long) uri.getPort(), NET_HOST_PORT); + assertTarget(server, uri.getPath() + "hello", null); assertEquals(client.getTraceId(), server.getTraceId()); } @@ -95,9 +97,9 @@ void spanNameWithoutQueryString() { SpanData client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000"); assertEquals(CLIENT, client.getKind()); assertEquals("GET", client.getName()); - assertEquals(HTTP_OK, client.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, client.getAttributes().get(HTTP_METHOD)); - assertEquals(uri.toString() + "hello?query=1", client.getAttributes().get(HTTP_URL)); + assertSemanticAttribute(client, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(client, HttpMethod.GET, HTTP_METHOD); + assertSemanticAttribute(client, uri.toString() + "hello?query=1", HTTP_URL); SpanData server = getSpanByKindAndParentId(spans, SERVER, client.getSpanId()); assertEquals(client.getTraceId(), server.getTraceId()); @@ -114,9 +116,9 @@ void urlWithoutAuthentication() { SpanData client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000"); assertEquals(CLIENT, client.getKind()); assertEquals("GET", client.getName()); - assertEquals(HTTP_OK, client.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, client.getAttributes().get(HTTP_METHOD)); - assertEquals(uri.toString() + "hello?query=1", client.getAttributes().get(HTTP_URL)); + assertSemanticAttribute(client, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(client, HttpMethod.GET, HTTP_METHOD); + assertSemanticAttribute(client, uri.toString() + "hello?query=1", HTTP_URL); SpanData server = getSpanByKindAndParentId(spans, SERVER, client.getSpanId()); assertEquals(client.getTraceId(), server.getTraceId()); @@ -131,20 +133,19 @@ void path() { SpanData client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000"); assertEquals(CLIENT, client.getKind()); assertEquals("GET", client.getName()); - assertEquals(HTTP_OK, client.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, client.getAttributes().get(HTTP_METHOD)); - assertEquals(uri.toString() + "hello/another", client.getAttributes().get(HTTP_URL)); + assertSemanticAttribute(client, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(client, HttpMethod.GET, HTTP_METHOD); + assertSemanticAttribute(client, uri.toString() + "hello/another", HTTP_URL); SpanData server = getSpanByKindAndParentId(spans, SERVER, client.getSpanId()); assertEquals(SERVER, server.getKind()); assertEquals("GET /hello/{path}", server.getName()); - assertEquals(HTTP_OK, server.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, server.getAttributes().get(HTTP_METHOD)); + assertSemanticAttribute(server, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(server, HttpMethod.GET, HTTP_METHOD); assertEquals("/hello/{path}", server.getAttributes().get(HTTP_ROUTE)); - assertEquals(uri.getHost(), server.getAttributes().get(NET_HOST_NAME)); - assertEquals(uri.getPort(), server.getAttributes().get(NET_HOST_PORT)); - assertEquals(uri.getPath() + "hello/another", server.getAttributes().get(HTTP_TARGET)); - + assertSemanticAttribute(server, uri.getHost(), NET_HOST_NAME); + assertSemanticAttribute(server, (long) uri.getPort(), NET_HOST_PORT); + assertTarget(server, uri.getPath() + "hello/another", null); assertEquals(client.getTraceId(), server.getTraceId()); } diff --git a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxClientOpenTelemetryTest.java b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxClientOpenTelemetryTest.java index e725a51525afa..bfde0e210a3e5 100644 --- a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxClientOpenTelemetryTest.java +++ b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxClientOpenTelemetryTest.java @@ -5,12 +5,13 @@ import static io.opentelemetry.semconv.SemanticAttributes.HTTP_METHOD; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_ROUTE; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_STATUS_CODE; -import static io.opentelemetry.semconv.SemanticAttributes.HTTP_TARGET; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_URL; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_NAME; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_PORT; import static io.opentelemetry.semconv.SemanticAttributes.NET_PEER_NAME; import static io.opentelemetry.semconv.SemanticAttributes.NET_PEER_PORT; +import static io.quarkus.opentelemetry.deployment.common.SemconvResolver.assertSemanticAttribute; +import static io.quarkus.opentelemetry.deployment.common.SemconvResolver.assertTarget; import static io.quarkus.opentelemetry.deployment.common.TestSpanExporter.getSpanByKindAndParentId; import static java.net.HttpURLConnection.HTTP_OK; import static java.util.stream.Collectors.toSet; @@ -30,6 +31,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import io.opentelemetry.sdk.trace.data.SpanData; +import io.quarkus.opentelemetry.deployment.common.SemconvResolver; import io.quarkus.opentelemetry.deployment.common.TestSpanExporter; import io.quarkus.opentelemetry.deployment.common.TestSpanExporterProvider; import io.quarkus.runtime.StartupEvent; @@ -47,7 +49,7 @@ public class VertxClientOpenTelemetryTest { @RegisterExtension static final QuarkusUnitTest TEST = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar - .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class) + .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class, SemconvResolver.class) .addAsResource(new StringAsset(TestSpanExporterProvider.class.getCanonicalName()), "META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider")) .withConfigurationResource("application-default.properties"); @@ -78,21 +80,21 @@ void client() throws Exception { SpanData client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000"); assertEquals("GET", client.getName()); - assertEquals(HTTP_OK, client.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, client.getAttributes().get(HTTP_METHOD)); - assertEquals(uri.toString() + "hello", client.getAttributes().get(HTTP_URL)); - assertEquals(uri.getHost(), client.getAttributes().get(NET_PEER_NAME)); - assertEquals(uri.getPort(), client.getAttributes().get(NET_PEER_PORT)); + assertSemanticAttribute(client, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(client, HttpMethod.GET, HTTP_METHOD); + assertSemanticAttribute(client, uri.toString() + "hello", HTTP_URL); + assertSemanticAttribute(client, uri.getHost(), NET_PEER_NAME); + assertSemanticAttribute(client, (long) uri.getPort(), NET_PEER_PORT); SpanData server = getSpanByKindAndParentId(spans, SERVER, client.getSpanId()); assertEquals(SERVER, server.getKind()); assertEquals("GET /hello", server.getName()); - assertEquals(HTTP_OK, server.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, server.getAttributes().get(HTTP_METHOD)); + assertSemanticAttribute(server, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(server, HttpMethod.GET, HTTP_METHOD); assertEquals("/hello", server.getAttributes().get(HTTP_ROUTE)); - assertEquals(uri.getHost(), server.getAttributes().get(NET_HOST_NAME)); - assertEquals(uri.getPort(), server.getAttributes().get(NET_HOST_PORT)); - assertEquals(uri.getPath() + "hello", server.getAttributes().get(HTTP_TARGET)); + assertSemanticAttribute(server, uri.getHost(), NET_HOST_NAME); + assertSemanticAttribute(server, (long) uri.getPort(), NET_HOST_PORT); + assertTarget(server, uri.getPath() + "hello", null); assertEquals(client.getTraceId(), server.getTraceId()); } @@ -112,21 +114,21 @@ void path() throws Exception { SpanData client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000"); assertEquals(CLIENT, client.getKind()); assertEquals("GET", client.getName()); - assertEquals(HTTP_OK, client.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, client.getAttributes().get(HTTP_METHOD)); - assertEquals(uri.toString() + "hello/naruto", client.getAttributes().get(HTTP_URL)); - assertEquals(uri.getHost(), client.getAttributes().get(NET_PEER_NAME)); - assertEquals(uri.getPort(), client.getAttributes().get(NET_PEER_PORT)); + assertSemanticAttribute(client, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(client, HttpMethod.GET, HTTP_METHOD); + assertSemanticAttribute(client, uri.toString() + "hello/naruto", HTTP_URL); + assertSemanticAttribute(client, uri.getHost(), NET_PEER_NAME); + assertSemanticAttribute(client, (long) uri.getPort(), NET_PEER_PORT); SpanData server = getSpanByKindAndParentId(spans, SERVER, client.getSpanId()); assertEquals(SERVER, server.getKind()); assertEquals("GET /hello/:name", server.getName()); - assertEquals(HTTP_OK, server.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, server.getAttributes().get(HTTP_METHOD)); + assertSemanticAttribute(server, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(server, HttpMethod.GET, HTTP_METHOD); assertEquals("/hello/:name", server.getAttributes().get(HTTP_ROUTE)); - assertEquals(uri.getHost(), server.getAttributes().get(NET_HOST_NAME)); - assertEquals(uri.getPort(), server.getAttributes().get(NET_HOST_PORT)); - assertEquals(uri.getPath() + "hello/naruto", server.getAttributes().get(HTTP_TARGET)); + assertSemanticAttribute(server, uri.getHost(), NET_HOST_NAME); + assertSemanticAttribute(server, (long) uri.getPort(), NET_HOST_PORT); + assertTarget(server, uri.getPath() + "hello/naruto", null); assertEquals(client.getTraceId(), server.getTraceId()); } @@ -146,21 +148,21 @@ void query() throws Exception { SpanData client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000"); assertEquals(CLIENT, client.getKind()); assertEquals("GET", client.getName()); - assertEquals(HTTP_OK, client.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, client.getAttributes().get(HTTP_METHOD)); - assertEquals(uri.toString() + "hello?name=foo", client.getAttributes().get(HTTP_URL)); - assertEquals(uri.getHost(), client.getAttributes().get(NET_PEER_NAME)); - assertEquals(uri.getPort(), client.getAttributes().get(NET_PEER_PORT)); + assertSemanticAttribute(client, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(client, HttpMethod.GET, HTTP_METHOD); + assertSemanticAttribute(client, uri.toString() + "hello?name=foo", HTTP_URL); + assertSemanticAttribute(client, uri.getHost(), NET_PEER_NAME); + assertSemanticAttribute(client, (long) uri.getPort(), NET_PEER_PORT); SpanData server = getSpanByKindAndParentId(spans, SERVER, client.getSpanId()); assertEquals(SERVER, server.getKind()); assertEquals("GET /hello", server.getName()); - assertEquals(HTTP_OK, server.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(HttpMethod.GET, server.getAttributes().get(HTTP_METHOD)); + assertSemanticAttribute(server, (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(server, HttpMethod.GET, HTTP_METHOD); assertEquals("/hello", server.getAttributes().get(HTTP_ROUTE)); - assertEquals(uri.getHost(), server.getAttributes().get(NET_HOST_NAME)); - assertEquals(uri.getPort(), server.getAttributes().get(NET_HOST_PORT)); - assertEquals(uri.getPath() + "hello?name=foo", server.getAttributes().get(HTTP_TARGET)); + assertSemanticAttribute(server, uri.getHost(), NET_HOST_NAME); + assertSemanticAttribute(server, (long) uri.getPort(), NET_HOST_PORT); + assertTarget(server, uri.getPath() + "hello", "name=foo"); assertEquals(client.getTraceId(), server.getTraceId()); } diff --git a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryForwardedTest.java b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryForwardedTest.java index 9556aa2bb1313..b7cb2da17bc83 100644 --- a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryForwardedTest.java +++ b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryForwardedTest.java @@ -2,9 +2,9 @@ import static io.opentelemetry.api.trace.SpanKind.SERVER; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_CLIENT_IP; +import static io.quarkus.opentelemetry.deployment.common.SemconvResolver.assertSemanticAttribute; import static io.quarkus.opentelemetry.deployment.common.TestSpanExporter.getSpanByKindAndParentId; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; @@ -15,6 +15,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import io.opentelemetry.sdk.trace.data.SpanData; +import io.quarkus.opentelemetry.deployment.common.SemconvResolver; import io.quarkus.opentelemetry.deployment.common.TestSpanExporter; import io.quarkus.opentelemetry.deployment.common.TestSpanExporterProvider; import io.quarkus.opentelemetry.deployment.common.TracerRouter; @@ -26,7 +27,7 @@ public class VertxOpenTelemetryForwardedTest { static final QuarkusUnitTest unitTest = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClass(TracerRouter.class) - .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class) + .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class, SemconvResolver.class) .addAsResource(new StringAsset(TestSpanExporterProvider.class.getCanonicalName()), "META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider")) .withConfigurationResource("application-default.properties"); @@ -44,6 +45,6 @@ void trace() { List spans = testSpanExporter.getFinishedSpanItems(2); SpanData server = getSpanByKindAndParentId(spans, SERVER, "0000000000000000"); - assertEquals("192.0.2.60", server.getAttributes().get(HTTP_CLIENT_IP)); + assertSemanticAttribute(server, "192.0.2.60", HTTP_CLIENT_IP); } } diff --git a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryTest.java b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryTest.java index 79d8cdae41227..b6134141327bb 100644 --- a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryTest.java +++ b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryTest.java @@ -8,10 +8,11 @@ import static io.opentelemetry.semconv.SemanticAttributes.HTTP_ROUTE; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_SCHEME; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_STATUS_CODE; -import static io.opentelemetry.semconv.SemanticAttributes.HTTP_TARGET; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_NAME; import static io.opentelemetry.semconv.SemanticAttributes.NET_HOST_PORT; import static io.opentelemetry.semconv.SemanticAttributes.USER_AGENT_ORIGINAL; +import static io.quarkus.opentelemetry.deployment.common.SemconvResolver.assertSemanticAttribute; +import static io.quarkus.opentelemetry.deployment.common.SemconvResolver.assertTarget; import static io.quarkus.opentelemetry.deployment.common.TestSpanExporter.getSpanByKindAndParentId; import static io.restassured.RestAssured.given; import static io.vertx.core.http.HttpMethod.GET; @@ -43,6 +44,7 @@ import io.opentelemetry.sdk.trace.IdGenerator; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.samplers.Sampler; +import io.quarkus.opentelemetry.deployment.common.SemconvResolver; import io.quarkus.opentelemetry.deployment.common.TestSpanExporter; import io.quarkus.opentelemetry.deployment.common.TestSpanExporterProvider; import io.quarkus.opentelemetry.deployment.common.TestUtil; @@ -56,10 +58,9 @@ public class VertxOpenTelemetryTest { .withApplicationRoot((jar) -> jar .addClass(TracerRouter.class) .addClass(TestUtil.class) - .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class) + .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class, SemconvResolver.class) .addAsResource(new StringAsset(TestSpanExporterProvider.class.getCanonicalName()), "META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider")) - // .overrideConfigKey(SmallRyeConfig.SMALLRYE_CONFIG_MAPPING_VALIDATE_UNKNOWN, "false")// FIXME default config mapping .overrideConfigKey("quarkus.otel.traces.exporter", "test-span-exporter") .overrideConfigKey("quarkus.otel.metrics.exporter", "none") .overrideConfigKey("quarkus.otel.logs.exporter", "none") @@ -88,12 +89,12 @@ void trace() throws NoSuchFieldException, IllegalAccessException, InvocationTarg Sampler sampler = TestUtil.getSampler(openTelemetry); SpanData server = getSpanByKindAndParentId(spans, SERVER, "0000000000000000"); - assertEquals(HTTP_OK, server.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals("/tracer", server.getAttributes().get(HTTP_TARGET)); - assertEquals("http", server.getAttributes().get(HTTP_SCHEME)); - assertEquals("localhost", server.getAttributes().get(NET_HOST_NAME)); - assertEquals("8081", server.getAttributes().get(NET_HOST_PORT).toString()); - assertEquals("127.0.0.1", server.getAttributes().get(HTTP_CLIENT_IP)); + assertSemanticAttribute(server, (long) HTTP_OK, HTTP_STATUS_CODE); + assertTarget(server, "/tracer", null); + assertSemanticAttribute(server, "http", HTTP_SCHEME); + assertSemanticAttribute(server, "localhost", NET_HOST_NAME); + assertSemanticAttribute(server, 8081L, NET_HOST_PORT); + assertSemanticAttribute(server, "127.0.0.1", HTTP_CLIENT_IP); assertThat(textMapPropagators, arrayContainingInAnyOrder(W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance())); assertThat(idGenerator, instanceOf(IdGenerator.random().getClass())); @@ -115,12 +116,12 @@ void spanNameWithoutQueryString() { final SpanData server = getSpanByKindAndParentId(spans, SERVER, "0000000000000000"); assertEquals("GET /tracer", server.getName()); - assertEquals(HTTP_OK, server.getAttributes().get(HTTP_STATUS_CODE)); - assertEquals("/tracer?id=1", server.getAttributes().get(HTTP_TARGET)); - assertEquals("http", server.getAttributes().get(HTTP_SCHEME)); - assertEquals("localhost", server.getAttributes().get(NET_HOST_NAME)); - assertEquals("8081", server.getAttributes().get(NET_HOST_PORT).toString()); - assertEquals("127.0.0.1", server.getAttributes().get(HTTP_CLIENT_IP)); + assertSemanticAttribute(server, (long) HTTP_OK, HTTP_STATUS_CODE); + assertTarget(server, "/tracer", "id=1"); + assertSemanticAttribute(server, "http", HTTP_SCHEME); + assertSemanticAttribute(server, "localhost", NET_HOST_NAME); + assertSemanticAttribute(server, 8081L, NET_HOST_PORT); + assertSemanticAttribute(server, "127.0.0.1", HTTP_CLIENT_IP); assertNotNull(server.getAttributes().get(USER_AGENT_ORIGINAL)); SpanData internal = getSpanByKindAndParentId(spans, INTERNAL, server.getSpanId()); @@ -141,8 +142,8 @@ void spanPath() { assertEquals(1, spans.size()); assertEquals("GET /hello/:name", spans.get(0).getName()); - assertEquals(HTTP_OK, spans.get(0).getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(GET.toString(), spans.get(0).getAttributes().get(HTTP_METHOD)); + assertSemanticAttribute(spans.get(0), (long) HTTP_OK, HTTP_STATUS_CODE); + assertSemanticAttribute(spans.get(0), GET.toString(), HTTP_METHOD); assertEquals("/hello/:name", spans.get(0).getAttributes().get(HTTP_ROUTE)); } @@ -155,7 +156,7 @@ void notFound() { assertEquals("GET /*", spans.get(0).getName()); assertEquals("/*", spans.get(0).getAttributes().get(HTTP_ROUTE)); - assertEquals(HTTP_NOT_FOUND, spans.get(0).getAttributes().get(HTTP_STATUS_CODE)); + assertSemanticAttribute(spans.get(0), (long) HTTP_NOT_FOUND, HTTP_STATUS_CODE); } @Test @@ -169,8 +170,8 @@ void notFoundPath() { assertEquals(1, spans.size()); assertEquals("GET /hello/:name", spans.get(0).getName()); - assertEquals(HTTP_NOT_FOUND, spans.get(0).getAttributes().get(HTTP_STATUS_CODE)); - assertEquals(GET.toString(), spans.get(0).getAttributes().get(HTTP_METHOD)); + assertSemanticAttribute(spans.get(0), (long) HTTP_NOT_FOUND, HTTP_STATUS_CODE); + assertSemanticAttribute(spans.get(0), GET.toString(), HTTP_METHOD); assertEquals("/hello/:name", spans.get(0).getAttributes().get(HTTP_ROUTE)); } } diff --git a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryXForwardedTest.java b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryXForwardedTest.java index e58f286f9df68..bbf97ebedb203 100644 --- a/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryXForwardedTest.java +++ b/extensions/opentelemetry/deployment/src/test/java/io/quarkus/opentelemetry/deployment/instrumentation/VertxOpenTelemetryXForwardedTest.java @@ -2,9 +2,9 @@ import static io.opentelemetry.api.trace.SpanKind.SERVER; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_CLIENT_IP; +import static io.quarkus.opentelemetry.deployment.common.SemconvResolver.assertSemanticAttribute; import static io.quarkus.opentelemetry.deployment.common.TestSpanExporter.getSpanByKindAndParentId; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; @@ -15,6 +15,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import io.opentelemetry.sdk.trace.data.SpanData; +import io.quarkus.opentelemetry.deployment.common.SemconvResolver; import io.quarkus.opentelemetry.deployment.common.TestSpanExporter; import io.quarkus.opentelemetry.deployment.common.TestSpanExporterProvider; import io.quarkus.opentelemetry.deployment.common.TracerRouter; @@ -26,7 +27,7 @@ public class VertxOpenTelemetryXForwardedTest { static final QuarkusUnitTest unitTest = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClass(TracerRouter.class) - .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class) + .addClasses(TestSpanExporter.class, TestSpanExporterProvider.class, SemconvResolver.class) .addAsResource(new StringAsset(TestSpanExporterProvider.class.getCanonicalName()), "META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider")) .withConfigurationResource("application-default.properties"); @@ -44,6 +45,6 @@ void trace() { List spans = testSpanExporter.getFinishedSpanItems(2); SpanData server = getSpanByKindAndParentId(spans, SERVER, "0000000000000000"); - assertEquals("203.0.113.195", server.getAttributes().get(HTTP_CLIENT_IP)); + assertSemanticAttribute(server, "203.0.113.195", HTTP_CLIENT_IP); } } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/AutoConfiguredOpenTelemetrySdkBuilderCustomizer.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/AutoConfiguredOpenTelemetrySdkBuilderCustomizer.java index de7e1ee998d96..27ec3b7e2661c 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/AutoConfiguredOpenTelemetrySdkBuilderCustomizer.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/AutoConfiguredOpenTelemetrySdkBuilderCustomizer.java @@ -1,5 +1,6 @@ package io.quarkus.opentelemetry.runtime; +import static io.quarkus.opentelemetry.runtime.OpenTelemetryUtil.getSemconvStabilityOptin; import static java.lang.Boolean.TRUE; import static java.util.Collections.emptyList; @@ -22,10 +23,10 @@ import io.opentelemetry.sdk.trace.SpanProcessor; import io.opentelemetry.sdk.trace.samplers.Sampler; import io.quarkus.arc.All; -import io.quarkus.opentelemetry.TextMapPropagatorCustomizer; import io.quarkus.opentelemetry.runtime.config.build.OTelBuildConfig; import io.quarkus.opentelemetry.runtime.config.runtime.OTelRuntimeConfig; import io.quarkus.opentelemetry.runtime.exporter.otlp.RemoveableLateBoundBatchSpanProcessor; +import io.quarkus.opentelemetry.runtime.propagation.TextMapPropagatorCustomizer; import io.quarkus.opentelemetry.runtime.tracing.DelayedAttributes; import io.quarkus.opentelemetry.runtime.tracing.DropTargetsSampler; import io.quarkus.opentelemetry.runtime.tracing.TracerRecorder; @@ -99,6 +100,7 @@ public Resource apply(Resource existingResource, ConfigProperties configProperti @Singleton final class SamplerCustomizer implements AutoConfiguredOpenTelemetrySdkBuilderCustomizer { + private static final String OTEL_SEMCONV_STABILITY_OPT_IN = "otel.semconv-stability.opt-in"; private final OTelBuildConfig oTelBuildConfig; private final OTelRuntimeConfig oTelRuntimeConfig; @@ -133,7 +135,10 @@ public Sampler apply(Sampler existingSampler, ConfigProperties configProperties) // make sure dropped targets are not sampled if (!dropTargets.isEmpty()) { - return new DropTargetsSampler(effectiveSampler, dropTargets); + return new DropTargetsSampler(effectiveSampler, + dropTargets, + getSemconvStabilityOptin( + configProperties.getString(OTEL_SEMCONV_STABILITY_OPT_IN))); } else { return effectiveSampler; } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java index de8326f931aeb..1b2894cc49a25 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtil.java @@ -12,6 +12,7 @@ import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.trace.ReadableSpan; +import io.quarkus.opentelemetry.runtime.config.runtime.SemconvStabilityType; import io.quarkus.vertx.core.runtime.VertxMDC; public final class OpenTelemetryUtil { @@ -111,4 +112,16 @@ public static void clearMDCData(io.vertx.core.Context vertxContext) { vertxMDC.remove(PARENT_ID, vertxContext); vertxMDC.remove(SAMPLED, vertxContext); } + + public static SemconvStabilityType getSemconvStabilityOptin(String config) { + if (config == null || config.isBlank()) { + return SemconvStabilityType.HTTP_OLD; + } + + try { + return SemconvStabilityType.fromValue(config); + } catch (IllegalArgumentException e) { + return SemconvStabilityType.HTTP_OLD; + } + } } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/OTelRuntimeConfig.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/OTelRuntimeConfig.java index f428629d4f957..0389142e4df9b 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/OTelRuntimeConfig.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/OTelRuntimeConfig.java @@ -76,4 +76,19 @@ public interface OTelRuntimeConfig { * Enable/disable instrumentation for specific technologies. */ InstrumentRuntimeConfig instrument(); + + /** + * Opt-in to emit stable OpenTelemetry semantic conventions or a + * duplication of the old plus the new semantic convention attribute names. + *

+ * - http - emit the new, stable HTTP and networking attributes, and stop emitting the old + * experimental HTTP and networking attributes that the instrumentation emitted previously. + *

+ * - http/dup - emit both the old and the stable HTTP and networking attributes, allowing + * for a more seamless transition. + *

+ * The default, by not defining a property value, will mean the use of the old legacy semantic attribute names. + */ + @WithName("otel.semconv-stability.opt-in") + Optional otelSemconvStabilityOptIn(); } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/SemconvStabilityType.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/SemconvStabilityType.java new file mode 100644 index 0000000000000..be0d7f71ba66d --- /dev/null +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/SemconvStabilityType.java @@ -0,0 +1,43 @@ +package io.quarkus.opentelemetry.runtime.config.runtime; + +public enum SemconvStabilityType { + /** + * Emit the new stable convention names + */ + HTTP("http"), + /** + * Emit the old unstable plus the new stable convention names for transition purposes + */ + HTTP_DUP("http/dup"), + /** + * Emit the old unstable convention names. + *

+ * This is a non standard property name, only used in Quarkus. + */ + HTTP_OLD("http/old"); + + private final String value; + + SemconvStabilityType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static SemconvStabilityType fromValue(String value) { + for (SemconvStabilityType type : values()) { + if (type.value.equals(value)) { + return type; + } + } + throw new IllegalArgumentException("No enum constant with value: " + value); + } + + static class Constants { + public static final String HTTP = "http"; + public static final String HTTP_DUP = "http/dup"; + public static final String HTTP_OLD = "http/old"; + } +} diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/TextMapPropagatorCustomizer.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/propagation/TextMapPropagatorCustomizer.java similarity index 90% rename from extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/TextMapPropagatorCustomizer.java rename to extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/propagation/TextMapPropagatorCustomizer.java index 6911e69917338..061c0ca73e464 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/TextMapPropagatorCustomizer.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/propagation/TextMapPropagatorCustomizer.java @@ -1,4 +1,4 @@ -package io.quarkus.opentelemetry; +package io.quarkus.opentelemetry.runtime.propagation; import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/DropTargetsSampler.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/DropTargetsSampler.java index 8222d2c99a74d..d9c332d86c313 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/DropTargetsSampler.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/DropTargetsSampler.java @@ -9,14 +9,19 @@ import io.opentelemetry.sdk.trace.samplers.Sampler; import io.opentelemetry.sdk.trace.samplers.SamplingResult; import io.opentelemetry.semconv.SemanticAttributes; +import io.quarkus.opentelemetry.runtime.config.runtime.SemconvStabilityType; public class DropTargetsSampler implements Sampler { private final Sampler sampler; private final List dropTargets; + private final SemconvStabilityType semconvStabilityOptin; - public DropTargetsSampler(Sampler sampler, List dropTargets) { + public DropTargetsSampler(final Sampler sampler, + final List dropTargets, + final SemconvStabilityType semconvStabilityOptin) { this.sampler = sampler; this.dropTargets = dropTargets; + this.semconvStabilityOptin = semconvStabilityOptin; } @Override @@ -24,7 +29,16 @@ public SamplingResult shouldSample(Context parentContext, String traceId, String Attributes attributes, List parentLinks) { if (spanKind.equals(SpanKind.SERVER)) { - String target = attributes.get(SemanticAttributes.HTTP_TARGET); + String target; + if (SemconvStabilityType.HTTP.equals(semconvStabilityOptin) || + SemconvStabilityType.HTTP_DUP.equals(semconvStabilityOptin)) { + // HTTP_TARGET was split into url.path and url.query + String path = attributes.get(SemanticAttributes.URL_PATH); + String query = attributes.get(SemanticAttributes.URL_QUERY); + target = path + (query == null ? "" : "?" + query); + } else { + target = attributes.get(SemanticAttributes.HTTP_TARGET); + } if (shouldDrop(target)) { return SamplingResult.drop(); } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java index 105eb7f7a1881..f155facf34c8a 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java @@ -1,5 +1,7 @@ package io.quarkus.opentelemetry.runtime.tracing.intrumentation; +import static io.quarkus.opentelemetry.runtime.OpenTelemetryUtil.getSemconvStabilityOptin; + import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; @@ -39,11 +41,12 @@ public Consumer getVertxTracingOptions() { } /* RUNTIME INIT */ - public void setupVertxTracer(BeanContainer beanContainer, boolean sqlClientAvailable) { + public void setupVertxTracer(BeanContainer beanContainer, boolean sqlClientAvailable, + final String semconvStability) { OpenTelemetry openTelemetry = beanContainer.beanInstance(OpenTelemetry.class); List> tracers = new ArrayList<>(3); if (config.getValue().instrument().vertxHttp()) { - tracers.add(new HttpInstrumenterVertxTracer(openTelemetry)); + tracers.add(new HttpInstrumenterVertxTracer(openTelemetry, getSemconvStabilityOptin(semconvStability))); } if (config.getValue().instrument().vertxEventBus()) { tracers.add(new EventBusInstrumenterVertxTracer(openTelemetry)); diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/scheduler/OpenTelemetryJobInstrumenter.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/scheduler/OpenTelemetryJobInstrumenter.java similarity index 96% rename from extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/scheduler/OpenTelemetryJobInstrumenter.java rename to extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/scheduler/OpenTelemetryJobInstrumenter.java index 3a1a84c111bbb..1456bce5beafd 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/scheduler/OpenTelemetryJobInstrumenter.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/scheduler/OpenTelemetryJobInstrumenter.java @@ -1,4 +1,4 @@ -package io.quarkus.opentelemetry.runtime.scheduler; +package io.quarkus.opentelemetry.runtime.tracing.intrumentation.scheduler; import java.util.concurrent.CompletionStage; diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/vertx/HttpInstrumenterVertxTracer.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/vertx/HttpInstrumenterVertxTracer.java index bb4f44309a4ba..cdf4b86522bb8 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/vertx/HttpInstrumenterVertxTracer.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/vertx/HttpInstrumenterVertxTracer.java @@ -1,6 +1,7 @@ package io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx; -import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpRouteSource.FILTER; +import static io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteSource.SERVER_FILTER; +import static io.opentelemetry.semconv.SemanticAttributes.CLIENT_ADDRESS; import static io.opentelemetry.semconv.SemanticAttributes.HTTP_CLIENT_IP; import static io.quarkus.opentelemetry.runtime.config.build.OTelBuildConfig.INSTRUMENTATION_NAME; @@ -21,13 +22,14 @@ import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesGetter; -import io.opentelemetry.instrumentation.api.instrumenter.http.HttpRouteBiGetter; -import io.opentelemetry.instrumentation.api.instrumenter.http.HttpRouteHolder; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesGetter; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteBiGetter; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; import io.opentelemetry.semconv.SemanticAttributes; +import io.quarkus.opentelemetry.runtime.config.runtime.SemconvStabilityType; import io.vertx.core.Context; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpHeaders; @@ -46,8 +48,8 @@ public class HttpInstrumenterVertxTracer implements InstrumenterVertxTracer serverInstrumenter; private final Instrumenter clientInstrumenter; - public HttpInstrumenterVertxTracer(final OpenTelemetry openTelemetry) { - serverInstrumenter = getServerInstrumenter(openTelemetry); + public HttpInstrumenterVertxTracer(final OpenTelemetry openTelemetry, final SemconvStabilityType semconvStability) { + serverInstrumenter = getServerInstrumenter(openTelemetry, semconvStability); clientInstrumenter = getClientInstrumenter(openTelemetry); } @@ -95,7 +97,7 @@ public void sendResponse( final Throwable failure, final TagExtractor tagExtractor) { - HttpRouteHolder.updateHttpRoute(spanOperation.getSpanContext(), FILTER, RouteGetter.ROUTE_GETTER, + HttpServerRoute.update(spanOperation.getSpanContext(), SERVER_FILTER, RouteGetter.ROUTE_GETTER, ((HttpRequestSpan) spanOperation.getRequest()), (HttpResponse) response); InstrumenterVertxTracer.super.sendResponse(context, response, spanOperation, failure, tagExtractor); } @@ -106,7 +108,8 @@ public HttpRequest writableHeaders( return WriteHeadersHttpRequest.request(request, headers); } - private static Instrumenter getServerInstrumenter(final OpenTelemetry openTelemetry) { + private static Instrumenter getServerInstrumenter(final OpenTelemetry openTelemetry, + final SemconvStabilityType semconvStability) { ServerAttributesExtractor serverAttributesExtractor = new ServerAttributesExtractor(); InstrumenterBuilder serverBuilder = Instrumenter.builder( @@ -118,8 +121,8 @@ private static Instrumenter getServerInstrumenter(fin .setSpanStatusExtractor(HttpSpanStatusExtractor.create(serverAttributesExtractor)) .addAttributesExtractor( HttpServerAttributesExtractor.create(serverAttributesExtractor)) - .addAttributesExtractor(new AdditionalServerAttributesExtractor()) - .addContextCustomizer(HttpRouteHolder.create(serverAttributesExtractor)) + .addAttributesExtractor(new AdditionalServerAttributesExtractor(semconvStability)) + .addContextCustomizer(HttpServerRoute.create(serverAttributesExtractor)) .buildServerInstrumenter(new HttpRequestTextMapGetter()); } @@ -140,7 +143,7 @@ private static Instrumenter getClientInstrumenter(fin .buildClientInstrumenter(new HttpRequestTextMapSetter()); } - private static class RouteGetter implements HttpRouteBiGetter { + private static class RouteGetter implements HttpServerRouteBiGetter { static final RouteGetter ROUTE_GETTER = new RouteGetter(); @Override @@ -269,6 +272,12 @@ private static Long getContentLength(final MultiMap headers) { } private static class AdditionalServerAttributesExtractor implements AttributesExtractor { + private final SemconvStabilityType semconvStability; + + public AdditionalServerAttributesExtractor(final SemconvStabilityType semconvStability) { + this.semconvStability = semconvStability; + } + @Override public void onStart( final AttributesBuilder attributes, @@ -278,7 +287,18 @@ public void onStart( if (httpRequest instanceof HttpServerRequest) { String clientIp = VertxUtil.extractClientIP((HttpServerRequest) httpRequest); if (clientIp != null) { - attributes.put(HTTP_CLIENT_IP, clientIp); + switch (semconvStability) { + case HTTP_OLD: + attributes.put(HTTP_CLIENT_IP, clientIp); + break; + case HTTP_DUP: + attributes.put(HTTP_CLIENT_IP, clientIp); + attributes.put(CLIENT_ADDRESS, clientIp); + break; + case HTTP: + attributes.put(CLIENT_ADDRESS, clientIp); + break; + } } } } diff --git a/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtilTest.java b/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtilTest.java index eebe37eee8a85..34903c96f90a1 100644 --- a/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtilTest.java +++ b/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/OpenTelemetryUtilTest.java @@ -17,6 +17,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.SpanProcessor; +import io.quarkus.opentelemetry.runtime.config.runtime.SemconvStabilityType; public class OpenTelemetryUtilTest { @@ -118,4 +119,16 @@ public void testGetSpanData_nullValue() { Map actual = OpenTelemetryUtil.getSpanData(null); assertEquals(0, actual.size()); } + + @Test + public void testSemconvOptin() { + assertEquals(SemconvStabilityType.HTTP_OLD, + OpenTelemetryUtil.getSemconvStabilityOptin(null)); + assertEquals(SemconvStabilityType.HTTP_OLD, + OpenTelemetryUtil.getSemconvStabilityOptin(SemconvStabilityType.HTTP_OLD.getValue())); + assertEquals(SemconvStabilityType.HTTP, + OpenTelemetryUtil.getSemconvStabilityOptin(SemconvStabilityType.HTTP.getValue())); + assertEquals(SemconvStabilityType.HTTP_DUP, + OpenTelemetryUtil.getSemconvStabilityOptin(SemconvStabilityType.HTTP_DUP.getValue())); + } } diff --git a/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/tracing/DropTargetsSamplerTest.java b/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/tracing/DropTargetsSamplerTest.java index 43de8f26064e7..287784eacb258 100644 --- a/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/tracing/DropTargetsSamplerTest.java +++ b/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/tracing/DropTargetsSamplerTest.java @@ -1,5 +1,6 @@ package io.quarkus.opentelemetry.runtime.tracing; +import static io.quarkus.opentelemetry.runtime.OpenTelemetryUtil.*; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; @@ -14,31 +15,42 @@ import io.opentelemetry.sdk.trace.samplers.Sampler; import io.opentelemetry.sdk.trace.samplers.SamplingResult; import io.opentelemetry.semconv.SemanticAttributes; +import io.quarkus.opentelemetry.runtime.config.runtime.SemconvStabilityType; class DropTargetsSamplerTest { @Test void testDropTargets() { CountingSampler countingSampler = new CountingSampler(); - var sut = new DropTargetsSampler(countingSampler, List.of("/q/swagger-ui", "/q/swagger-ui*")); + SemconvStabilityType semconvStabilityOptin = getSemconvStabilityOptin( + System.getProperty("quarkus.otel.semconv-stability.opt-in")); + var sut = new DropTargetsSampler(countingSampler, List.of("/q/swagger-ui", "/q/swagger-ui*"), + semconvStabilityOptin); - assertEquals(SamplingResult.recordAndSample(), getShouldSample(sut, "/other")); + assertEquals(SamplingResult.recordAndSample(), getShouldSample(sut, "/other", semconvStabilityOptin)); assertEquals(1, countingSampler.count.get()); - assertEquals(SamplingResult.drop(), getShouldSample(sut, "/q/swagger-ui")); + assertEquals(SamplingResult.drop(), getShouldSample(sut, "/q/swagger-ui", semconvStabilityOptin)); assertEquals(1, countingSampler.count.get()); - assertEquals(SamplingResult.drop(), getShouldSample(sut, "/q/swagger-ui/")); + assertEquals(SamplingResult.drop(), getShouldSample(sut, "/q/swagger-ui/", semconvStabilityOptin)); assertEquals(1, countingSampler.count.get()); - assertEquals(SamplingResult.drop(), getShouldSample(sut, "/q/swagger-ui/whatever")); + assertEquals(SamplingResult.drop(), getShouldSample(sut, "/q/swagger-ui/whatever", semconvStabilityOptin)); assertEquals(1, countingSampler.count.get()); - assertEquals(SamplingResult.recordAndSample(), getShouldSample(sut, "/q/test")); + assertEquals(SamplingResult.recordAndSample(), getShouldSample(sut, "/q/test", semconvStabilityOptin)); assertEquals(2, countingSampler.count.get()); } - private static SamplingResult getShouldSample(DropTargetsSampler sut, String target) { + private static SamplingResult getShouldSample(DropTargetsSampler sut, + String target, + SemconvStabilityType semconvStabilityOptin) { + if (SemconvStabilityType.HTTP.equals(semconvStabilityOptin) || + SemconvStabilityType.HTTP_DUP.equals(semconvStabilityOptin)) { + return sut.shouldSample(null, null, null, SpanKind.SERVER, + Attributes.of(SemanticAttributes.URL_PATH, target), null); + } return sut.shouldSample(null, null, null, SpanKind.SERVER, Attributes.of(SemanticAttributes.HTTP_TARGET, target), null); }