diff --git a/docs/src/main/asciidoc/_includes/opentelemetry-config.adoc b/docs/src/main/asciidoc/_includes/opentelemetry-config.adoc new file mode 100644 index 0000000000000..50a2ae6339f95 --- /dev/null +++ b/docs/src/main/asciidoc/_includes/opentelemetry-config.adoc @@ -0,0 +1,34 @@ +There are no mandatory configurations for the extension to work. + +If you need to change any of the default property values, here is an example on how to configure the default OTLP gRPC Exporter within the application, using the `src/main/resources/application.properties` file: + +[source,properties] +---- +quarkus.application.name=myservice // <1> +quarkus.otel.exporter.otlp.endpoint=http://localhost:4317 // <2> +quarkus.otel.exporter.otlp.headers=authorization=Bearer my_secret // <3> +quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} [%c{2.}] (%t) %s%e%n // <4> + +# Alternative to the console log +quarkus.http.access-log.pattern="...traceId=%{X,traceId} spanId=%{X,spanId}" // <5> +---- + +<1> All spans created from the application will include an OpenTelemetry `Resource` indicating the telemetry was created by the `myservice` application. If not set, it will default to the artifact id. +<2> gRPC endpoint to send the telemetry. If not set, it will default to `http://localhost:4317`. +<3> Optional gRPC headers commonly used for authentication +<4> Add tracing information into log messages. +<5> You can also only put the trace info into the access log. In this case you must omit the info in the console log format. + +We provide signal agnostic configurations for the connection related properties, meaning that you can use the same properties for both tracing and metrics when you set: +[source,properties] +---- +quarkus.otel.exporter.otlp.endpoint=http://localhost:4317 +---- +If you need different configurations for each signal, you can use the specific properties: +[source,properties] +---- +quarkus.otel.exporter.otlp.traces.endpoint=http://trace-uri:4317 // <1> +quarkus.otel.exporter.otlp.metrics.endpoint=http://metrics-uri:4317 // <2> +---- +<1> The endpoint for the traces exporter. +<2> The endpoint for the metrics exporter. \ No newline at end of file diff --git a/docs/src/main/asciidoc/opentelemetry-metrics.adoc b/docs/src/main/asciidoc/opentelemetry-metrics.adoc new file mode 100644 index 0000000000000..9f51d51112544 --- /dev/null +++ b/docs/src/main/asciidoc/opentelemetry-metrics.adoc @@ -0,0 +1,308 @@ +//// +This guide is maintained in the main Quarkus repository +and pull requests should be submitted there: +https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc +//// += Using OpenTelemetry Metrics +include::_attributes.adoc[] +:categories: observability +:summary: This guide explains how your Quarkus application can utilize OpenTelemetry to provide metrics for interactive web applications. +:topics: observability,opentelemetry,metrics +:extensions: io.quarkus:quarkus-opentelemetry + +This guide explains how your Quarkus application can utilize https://opentelemetry.io/[OpenTelemetry] (OTel) to provide +metrics for interactive web applications. + +[NOTE] +==== +- The xref:opentelemetry.adoc[OpenTelemetry Guide] is available with high-level information about OpenTelemetry and for signal independent, common functionality. +- If you search more information about OpenTelemetry Tracing, please refer to the xref:opentelemetry-tracing.adoc[OpenTelemetry Tracing Guide]. +==== + + +== Prerequisites + +:prerequisites-docker-compose: +include::{includes}/prerequisites.adoc[] + +== Architecture + +In this guide, we create a straightforward REST application to demonstrate distributed tracing. + +== Solution + +We recommend that you follow the instructions in the next sections and create the application step by step. +However, you can skip right to the completed example. + +Clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {quickstarts-archive-url}[archive]. + +The solution is located in the `opentelemetry-quickstart` link:{quickstarts-tree-url}/opentelemetry-quickstart[directory]. + +== Creating the Maven project + +First, we need a new project. Create a new project with the following command: + +:create-app-artifact-id: opentelemetry-quickstart +:create-app-extensions: rest,quarkus-opentelemetry +include::{includes}/devtools/create-app.adoc[] + +This command generates the Maven project and imports the `quarkus-opentelemetry` extension, +which includes the default OpenTelemetry support, +and a gRPC span exporter for https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md[OTLP]. + +If you already have your Quarkus project configured, you can add the `quarkus-opentelemetry` extension +to your project by running the following command in your project base directory: + +:add-extension-extensions: opentelemetry +include::{includes}/devtools/extension-add.adoc[] + +This will add the following to your build file: + +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml +---- + + io.quarkus + quarkus-opentelemetry + +---- + +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.quarkus:quarkus-opentelemetry") +---- + +=== Examine the Jakarta REST resource + +Create a `src/main/java/org/acme/opentelemetry/MetricResource.java` file with the following content: + +[source,java] +---- +package org.acme.opentelemetry; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import org.jboss.logging.Logger; + +@Path("/hello") +public class MetricResource { + + private static final Logger LOG = Logger.getLogger(MetricResource.class); + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + LOG.info("hello"); + return "hello"; + } +} +---- + +Quarkus is not currently producing metrics out of the box. + +=== Create the configuration + +There are no mandatory configurations for the extension to work. + +If you need to change any of the default property values, here is an example on how to configure the default OTLP gRPC Exporter within the application, using the `src/main/resources/application.properties` file: + +[source,properties] +---- +quarkus.application.name=myservice // <1> +quarkus.otel.exporter.otlp.traces.endpoint=http://localhost:4317 // <2> +quarkus.otel.exporter.otlp.traces.headers=authorization=Bearer my_secret // <3> +quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} [%c{2.}] (%t) %s%e%n // <4> + +# Alternative to the console log +quarkus.http.access-log.pattern="...traceId=%{X,traceId} spanId=%{X,spanId}" // <5> +---- + +<1> All spans created from the application will include an OpenTelemetry `Resource` indicating the span was created by the `myservice` application. If not set, it will default to the artifact id. +<2> gRPC endpoint to send spans. If not set, it will default to `http://localhost:4317`. +<3> Optional gRPC headers commonly used for authentication +<4> Add tracing information into log messages. +<5> You can also only put the trace info into the access log. In this case you must omit the info in the console log format. + +[NOTE] +==== +All configurations have been updated from `quarkus.opentelemetry.\*` -> `quarkus.otel.*` + +The legacy configurations are now deprecated but will still work during a transition period. +==== + +=== Disable all or parts of the OpenTelemetry extension + +Once you add the dependency, the extension will be enabled by default but there are a few ways to disable the OpenTelemetry extension globally or partially. + +|=== +|Property name |Default value |Description + +|`quarkus.otel.enabled` +|true +|If false, disable the OpenTelemetry usage at *build* time. + +|`quarkus.otel.sdk.disabled` +|false +|Comes from the OpenTelemetry autoconfiguration. If true, will disable the OpenTelemetry SDK usage at *runtime*. + +|`quarkus.otel.traces.enabled` +|true +|If false, disable the OpenTelemetry tracing usage at *build* time. + +|`quarkus.otel.exporter.otlp.enabled` +|true +|If false will disable the default OTLP exporter at *build* time. +|=== + +If you need to enable or disable the exporter at runtime, you can use the <> because it has the ability to filter out all the spans if needed. + + +== Run the application + +First we need to start a system to visualise the OpenTelemetry data. +We have 2 options: + +* Start an all-in-one Grafana OTel LGTM system for traces and metrics. +* Jaeger system just for traces. + +=== Grafana OTel LGTM option + +* Take a look at: xref:observability-devservices-lgtm.adoc[Getting Started with Grafana-OTel-LGTM]. + +This features a Quarkus Dev service including a Grafana for visualizing data, Loki to store logs, Tempo to store traces and Prometheus to store metrics. Also provides and OTel collector to receive the data. + +=== Start the application + +Now we are ready to run our application. If using `application.properties` to configure the tracer: + +include::{includes}/devtools/dev.adoc[] + +or if configuring the OTLP gRPC endpoint via JVM arguments: + +:dev-additional-parameters: -Djvm.args="-Dquarkus.otel.exporter.otlp.traces.endpoint=http://localhost:4317" +include::{includes}/devtools/dev.adoc[] +:!dev-additional-parameters: + +With the OpenTelemetry Collector, the Jaeger system and the application running, you can make a request to the provided endpoint: + +[source,shell] +---- +$ curl http://localhost:8080/hello +hello +---- + +When the first request has been submitted, you will be able to see the tracing information in the logs: + +[source] +---- +10:49:02 INFO traceId=, parentId=, spanId=, sampled= [io.quarkus] (main) Installed features: [cdi, opentelemetry, resteasy-client, resteasy, smallrye-context-propagation, vertx] +10:49:03 INFO traceId=17ceb8429b9f25b0b879fa1503259456, parentId=3125c8bee75b7ad6, spanId=58ce77c86dd23457, sampled=true [or.ac.op.TracedResource] (executor-thread-1) hello +10:49:03 INFO traceId=ad23acd6d9a4ed3d1de07866a52fa2df, parentId=, spanId=df13f5b45cf4d1e2, sampled=true [or.ac.op.TracedResource] (executor-thread-0) hello +---- + + +Then visit the http://localhost:16686[Jaeger UI] to see the tracing information. + +Hit `CTRL+C` or type `q` to stop the application. + + + +=== Resource + + +==== End User attributes + + +== Additional instrumentation + +Some Quarkus extensions will require additional code to ensure traces are propagated to subsequent execution. +These sections will outline what is necessary to propagate traces across process boundaries. + +The instrumentation documented in this section has been tested with Quarkus and works in both standard and native mode. + +=== CDI + +Annotating a method in any CDI aware bean with the `io.opentelemetry.instrumentation.annotations.WithSpan` +annotation will create a new Span and establish any required relationships with the current Trace context. + +Annotating a method in any CDI aware bean with the `io.opentelemetry.instrumentation.annotations.AddingSpanAttributes` will not create a new span but will add annotated method parameters to attributes in the current span. + +If a method is annotated by mistake with `@AddingSpanAttributes` and `@WithSpan` annotations, the `@WithSpan` annotation will take precedence. + +Method parameters can be annotated with the `io.opentelemetry.instrumentation.annotations.SpanAttribute` annotation to +indicate which method parameters should be part of the span. The parameter name can be customized as well. + +Example: +[source,java] +---- +@ApplicationScoped +class SpanBean { + @WithSpan + void span() { + + } + + @WithSpan("name") + void spanName() { + + } + + @WithSpan(kind = SERVER) + void spanKind() { + + } + + @WithSpan + void spanArgs(@SpanAttribute(value = "arg") String arg) { + + } + + @AddingSpanAttributes + void addArgumentToExistingSpan(@SpanAttribute(value = "arg") String arg) { + + } +} +---- + +=== Available OpenTelemetry CDI injections + +As per MicroProfile Telemetry Tracing specification, Quarkus supports the CDI injections of the +following classes: + +* `io.opentelemetry.api.OpenTelemetry` +* `io.opentelemetry.api.trace.Tracer` +* `io.opentelemetry.api.trace.Span` +* `io.opentelemetry.api.baggage.Baggage` + +You can inject these classes in any CDI enabled bean. For instance, the `Tracer` is particularly useful to start custom spans: + +[source,java] +---- +@Inject +Tracer tracer; + +... + +public void tracedWork() { + Span span = tracer.spanBuilder("My custom span") + .setAttribute("attr", "attr.value") + .setParent(Context.current().with(Span.current())) + .setSpanKind(SpanKind.INTERNAL) + .startSpan(); + + // traced work + + span.end(); +} +---- + +== Exporters + + + +[[configuration-reference]] +== OpenTelemetry Configuration Reference + diff --git a/docs/src/main/asciidoc/opentelemetry-tracing.adoc b/docs/src/main/asciidoc/opentelemetry-tracing.adoc new file mode 100644 index 0000000000000..799fc70a85f8f --- /dev/null +++ b/docs/src/main/asciidoc/opentelemetry-tracing.adoc @@ -0,0 +1,607 @@ +//// +This guide is maintained in the main Quarkus repository +and pull requests should be submitted there: +https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc +//// += Using OpenTelemetry Tracing +include::_attributes.adoc[] +:categories: observability +:summary: This guide explains how your Quarkus application can utilize OpenTelemetry Tracing to provide distributed tracing for interactive web applications. +:topics: observability,opentelemetry,tracing +:extensions: io.quarkus:quarkus-opentelemetry + +This guide explains how your Quarkus application can utilize https://opentelemetry.io/[OpenTelemetry] (OTel) to provide +distributed tracing for interactive web applications. + +[NOTE] +==== +- The xref:opentelemetry.adoc[OpenTelemetry Guide] is available with high-level information about OpenTelemetry and for signal independent, common functionality. +- If you search more information about OpenTelemetry Metrics, please refer to the xref:opentelemetry-metrics.adoc[OpenTelemetry Metrics Guide]. +==== + +== Prerequisites + +:prerequisites-docker-compose: +include::{includes}/prerequisites.adoc[] + +== Architecture + +In this guide, we create a straightforward REST application to demonstrate distributed tracing. + +== Solution + +We recommend that you follow the instructions in the next sections and create the application step by step. +However, you can skip right to the completed example. + +Clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {quickstarts-archive-url}[archive]. + +The solution is located in the `opentelemetry-quickstart` link:{quickstarts-tree-url}/opentelemetry-quickstart[directory]. + +== Creating the Maven project + +First, we need a new project. Create a new project with the following command: + +:create-app-artifact-id: opentelemetry-quickstart +:create-app-extensions: rest,quarkus-opentelemetry +include::{includes}/devtools/create-app.adoc[] + +This command generates the Maven project and imports the `quarkus-opentelemetry` extension, +which includes the default OpenTelemetry support, +and a gRPC span exporter for https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md[OTLP]. + +If you already have your Quarkus project configured, you can add the `quarkus-opentelemetry` extension +to your project by running the following command in your project base directory: + +:add-extension-extensions: opentelemetry +include::{includes}/devtools/extension-add.adoc[] + +This will add the following to your build file: + +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml +---- + + io.quarkus + quarkus-opentelemetry + +---- + +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.quarkus:quarkus-opentelemetry") +---- + +=== Examine the Jakarta REST resource + +Create a `src/main/java/org/acme/opentelemetry/TracedResource.java` file with the following content: + +[source,java] +---- +package org.acme.opentelemetry; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import org.jboss.logging.Logger; + +@Path("/hello") +public class TracedResource { + + private static final Logger LOG = Logger.getLogger(TracedResource.class); + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + LOG.info("hello"); + return "hello"; + } +} +---- + +Notice that there is no tracing specific code included in the application. By default, requests sent to this +endpoint will be traced without any required code changes. + +=== Create the configuration + + +:opentelemetry-config: +include::{includes}/opentelemetry-config.adoc[] + +== Run the application + +First we need to start a system to visualise the OpenTelemetry data. +We have 2 options: + +* Start an all-in-one Grafana OTel LGTM system for traces and metrics. +* Jaeger system just for traces. + +=== Grafana OTel LGTM option + +* Take a look at: xref:observability-devservices-lgtm.adoc[Getting Started with Grafana-OTel-LGTM]. + +This features a Quarkus Dev service including a Grafana for visualizing data, Loki to store logs, Tempo to store traces and Prometheus to store metrics. Also provides and OTel collector to receive the data. + +=== Jaeger to see traces option + +Configure and start the https://opentelemetry.io/docs/collector/[OpenTelemetry Collector] to receive, process and export telemetry data to https://www.jaegertracing.io/[Jaeger] that will display the captured traces. + +[NOTE] +==== +Jaeger-all-in-one includes the Jaeger agent, an OTel collector, and the query service/UI. +You do not need to install a separated collector. You can directly send the trace data to Jaeger (after enabling OTLP receivers there, see e.g. this +https://medium.com/jaegertracing/introducing-native-support-for-opentelemetry-in-jaeger-eb661be8183c[blog entry] for details). +==== + +Start the OpenTelemetry Collector and Jaeger system via the following `docker-compose.yml` file that you can launch via `docker-compose up -d`: + +[source,yaml,subs="attributes"] +---- +version: "2" +services: + + # Jaeger + jaeger-all-in-one: + image: jaegertracing/all-in-one:latest + ports: + - "16686:16686" # Jaeger UI + - "14268:14268" # Receive legacy OpenTracing traces, optional + - "4317:4317" # OTLP gRPC receiver + - "4318:4318" # OTLP HTTP receiver, not yet used by Quarkus, optional + - "14250:14250" # Receive from external otel-collector, optional + environment: + - COLLECTOR_OTLP_ENABLED=true +---- +You should remove the optional ports you don't need them. + +=== Start the application + +Now we are ready to run our application. If using `application.properties` to configure the tracer: + +include::{includes}/devtools/dev.adoc[] + +or if configuring the OTLP gRPC endpoint via JVM arguments: + +:dev-additional-parameters: -Djvm.args="-Dquarkus.otel.exporter.otlp.traces.endpoint=http://localhost:4317" +include::{includes}/devtools/dev.adoc[] +:!dev-additional-parameters: + +With the OpenTelemetry Collector, the Jaeger system and the application running, you can make a request to the provided endpoint: + +[source,shell] +---- +$ curl http://localhost:8080/hello +hello +---- + +When the first request has been submitted, you will be able to see the tracing information in the logs: + +[source] +---- +10:49:02 INFO traceId=, parentId=, spanId=, sampled= [io.quarkus] (main) Installed features: [cdi, opentelemetry, resteasy-client, resteasy, smallrye-context-propagation, vertx] +10:49:03 INFO traceId=17ceb8429b9f25b0b879fa1503259456, parentId=3125c8bee75b7ad6, spanId=58ce77c86dd23457, sampled=true [or.ac.op.TracedResource] (executor-thread-1) hello +10:49:03 INFO traceId=ad23acd6d9a4ed3d1de07866a52fa2df, parentId=, spanId=df13f5b45cf4d1e2, sampled=true [or.ac.op.TracedResource] (executor-thread-0) hello +---- + + +Then visit the http://localhost:16686[Jaeger UI] to see the tracing information. + +Hit `CTRL+C` or type `q` to stop the application. + +=== JDBC + +The https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/jdbc/library[JDBC instrumentation] will add a span for each JDBC queries done by your application, to enable it, add the following dependency to your build file: + +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml +---- + + io.opentelemetry.instrumentation + opentelemetry-jdbc + +---- + +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.opentelemetry.instrumentation:opentelemetry-jdbc") +---- + +As it uses a dedicated JDBC datasource wrapper, you must enable telemetry for your datasource: + +[source, properties] +---- +# enable tracing +quarkus.datasource.jdbc.telemetry=true + +# configure datasource +quarkus.datasource.db-kind=postgresql +quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydatabase +---- + +== Additional configuration +Some use cases will require custom configuration of OpenTelemetry. +These sections will outline what is necessary to properly configure it. + +=== ID Generator +The OpenTelemetry extension will use by default a random https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#id-generators[ID Generator] +when creating the trace and span identifier. + +Some vendor-specific protocols need a custom ID Generator, you can override the default one by creating a producer. +The OpenTelemetry extension will detect the `IdGenerator` CDI bean and will use it when configuring the tracer producer. + +[source,java] +---- +@Singleton +public class CustomConfiguration { + + /** Creates a custom IdGenerator for OpenTelemetry */ + @Produces + @Singleton + public IdGenerator idGenerator() { + return AwsXrayIdGenerator.getInstance(); + } +} +---- + +=== Propagators +OpenTelemetry propagates cross-cutting concerns through https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/api-propagators.md[propagators] that will share an underlying `Context` for storing state and accessing +data across the lifespan of a distributed transaction. + +By default, the OpenTelemetry extension enables the https://www.w3.org/TR/trace-context/[W3C Trace Context] and the https://www.w3.org/TR/baggage/[W3C Baggage] +propagators, you can however choose any of the supported OpenTelemetry propagators by setting the `propagators` config that is described in the <>. + +==== Additional Propagators + +* The `b3`, `b3multi`, `jaeger` and `ottrace` propagators will need the https://github.com/open-telemetry/opentelemetry-java/tree/main/extensions/trace-propagators[trace-propagators] +extension to be added as a dependency to your project. + +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml +---- + + io.opentelemetry + opentelemetry-extension-trace-propagators + +---- + +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.opentelemetry:opentelemetry-extension-trace-propagators") +---- + +* The `xray` propagator will need the https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/aws-xray-propagator[aws] +extension to be added as a dependency to your project. + +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml +---- + + io.opentelemetry.contrib + opentelemetry-aws-xray-propagator + +---- + +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator") +---- + +==== Customise Propagator + +To customise the propagation header you can implement the `TextMapPropagatorCustomizer` interface. This can be used, as an example, to restrict propagation of OpenTelemetry trace headers and prevent potentially sensitive data to be sent to third party systems. + +```java +/** + * /** + * Meant to be implemented by a CDI bean that provides arbitrary customization for the TextMapPropagator + * that are to be registered with OpenTelemetry + */ +public interface TextMapPropagatorCustomizer { + + TextMapPropagator customize(Context context); + + interface Context { + TextMapPropagator propagator(); + + ConfigProperties otelConfigProperties(); + } +} +``` + +=== Resource + +See the main xref:opentelemetry.adoc#resource[OpenTelemetry Guide resources] section. + +==== End User attributes + +When enabled, Quarkus adds OpenTelemetry End User attributes as Span attributes. +Before you enable this feature, verify that Quarkus Security extension is present and configured. +More information about the Quarkus Security can be found in the xref:security-overview.adoc[Quarkus Security overview]. + +The attributes are only added when authentication has already happened on a best-efforts basis. +Whether the End User attributes are added as Span attributes depends on authentication and authorization configuration of your Quarkus application. +If you create custom Spans prior to the authentication, Quarkus cannot add the End User attributes to them. +Quarkus is only able to add the attributes to the Span that is current after the authentication has been finished. +Another important consideration regarding custom Spans is active CDI request context that is used to propagate Quarkus `SecurityIdentity`. +In principle, Quarkus is able to add the End User attributes when the CDI request context has been activated for you before the custom Spans are created. + +[source,application.properties] +---- +quarkus.otel.traces.eusp.enabled=true <1> +quarkus.http.auth.proactive=true <2> +---- +<1> Enable the End User Attributes feature so that the `SecurityIdentity` principal and roles are added as Span attributes. +The End User attributes are personally identifiable information, therefore make sure you want to export them before you enable this feature. +<2> Optionally enable proactive authentication. +The best possible results are achieved when proactive authentication is enabled because the authentication happens sooner. +A good way to determine whether proactive authentication should be enabled in your Quarkus application is to read the Quarkus xref:security-proactive-authentication.adoc[Proactive authentication] guide. + +IMPORTANT: This feature is not supported when a custom xref:security-customization.adoc#jaxrs-security-context[Jakarta REST SecurityContexts] is used. + +[[sampler]] +=== Sampler +A https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#sampling[sampler] decides whether a trace should be discarded or forwarded, effectively managing noise and reducing overhead by limiting the number of collected traces sent to the collector. + +Quarkus comes equipped with a https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#built-in-samplers[built-in sampler], and you also have the option to create your custom sampler. + +To use the built-in sampler, you can configure it by setting the desired sampler parameters as detailed in the <>. As an example, you can configure the sampler to retain 50% of the traces: +[source,application.properties] +---- +# build time property only: +quarkus.otel.traces.sampler=traceidratio +# Runtime property: +quarkus.otel.traces.sampler.arg=0.5 +---- +[TIP] +==== + +An interesting use case for the sampler is to activate and deactivate tracing export at runtime, acording to this example: +[source,application.properties] +---- +# build time property only: +quarkus.otel.traces.sampler=traceidratio +# On (default). All traces are exported: +quarkus.otel.traces.sampler.arg=1.0 +# Off. No traces are exported: +quarkus.otel.traces.sampler.arg=0.0 +---- +==== + +[NOTE] +==== +Quarkus 3.0 introduced breaking changes on the configuration. + +Sampler related property names and values change to comply with the latest Java OpenTelemetry SDK. During a transition period it will be possible to set the new configuration values in the old property because we are mapping `quarkus.opentelemetry.tracer.sampler` -> `quarkus.otel.traces.sampler`. + +If the sampler is parent based, there is no need to set, the now dropped property, `quarkus.opentelemetry.tracer.sampler.parent-based`. + +The values you need to set on `quarkus.opentelemetry.tracer.sampler` are now: + +|=== +|Old Sampler config value |New Sampler config value|New Sampler config value (Parent based) + +|`on` +|`always_on` +|`parentbased_always_on` + +|`off` +|`always_off` +|`parentbased_always_off` + +|`ratio` +|`traceidratio` +|`parentbased_traceidratio` +|=== +==== + +If you need to use a custom sampler there are now 2 different ways: + +==== Sampler CDI Producer + +You can create a sampler CDI producer. The Quarkus OpenTelemetry extension will detect the `Sampler` CDI bean and will use it when configuring the Tracer. + +[source,java] +---- +@Singleton +public class CustomConfiguration { + + /** Creates a custom sampler for OpenTelemetry */ + @Produces + @Singleton + public Sampler sampler() { + return JaegerRemoteSampler.builder() + .setServiceName("my-service") + .build(); + } +} +---- + +==== OTel Sampler SPI + +This will use the SPI hooks available with the OTel Autoconfiguration. +You can create a simple Sampler class: +[source,java] +---- +public class CustomSPISampler implements Sampler { + @Override + public SamplingResult shouldSample(Context context, + String s, + String s1, + SpanKind spanKind, + Attributes attributes, + List list) { + // Do some sampling here + return Sampler.alwaysOn().shouldSample(context, s, s1, spanKind, attributes, list); + } + + @Override + public String getDescription() { + return "custom-spi-sampler-description"; + } +} + +---- +Then a Sampler Provider: +[source,java] +---- +public class CustomSPISamplerProvider implements ConfigurableSamplerProvider { + @Override + public Sampler createSampler(ConfigProperties configProperties) { + return new CustomSPISampler(); + } + + @Override + public String getName() { + return "custom-spi-sampler"; + } +} +---- +Write the SPI loader text file at `resources/META-INF/services` with name `io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider` containing the full qualified name of the `CustomSPISamplerProvider` class. + +Then activate on the configuration: +[source,properties] +---- +quarkus.otel.traces.sampler=custom-spi-sampler +---- + +As you can see, CDI is much simpler to work with. + +== Additional instrumentation + +Some Quarkus extensions will require additional code to ensure traces are propagated to subsequent execution. +These sections will outline what is necessary to propagate traces across process boundaries. + +The instrumentation documented in this section has been tested with Quarkus and works in both standard and native mode. + +=== CDI + +Annotating a method in any CDI aware bean with the `io.opentelemetry.instrumentation.annotations.WithSpan` +annotation will create a new Span and establish any required relationships with the current Trace context. + +Annotating a method in any CDI aware bean with the `io.opentelemetry.instrumentation.annotations.AddingSpanAttributes` will not create a new span but will add annotated method parameters to attributes in the current span. + +If a method is annotated by mistake with `@AddingSpanAttributes` and `@WithSpan` annotations, the `@WithSpan` annotation will take precedence. + +Method parameters can be annotated with the `io.opentelemetry.instrumentation.annotations.SpanAttribute` annotation to +indicate which method parameters should be part of the span. The parameter name can be customized as well. + +Example: +[source,java] +---- +@ApplicationScoped +class SpanBean { + @WithSpan + void span() { + + } + + @WithSpan("name") + void spanName() { + + } + + @WithSpan(kind = SERVER) + void spanKind() { + + } + + @WithSpan + void spanArgs(@SpanAttribute(value = "arg") String arg) { + + } + + @AddingSpanAttributes + void addArgumentToExistingSpan(@SpanAttribute(value = "arg") String arg) { + + } +} +---- + +=== Available OpenTelemetry CDI injections + +As per MicroProfile Telemetry Tracing specification, Quarkus supports the CDI injections of the +following classes: + +* `io.opentelemetry.api.OpenTelemetry` +* `io.opentelemetry.api.trace.Tracer` +* `io.opentelemetry.api.trace.Span` +* `io.opentelemetry.api.baggage.Baggage` + +You can inject these classes in any CDI enabled bean. For instance, the `Tracer` is particularly useful to start custom spans: + +[source,java] +---- +@Inject +Tracer tracer; + +... + +public void tracedWork() { + Span span = tracer.spanBuilder("My custom span") + .setAttribute("attr", "attr.value") + .setParent(Context.current().with(Span.current())) + .setSpanKind(SpanKind.INTERNAL) + .startSpan(); + + // traced work + + span.end(); +} +---- + +=== Quarkus Messaging - Kafka + +When using the Quarkus Messaging extension for Kafka, +we are able to propagate the span into the Kafka Record with: + +[source,java] +---- +TracingMetadata tm = TracingMetadata.withPrevious(Context.current()); +Message out = Message.of(...).withMetadata(tm); +---- + +The above creates a `TracingMetadata` object we can add to the `Message` being produced, +which retrieves the OpenTelemetry `Context` to extract the current span for propagation. + +=== Quarkus Security Events + +Quarkus supports exporting of the xref:security-customization.adoc#observe-security-events[Security events] as OpenTelemetry Span events. + +[source,application.properties] +---- +quarkus.otel.security-events.enabled=true <1> +---- +<1> Export Quarkus Security events as OpenTelemetry Span events. + +== Exporters + +See the main xref:opentelemetry.adoc#exporters[OpenTelemetry Guide exporters] section. + +[[quarkus-extensions-using-opentelemetry]] +== Quarkus core extensions instrumented with OpenTelemetry tracing + +* https://quarkus.io/extensions/io.quarkus/quarkus-agroal[`quarkus-agroal`] +* https://quarkus.io/guides/grpc-getting-started[`quarkus-grpc`] +* https://quarkus.io/guides/redis[`quarkus-redis-client`] +* https://quarkus.io/extensions/io.quarkus/quarkus-rest-client-jaxrs[`quarkus-rest-client-jaxrs`] +* https://quarkus.io/guides/rest[`quarkus-rest`] +* https://quarkus.io/guides/resteasy[`quarkus-resteasy-jackson`] +* https://quarkus.io/guides/resteasy-client[`quarkus-resteasy-client`] +* https://quarkus.io/guides/scheduler[`quarkus-scheduler`] +* https://quarkus.io/guides/smallrye-graphql[`quarkus-smallrye-graphql`] +* https://quarkus.io/extensions/io.quarkus/quarkus-mongodb-client[`quarkus-mongodb-client`] +* https://quarkus.io/extensions/io.quarkus/quarkus-messaging[`quarkus-messaging`] +** AMQP 1.0 +** RabbitMQ +** Kafka +** Pulsar +* https://quarkus.io/guides/vertx[`quarkus-vertx`] (http requests) + +[[configuration-reference]] +== OpenTelemetry Configuration Reference + +See the main xref:opentelemetry.adoc#configuration-reference[OpenTelemetry Guide configuration] reference. \ No newline at end of file diff --git a/docs/src/main/asciidoc/opentelemetry.adoc b/docs/src/main/asciidoc/opentelemetry.adoc index bc5cb1e2c72fa..b059cdc7684ec 100644 --- a/docs/src/main/asciidoc/opentelemetry.adoc +++ b/docs/src/main/asciidoc/opentelemetry.adoc @@ -5,57 +5,68 @@ https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc //// = Using OpenTelemetry include::_attributes.adoc[] +:diataxis-type: reference :categories: observability -:summary: This guide explains how your Quarkus application can utilize OpenTelemetry to provide distributed tracing for interactive web applications. +:summary: This guide explains how your Quarkus application can utilize OpenTelemetry to provide observability for interactive web applications. :topics: observability,opentelemetry :extensions: io.quarkus:quarkus-opentelemetry This guide explains how your Quarkus application can utilize https://opentelemetry.io/[OpenTelemetry] (OTel) to provide -distributed tracing for interactive web applications. +Observability for interactive web applications. + +Here we show the signal independent features of the extension. [NOTE] ==== -- OpenTelemetry Metrics and Logging are not yet supported. -- Quarkus now supports the OpenTelemetry Autoconfiguration for Traces. The configurations match what you can see at -https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md[OpenTelemetry SDK Autoconfigure] -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]. +- The old OpenTelemetry guide has been split into this generic guide, the xref:opentelemetry-tracing.adoc[OpenTelemetry Tracing Guide] and the new xref:opentelemetry-metrics.adoc[OpenTelemetry Metrics Guide] has been created. +- OpenTelemetry Logging is not yet supported. +- 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*. ==== -== Prerequisites +== Introduction +https://opentelemetry.io/docs/what-is-opentelemetry/[OpenTelemetry] is an Observability framework and toolkit designed to create and manage telemetry data such as traces, metrics, and logs. Crucially, OpenTelemetry is vendor- and tool-agnostic. -:prerequisites-docker-compose: -include::{includes}/prerequisites.adoc[] +Quarkus provides manual and automatic instrumentation for tracing and manual instrumentation capabilities for metrics. -== Architecture +This will allow Quarkus based applications to be observable by tools and services supporting OpenTelemetry. -In this guide, we create a straightforward REST application to demonstrate distributed tracing. +[NOTE] +==== +Automatic metrics instrumentation in Quarkus is done by the xref:telemetry-micrometer.adoc[Quarkus Micrometer extension]. We plan to provide, in the future, a bridge for those metrics to be available also in OpenTelemetry. +==== -== Solution +Quarkus supports the OpenTelemetry Autoconfiguration. The configurations match what you can see at +https://opentelemetry.io/docs/languages/java/configuration/[OpenTelemetry SDK Autoconfigure] +with the `quarkus.*` prefix. -We recommend that you follow the instructions in the next sections and create the application step by step. -However, you can skip right to the completed example. +This guide provides a crosscutting explanation of the OpenTelemetry extension and how to use it. If you need detailed about any particular signal (tracing or metrics), please refer to the signal specific guide. -Clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {quickstarts-archive-url}[archive]. +With the introduction of OpenTelemetry Metrics, the original guide had to be split according to signal types, as follows: -The solution is located in the `opentelemetry-quickstart` link:{quickstarts-tree-url}/opentelemetry-quickstart[directory]. +=== xref:opentelemetry-tracing.adoc[OpenTelemetry Tracing Guide] -== Creating the Maven project +The tracing functionality is supported and *on* by default. -First, we need a new project. Create a new project with the following command: +=== xref:opentelemetry-metrics.adoc[OpenTelemetry Metrics Guide] -:create-app-artifact-id: opentelemetry-quickstart -:create-app-extensions: rest,quarkus-opentelemetry -include::{includes}/devtools/create-app.adoc[] +==== Enable Metrics +The metrics functionality is experimental and *off* by default. You will need to activate it by setting: -This command generates the Maven project and imports the `quarkus-opentelemetry` extension, -which includes the default OpenTelemetry support, -and a gRPC span exporter for https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md[OTLP]. +[source,properties] +---- +quarkus.otel.metrics.enabled=true +---- +At build time on your `application.properties` file. + +==== Manual instrumentation only +For now only manual instrumentation is supported. You can use the OpenTelemetry API to create and record metrics but Quarkus is not yet providing automatic instrumentation for metrics. + +In the future, we plan to bridge current Micrometer metrics to OpenTelemetry and maintain compatibility when possible. + +== Using the extension -If you already have your Quarkus project configured, you can add the `quarkus-opentelemetry` extension -to your project by running the following command in your project base directory: +If you already have your Quarkus project, you can add the `quarkus-opentelemetry` extension +to it by running the following command in your project base directory: :add-extension-extensions: opentelemetry include::{includes}/devtools/extension-add.adoc[] @@ -77,307 +88,118 @@ This will add the following to your build file: implementation("io.quarkus:quarkus-opentelemetry") ---- -=== Examine the Jakarta REST resource - -Create a `src/main/java/org/acme/opentelemetry/TracedResource.java` file with the following content: - -[source,java] ----- -package org.acme.opentelemetry; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; -import org.jboss.logging.Logger; - -@Path("/hello") -public class TracedResource { - - private static final Logger LOG = Logger.getLogger(TracedResource.class); - - @GET - @Produces(MediaType.TEXT_PLAIN) - public String hello() { - LOG.info("hello"); - return "hello"; - } -} ----- - -Notice that there is no tracing specific code included in the application. By default, requests sent to this -endpoint will be traced without any required code changes. === Create the configuration -There are no mandatory configurations for the extension to work. - -If you need to change any of the default property values, here is an example on how to configure the default OTLP gRPC Exporter within the application, using the `src/main/resources/application.properties` file: - -[source,properties] ----- -quarkus.application.name=myservice // <1> -quarkus.otel.exporter.otlp.traces.endpoint=http://localhost:4317 // <2> -quarkus.otel.exporter.otlp.traces.headers=authorization=Bearer my_secret // <3> -quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} [%c{2.}] (%t) %s%e%n // <4> - -# Alternative to the console log -quarkus.http.access-log.pattern="...traceId=%{X,traceId} spanId=%{X,spanId}" // <5> ----- - -<1> All spans created from the application will include an OpenTelemetry `Resource` indicating the span was created by the `myservice` application. If not set, it will default to the artifact id. -<2> gRPC endpoint to send spans. If not set, it will default to `http://localhost:4317`. -<3> Optional gRPC headers commonly used for authentication -<4> Add tracing information into log messages. -<5> You can also only put the trace info into the access log. In this case you must omit the info in the console log format. - -[NOTE] -==== -All configurations have been updated from `quarkus.opentelemetry.\*` -> `quarkus.otel.*` - -The legacy configurations are now deprecated but will still work during a transition period. -==== +:opentelemetry-config: +include::{includes}/opentelemetry-config.adoc[] === Disable all or parts of the OpenTelemetry extension -Once you add the dependency, the extension will be enabled by default but there are a few ways to disable the OpenTelemetry extension globally or partially. +Once you add the dependency, the extension will generate tracing data by default. To enable metrics or disable the OpenTelemetry extension globally or partially these are the properties to use (they are extracted from the config reference bellow): |=== -|Property name |Default value |Description +|Affected Signal | Property name |Default value |Description +| All |`quarkus.otel.enabled` |true |If false, disable the OpenTelemetry usage at *build* time. +| All |`quarkus.otel.sdk.disabled` |false |Comes from the OpenTelemetry autoconfiguration. If true, will disable the OpenTelemetry SDK usage at *runtime*. -|`quarkus.otel.traces.enabled` -|true -|If false, disable the OpenTelemetry tracing usage at *build* time. - +| All output |`quarkus.otel.exporter.otlp.enabled` |true -|If false will disable the default OTLP exporter at *build* time. -|=== - -If you need to enable or disable the exporter at runtime, you can use the <> because it has the ability to filter out all the spans if needed. - - -== Run the application - -First we need to start a system to visualise the OpenTelemetry data. -We have 2 options: - -* Start an all-in-one Grafana OTel LGTM system for traces and metrics. -* Jaeger system just for traces. - -=== Grafana OTel LGTM option - -* Take a look at: xref:observability-devservices-lgtm.adoc[Getting Started with Grafana-OTel-LGTM]. - -This features a Quarkus Dev service including a Grafana for visualizing data, Loki to store logs, Tempo to store traces and Prometheus to store metrics. Also provides and OTel collector to receive the data. - -=== Jaeger to see traces option - -Configure and start the https://opentelemetry.io/docs/collector/[OpenTelemetry Collector] to receive, process and export telemetry data to https://www.jaegertracing.io/[Jaeger] that will display the captured traces. - -[NOTE] -==== -Jaeger-all-in-one includes the Jaeger agent, an OTel collector, and the query service/UI. -You do not need to install a separated collector. You can directly send the trace data to Jaeger (after enabling OTLP receivers there, see e.g. this -https://medium.com/jaegertracing/introducing-native-support-for-opentelemetry-in-jaeger-eb661be8183c[blog entry] for details). -==== - -Start the OpenTelemetry Collector and Jaeger system via the following `docker-compose.yml` file that you can launch via `docker-compose up -d`: - -[source,yaml,subs="attributes"] ----- -version: "2" -services: - - # Jaeger - jaeger-all-in-one: - image: jaegertracing/all-in-one:latest - ports: - - "16686:16686" # Jaeger UI - - "14268:14268" # Receive legacy OpenTracing traces, optional - - "4317:4317" # OTLP gRPC receiver - - "4318:4318" # OTLP HTTP receiver, not yet used by Quarkus, optional - - "14250:14250" # Receive from external otel-collector, optional - environment: - - COLLECTOR_OTLP_ENABLED=true ----- -You should remove the optional ports you don't need them. - -=== Start the application - -Now we are ready to run our application. If using `application.properties` to configure the tracer: - -include::{includes}/devtools/dev.adoc[] - -or if configuring the OTLP gRPC endpoint via JVM arguments: - -:dev-additional-parameters: -Djvm.args="-Dquarkus.otel.exporter.otlp.traces.endpoint=http://localhost:4317" -include::{includes}/devtools/dev.adoc[] -:!dev-additional-parameters: +|Deprecated for removal. -With the OpenTelemetry Collector, the Jaeger system and the application running, you can make a request to the provided endpoint: +If false will disable the default OTLP exporter at *build* time. -[source,shell] ----- -$ curl http://localhost:8080/hello -hello ----- - -When the first request has been submitted, you will be able to see the tracing information in the logs: - -[source] ----- -10:49:02 INFO traceId=, parentId=, spanId=, sampled= [io.quarkus] (main) Installed features: [cdi, opentelemetry, resteasy-client, resteasy, smallrye-context-propagation, vertx] -10:49:03 INFO traceId=17ceb8429b9f25b0b879fa1503259456, parentId=3125c8bee75b7ad6, spanId=58ce77c86dd23457, sampled=true [or.ac.op.TracedResource] (executor-thread-1) hello -10:49:03 INFO traceId=ad23acd6d9a4ed3d1de07866a52fa2df, parentId=, spanId=df13f5b45cf4d1e2, sampled=true [or.ac.op.TracedResource] (executor-thread-0) hello ----- - - -Then visit the http://localhost:16686[Jaeger UI] to see the tracing information. - -Hit `CTRL+C` or type `q` to stop the application. - -=== JDBC - -The https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/jdbc/library[JDBC instrumentation] will add a span for each JDBC queries done by your application, to enable it, add the following dependency to your build file: - -[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] -.pom.xml ----- - - io.opentelemetry.instrumentation - opentelemetry-jdbc - ----- +| Traces +|`quarkus.otel.traces.enabled` +|true +|If false, disable the OpenTelemetry tracing usage at *build* time. -[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] -.build.gradle ----- -implementation("io.opentelemetry.instrumentation:opentelemetry-jdbc") ----- +| Traces output +|`quarkus.otel.traces.exporter` +|cdi +|List of exporters to be used for tracing, separated by commas. Has one of the values from _ExporterType_: `otlp`, `cdi`, `none`. This is a *build* time property and setting it to `none` will disable tracing data output. -As it uses a dedicated JDBC datasource wrapper, you must enable telemetry for your datasource: +| Metrics +|`quarkus.otel.metrics.enabled` +|false +|Metrics are disabled by default at *build* time because they are experimental. -[source, properties] ----- -# enable tracing -quarkus.datasource.jdbc.telemetry=true +| Metrics output +|`quarkus.otel.metrics.exporter` +|cdi +|List of exporters to be used for metrics, separated by commas. Has one of the values from _ExporterType_: `otlp`, `cdi`, `none`. This is a *build* time property and setting it to `none` will disable metrics data output. +|=== -# configure datasource -quarkus.datasource.db-kind=postgresql -quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydatabase ----- +If you need to enable or disable the exporter at runtime, you can use the <> because it has the ability to filter out all the spans if needed. -== Additional configuration -Some use cases will require custom configuration of OpenTelemetry. -These sections will outline what is necessary to properly configure it. +Particular instrumentation components can be disabled in tracing, like ignore client requests but keep server ones. For more details, please check the xref:opentelemetry-tracing.adoc[OpenTelemetry Tracing Guide]. -=== ID Generator -The OpenTelemetry extension will use by default a random https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#id-generators[ID Generator] -when creating the trace and span identifier. +=== Resource +A https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#resources[resource] is a representation +of the entity that is producing telemetry, it adds attributes to the exported trace or metric to characterize who is producing the telemetry. Quarkus follows the https://opentelemetry.io/docs/languages/java/configuration/#resources[resources auto-configuration] specified by the Java OpenTelemetry SDK. -Some vendor-specific protocols need a custom ID Generator, you can override the default one by creating a producer. -The OpenTelemetry extension will detect the `IdGenerator` CDI bean and will use it when configuring the tracer producer. +==== Default +The following attributes are added by default to resources. -[source,java] ----- -@Singleton -public class CustomConfiguration { +|=== +|Attribute name|Content example|Origin - /** Creates a custom IdGenerator for OpenTelemetry */ - @Produces - @Singleton - public IdGenerator idGenerator() { - return AwsXrayIdGenerator.getInstance(); - } -} ----- +|service.name +|"opentelemetry-quickstart" +|Value comes from the artifactId, from the `quarkus.application.name` property or from `quarkus.otel.resource.attributes=service.name=cart` property. -=== Propagators -OpenTelemetry propagates cross-cutting concerns through https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/api-propagators.md[propagators] that will share an underlying `Context` for storing state and accessing -data across the lifespan of a distributed transaction. +|host.name +|"bbaptist-mac" +|Resolved at startup -By default, the OpenTelemetry extension enables the https://www.w3.org/TR/trace-context/[W3C Trace Context] and the https://www.w3.org/TR/baggage/[W3C Baggage] -propagators, you can however choose any of the supported OpenTelemetry propagators by setting the `propagators` config that is described in the <>. +|service.version +|"1.0-SNAPSHOT" +|Resolved at build time from the artifact version -==== Additional Propagators +|telemetry.sdk.language +|"java" +|Static value -* The `b3`, `b3multi`, `jaeger` and `ottrace` propagators will need the https://github.com/open-telemetry/opentelemetry-java/tree/main/extensions/trace-propagators[trace-propagators] -extension to be added as a dependency to your project. +|telemetry.sdk.name +|"opentelemetry" +|Resolved at build time -[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] -.pom.xml ----- - - io.opentelemetry - opentelemetry-extension-trace-propagators - ----- +|telemetry.sdk.version +|"1.32.0" +|Resolved at build time -[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] -.build.gradle ----- -implementation("io.opentelemetry:opentelemetry-extension-trace-propagators") ----- +|webengine.name +|"Quarkus" +|Static value -* The `xray` propagator will need the https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/aws-xray-propagator[aws] -extension to be added as a dependency to your project. +|webengine.version +|"999-SNAPSHOT" +|Quarkus version resolved at build time +|=== -[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] -.pom.xml ----- - - io.opentelemetry.contrib - opentelemetry-aws-xray-propagator - ----- +==== Using configuration +You can add additional attributes by setting the `quarkus.otel.resource.attributes` config that is described in the <>. +Since this property can be overridden at runtime, the OpenTelemetry extension will pick up its value following the order of precedence that +is described in the xref:config-reference.adoc#configuration-sources[Quarkus Configuration Reference]. -[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] -.build.gradle +[Source,properties] ---- -implementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator") +quarkus.otel.resource.attributes=deployment.environment=dev,service.name=cart,service.namespace=shopping ---- +This will add the attributes for `deployment.environment`, `service.name` and `service.namespace` to the resource and be included in traces and metrics. -==== Customise Propagator - -To customise the propagation header you can implement the `TextMapPropagatorCustomizer` interface. This can be used, as an example, to restrict propagation of OpenTelemetry trace headers and prevent potentially sensitive data to be sent to third party systems. - -```java -/** - * /** - * Meant to be implemented by a CDI bean that provides arbitrary customization for the TextMapPropagator - * that are to be registered with OpenTelemetry - */ -public interface TextMapPropagatorCustomizer { - - TextMapPropagator customize(Context context); - - interface Context { - TextMapPropagator propagator(); - - ConfigProperties otelConfigProperties(); - } -} -``` - -=== Resource -A https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#resources[resource] is a representation -of the entity that is producing telemetry, it adds attributes to the exported trace to characterize who is producing the trace. - -You can add attributes by setting the `resource-attributes` tracer config that is described in the <>. -Since this property can be overridden at runtime, the OpenTelemetry extension will pick up its value following the order of precedence that -is described in the xref:config-reference.adoc#configuration-sources[Quarkus Configuration Reference]. - +==== Using CDI beans If by any means you need to use a custom resource or one that is provided by one of the https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions[OpenTelemetry SDK Extensions] -you can create multiple resource producers. The OpenTelemetry extension will detect the `Resource` CDI beans and will merge them when configuring the tracer producer. +you can create multiple resource producers. The OpenTelemetry extension will detect the `Resource` CDI beans and will merge them when configuring the OTel SDK. [source,java] ---- @@ -398,299 +220,36 @@ public class CustomConfiguration { } ---- -==== End User attributes - -When enabled, Quarkus adds OpenTelemetry End User attributes as Span attributes. -Before you enable this feature, verify that Quarkus Security extension is present and configured. -More information about the Quarkus Security can be found in the xref:security-overview.adoc[Quarkus Security overview]. - -The attributes are only added when authentication has already happened on a best-efforts basis. -Whether the End User attributes are added as Span attributes depends on authentication and authorization configuration of your Quarkus application. -If you create custom Spans prior to the authentication, Quarkus cannot add the End User attributes to them. -Quarkus is only able to add the attributes to the Span that is current after the authentication has been finished. -Another important consideration regarding custom Spans is active CDI request context that is used to propagate Quarkus `SecurityIdentity`. -In principle, Quarkus is able to add the End User attributes when the CDI request context has been activated for you before the custom Spans are created. - -[source,application.properties] ----- -quarkus.otel.traces.eusp.enabled=true <1> -quarkus.http.auth.proactive=true <2> ----- -<1> Enable the End User Attributes feature so that the `SecurityIdentity` principal and roles are added as Span attributes. -The End User attributes are personally identifiable information, therefore make sure you want to export them before you enable this feature. -<2> Optionally enable proactive authentication. -The best possible results are achieved when proactive authentication is enabled because the authentication happens sooner. -A good way to determine whether proactive authentication should be enabled in your Quarkus application is to read the Quarkus xref:security-proactive-authentication.adoc[Proactive authentication] guide. - -IMPORTANT: This feature is not supported when a custom xref:security-customization.adoc#jaxrs-security-context[Jakarta REST SecurityContexts] is used. - -[[sampler]] -=== Sampler -A https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#sampling[sampler] decides whether a trace should be discarded or forwarded, effectively managing noise and reducing overhead by limiting the number of collected traces sent to the collector. - -Quarkus comes equipped with a https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#built-in-samplers[built-in sampler], and you also have the option to create your custom sampler. - -To use the built-in sampler, you can configure it by setting the desired sampler parameters as detailed in the <>. As an example, you can configure the sampler to retain 50% of the traces: -[source,application.properties] ----- -# build time property only: -quarkus.otel.traces.sampler=traceidratio -# Runtime property: -quarkus.otel.traces.sampler.arg=0.5 ----- -[TIP] -==== - -An interesting use case for the sampler is to activate and deactivate tracing export at runtime, acording to this example: -[source,application.properties] ----- -# build time property only: -quarkus.otel.traces.sampler=traceidratio -# On (default). All traces are exported: -quarkus.otel.traces.sampler.arg=1.0 -# Off. No traces are exported: -quarkus.otel.traces.sampler.arg=0.0 ----- -==== - -[NOTE] -==== -Quarkus 3.0 introduced breaking changes on the configuration. - -Sampler related property names and values change to comply with the latest Java OpenTelemetry SDK. During a transition period it will be possible to set the new configuration values in the old property because we are mapping `quarkus.opentelemetry.tracer.sampler` -> `quarkus.otel.traces.sampler`. - -If the sampler is parent based, there is no need to set, the now dropped property, `quarkus.opentelemetry.tracer.sampler.parent-based`. - -The values you need to set on `quarkus.opentelemetry.tracer.sampler` are now: - -|=== -|Old Sampler config value |New Sampler config value|New Sampler config value (Parent based) - -|`on` -|`always_on` -|`parentbased_always_on` - -|`off` -|`always_off` -|`parentbased_always_off` - -|`ratio` -|`traceidratio` -|`parentbased_traceidratio` -|=== -==== - -If you need to use a custom sampler there are now 2 different ways: - -==== Sampler CDI Producer - -You can create a sampler CDI producer. The Quarkus OpenTelemetry extension will detect the `Sampler` CDI bean and will use it when configuring the Tracer. - -[source,java] ----- -@Singleton -public class CustomConfiguration { - - /** Creates a custom sampler for OpenTelemetry */ - @Produces - @Singleton - public Sampler sampler() { - return JaegerRemoteSampler.builder() - .setServiceName("my-service") - .build(); - } -} ----- - -==== OTel Sampler SPI - -This will use the SPI hooks available with the OTel Autoconfiguration. -You can create a simple Sampler class: -[source,java] ----- -public class CustomSPISampler implements Sampler { - @Override - public SamplingResult shouldSample(Context context, - String s, - String s1, - SpanKind spanKind, - Attributes attributes, - List list) { - // Do some sampling here - return Sampler.alwaysOn().shouldSample(context, s, s1, spanKind, attributes, list); - } - - @Override - public String getDescription() { - return "custom-spi-sampler-description"; - } -} - ----- -Then a Sampler Provider: -[source,java] ----- -public class CustomSPISamplerProvider implements ConfigurableSamplerProvider { - @Override - public Sampler createSampler(ConfigProperties configProperties) { - return new CustomSPISampler(); - } - - @Override - public String getName() { - return "custom-spi-sampler"; - } -} ----- -Write the SPI loader text file at `resources/META-INF/services` with name `io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider` containing the full qualified name of the `CustomSPISamplerProvider` class. - -Then activate on the configuration: -[source,properties] ----- -quarkus.otel.traces.sampler=custom-spi-sampler ----- - -As you can see, CDI is much simpler to work with. - -== Additional instrumentation - -Some Quarkus extensions will require additional code to ensure traces are propagated to subsequent execution. -These sections will outline what is necessary to propagate traces across process boundaries. - -The instrumentation documented in this section has been tested with Quarkus and works in both standard and native mode. - -=== CDI - -Annotating a method in any CDI aware bean with the `io.opentelemetry.instrumentation.annotations.WithSpan` -annotation will create a new Span and establish any required relationships with the current Trace context. - -Annotating a method in any CDI aware bean with the `io.opentelemetry.instrumentation.annotations.AddingSpanAttributes` will not create a new span but will add annotated method parameters to attributes in the current span. - -If a method is annotated by mistake with `@AddingSpanAttributes` and `@WithSpan` annotations, the `@WithSpan` annotation will take precedence. - -Method parameters can be annotated with the `io.opentelemetry.instrumentation.annotations.SpanAttribute` annotation to -indicate which method parameters should be part of the span. The parameter name can be customized as well. - -Example: -[source,java] ----- -@ApplicationScoped -class SpanBean { - @WithSpan - void span() { - - } - - @WithSpan("name") - void spanName() { - - } - - @WithSpan(kind = SERVER) - void spanKind() { - - } - - @WithSpan - void spanArgs(@SpanAttribute(value = "arg") String arg) { - - } - - @AddingSpanAttributes - void addArgumentToExistingSpan(@SpanAttribute(value = "arg") String arg) { - - } -} ----- - -=== Available OpenTelemetry CDI injections - -As per MicroProfile Telemetry Tracing specification, Quarkus supports the CDI injections of the -following classes: - -* `io.opentelemetry.api.OpenTelemetry` -* `io.opentelemetry.api.trace.Tracer` -* `io.opentelemetry.api.trace.Span` -* `io.opentelemetry.api.baggage.Baggage` - -You can inject these classes in any CDI enabled bean. For instance, the `Tracer` is particularly useful to start custom spans: - -[source,java] ----- -@Inject -Tracer tracer; - -... - -public void tracedWork() { - Span span = tracer.spanBuilder("My custom span") - .setAttribute("attr", "attr.value") - .setParent(Context.current().with(Span.current())) - .setSpanKind(SpanKind.INTERNAL) - .startSpan(); - - // traced work - - span.end(); -} ----- - -=== Quarkus Messaging - Kafka +== Exporters -When using the Quarkus Messaging extension for Kafka, -we are able to propagate the span into the Kafka Record with: +=== Default -[source,java] ----- -TracingMetadata tm = TracingMetadata.withPrevious(Context.current()); -Message out = Message.of(...).withMetadata(tm); ----- +The Quarkus OpenTelemetry extension uses its own signal exporters built on top of Vert.x for optimal performance and maintainability. -The above creates a `TracingMetadata` object we can add to the `Message` being produced, -which retrieves the OpenTelemetry `Context` to extract the current span for propagation. +The exporter is automatically wired with CDI, that's why the `quarkus.otel.traces.exporter` and `quarkus.otel.metrics.exporter` properties default to `cdi`. -=== Quarkus Security Events +The `quarkus.otel.exporter.otlp.protocol` default to `grpc` and `http/protobuf` can also be used. -Quarkus supports exporting of the xref:security-customization.adoc#observe-security-events[Security events] as OpenTelemetry Span events. +=== On Quarkiverse +Additional exporters will be available in the Quarkiverse https://docs.quarkiverse.io/quarkus-opentelemetry-exporter/dev/index.html[quarkus-opentelemetry-exporter] project. -[source,application.properties] ----- -quarkus.otel.security-events.enabled=true <1> ----- -<1> Export Quarkus Security events as OpenTelemetry Span events. +Currently, are available the following exporters (may be outdated) for: -== Exporters +- Legacy Jaeger +- Microsoft Azure +- Google Cloud -=== Default +Also on Quarkiverse, the https://docs.quarkiverse.io/quarkus-amazon-services/dev/opentelemetry.html[Quarkus AWS SDK has integration with OpenTelemetry]. -The Quarkus OpenTelemetry extension uses its own exporter built on top of Vert.x for optimal performance and maintainability. +== Visualizing the data -The exporter is automatically wired with CDI, that's why the `quarkus.otel.traces.exporter` property defaults to `cdi`. +We recommend the xref:observability-devservices-lgtm.adoc[Getting Started with Grafana-OTel-LGTM]. -The `quarkus.otel.exporter.otlp.traces.protocol` default to `grpc` and `http/protobuf` can also be used. +This provides a Quarkus Dev service using an "all-in-one" https://github.com/grafana/docker-otel-lgtm[Grafana OTel LGTM]. -=== On Quarkiverse -Additional exporters will be available in the Quarkiverse https://docs.quarkiverse.io/quarkus-opentelemetry-exporter/dev/index.html[quarkus-opentelemetry-exporter] project. +Grafana is used to visualize data, Loki to store logs, Tempo to store traces and Prometheus to store metrics. Also provides and OTel collector to receive the data. -[[quarkus-extensions-using-opentelemetry]] -== Quarkus core extensions instrumented with OpenTelemetry tracing - -* https://quarkus.io/extensions/io.quarkus/quarkus-agroal[`quarkus-agroal`] -* https://quarkus.io/guides/grpc-getting-started[`quarkus-grpc`] -* https://quarkus.io/guides/redis[`quarkus-redis-client`] -* https://quarkus.io/extensions/io.quarkus/quarkus-rest-client-jaxrs[`quarkus-rest-client-jaxrs`] -* https://quarkus.io/guides/rest[`quarkus-rest`] -* https://quarkus.io/guides/resteasy[`quarkus-resteasy-jackson`] -* https://quarkus.io/guides/resteasy-client[`quarkus-resteasy-client`] -* https://quarkus.io/guides/scheduler[`quarkus-scheduler`] -* https://quarkus.io/guides/smallrye-graphql[`quarkus-smallrye-graphql`] -* https://quarkus.io/extensions/io.quarkus/quarkus-mongodb-client[`quarkus-mongodb-client`] -* https://quarkus.io/extensions/io.quarkus/quarkus-messaging[`quarkus-messaging`] -** AMQP 1.0 -** RabbitMQ -** Kafka -** Pulsar -* https://quarkus.io/guides/vertx[`quarkus-vertx`] (http requests) +This provides an easy way to visualize all OpenTelemetry data generated by the application. [[configuration-reference]] == OpenTelemetry Configuration Reference @@ -702,7 +261,4 @@ adding the usual `quarkus.*` prefix. Quarkus OpenTelemetry configuration properties now have the `quarkus.otel.*` prefix. -*The legacy properties* with prefix `quarkus.opentelemetry.*` are currently being mapped to the new ones as a default, during a transition period. See Default column in the details below. - - include::{generated-dir}/config/quarkus-opentelemetry.adoc[leveloffset=+1, opts=optional] 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 ab745941977be..4664cb0d67faf 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,7 +2,6 @@ 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; @@ -104,7 +103,7 @@ AdditionalBeanBuildItem ensureProducerIsRetained() { return AdditionalBeanBuildItem.builder() .setUnremovable() .addBeanClasses( - AutoConfiguredOpenTelemetrySdkBuilderCustomizer.ResourceCustomizer.class, + AutoConfiguredOpenTelemetrySdkBuilderCustomizer.TracingResourceCustomizer.class, AutoConfiguredOpenTelemetrySdkBuilderCustomizer.SamplerCustomizer.class, AutoConfiguredOpenTelemetrySdkBuilderCustomizer.TracerProviderCustomizer.class, AutoConfiguredOpenTelemetrySdkBuilderCustomizer.MetricProviderCustomizer.class, 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 aa7360206490b..eb5f2ab912fb4 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 @@ -41,7 +41,7 @@ public interface AutoConfiguredOpenTelemetrySdkBuilderCustomizer { void customize(AutoConfiguredOpenTelemetrySdkBuilder builder); @Singleton - final class ResourceCustomizer implements AutoConfiguredOpenTelemetrySdkBuilderCustomizer { + final class TracingResourceCustomizer implements AutoConfiguredOpenTelemetrySdkBuilderCustomizer { private final ApplicationConfig appConfig; private final OTelBuildConfig oTelBuildConfig; @@ -49,11 +49,11 @@ final class ResourceCustomizer implements AutoConfiguredOpenTelemetrySdkBuilderC private final Instance delayedAttributes; private final List resources; - public ResourceCustomizer(ApplicationConfig appConfig, - OTelBuildConfig oTelBuildConfig, - OTelRuntimeConfig oTelRuntimeConfig, - @Any Instance delayedAttributes, - @All List resources) { + public TracingResourceCustomizer(ApplicationConfig appConfig, + OTelBuildConfig oTelBuildConfig, + OTelRuntimeConfig oTelRuntimeConfig, + @Any Instance delayedAttributes, + @All List resources) { this.appConfig = appConfig; this.oTelBuildConfig = oTelBuildConfig; this.oTelRuntimeConfig = oTelRuntimeConfig; @@ -66,7 +66,8 @@ public void customize(AutoConfiguredOpenTelemetrySdkBuilder builder) { builder.addResourceCustomizer(new BiFunction<>() { @Override public Resource apply(Resource existingResource, ConfigProperties configProperties) { - if (oTelBuildConfig.traces().enabled().orElse(TRUE)) { + if (oTelBuildConfig.traces().enabled().orElse(TRUE) || + oTelBuildConfig.metrics().enabled().orElse(TRUE)) { Resource consolidatedResource = existingResource.merge( Resource.create(delayedAttributes.get())); @@ -82,13 +83,7 @@ public boolean test(String sn) { }) .orElse(null); - // must be resolved at startup, once. - String hostname = null; - try { - hostname = InetAddress.getLocalHost().getHostName(); - } catch (UnknownHostException e) { - hostname = "unknown"; - } + String hostname = getHostname(); // Merge resource instances with env attributes Resource resource = resources.stream() @@ -259,4 +254,16 @@ public ConfigProperties otelConfigProperties() { } } } + + private static String getHostname() { + // must be resolved at startup, once. + String hostname = null; + try { + hostname = InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + hostname = "unknown"; + } + return hostname; + } + } diff --git a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/HierarchicalOTelConnectionConfigInterceptor.java b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/HierarchicalOTelConnectionConfigInterceptor.java similarity index 98% rename from extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/HierarchicalOTelConnectionConfigInterceptor.java rename to extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/HierarchicalOTelConnectionConfigInterceptor.java index 6b612fdba0d8e..bd011e5a4c684 100644 --- a/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/runtime/HierarchicalOTelConnectionConfigInterceptor.java +++ b/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/config/HierarchicalOTelConnectionConfigInterceptor.java @@ -1,4 +1,4 @@ -package io.quarkus.opentelemetry.runtime.config.runtime; +package io.quarkus.opentelemetry.runtime.config; import java.util.HashSet; import java.util.Iterator; diff --git a/extensions/opentelemetry/runtime/src/main/resources/META-INF/services/io.smallrye.config.ConfigSourceInterceptor b/extensions/opentelemetry/runtime/src/main/resources/META-INF/services/io.smallrye.config.ConfigSourceInterceptor index d9f3e1f659c52..55782f5c4d6ec 100644 --- a/extensions/opentelemetry/runtime/src/main/resources/META-INF/services/io.smallrye.config.ConfigSourceInterceptor +++ b/extensions/opentelemetry/runtime/src/main/resources/META-INF/services/io.smallrye.config.ConfigSourceInterceptor @@ -1 +1 @@ -io.quarkus.opentelemetry.runtime.config.runtime.HierarchicalOTelConnectionConfigInterceptor +io.quarkus.opentelemetry.runtime.config.HierarchicalOTelConnectionConfigInterceptor diff --git a/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/config/runtime/HierarchicalOTelConnectionConfigInterceptorTest.java b/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/config/HierarchicalOTelConnectionConfigInterceptorTest.java similarity index 84% rename from extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/config/runtime/HierarchicalOTelConnectionConfigInterceptorTest.java rename to extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/config/HierarchicalOTelConnectionConfigInterceptorTest.java index 09bdcf90a1c13..e509ebb35805a 100644 --- a/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/config/runtime/HierarchicalOTelConnectionConfigInterceptorTest.java +++ b/extensions/opentelemetry/runtime/src/test/java/io/quarkus/opentelemetry/runtime/config/HierarchicalOTelConnectionConfigInterceptorTest.java @@ -1,9 +1,9 @@ -package io.quarkus.opentelemetry.runtime.config.runtime; +package io.quarkus.opentelemetry.runtime.config; -import static io.quarkus.opentelemetry.runtime.config.runtime.HierarchicalOTelConnectionConfigInterceptor.BASE; -import static io.quarkus.opentelemetry.runtime.config.runtime.HierarchicalOTelConnectionConfigInterceptor.METRICS; -import static io.quarkus.opentelemetry.runtime.config.runtime.HierarchicalOTelConnectionConfigInterceptor.MappingFunction; -import static io.quarkus.opentelemetry.runtime.config.runtime.HierarchicalOTelConnectionConfigInterceptor.TRACES; +import static io.quarkus.opentelemetry.runtime.config.HierarchicalOTelConnectionConfigInterceptor.BASE; +import static io.quarkus.opentelemetry.runtime.config.HierarchicalOTelConnectionConfigInterceptor.METRICS; +import static io.quarkus.opentelemetry.runtime.config.HierarchicalOTelConnectionConfigInterceptor.MappingFunction; +import static io.quarkus.opentelemetry.runtime.config.HierarchicalOTelConnectionConfigInterceptor.TRACES; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.HashMap;