Skip to content

Commit cece5ed

Browse files
committed
Micrometer to OTel Bridge
1 parent 7e76c74 commit cece5ed

File tree

43 files changed

+3207
-4
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3207
-4
lines changed

.github/native-tests.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117
{
118118
"category": "Misc4",
119119
"timeout": 130,
120-
"test-modules": "picocli-native, gradle, micrometer-mp-metrics, micrometer-prometheus, logging-json, jaxp, jaxb, observability-lgtm, opentelemetry, opentelemetry-jdbc-instrumentation, opentelemetry-mongodb-client-instrumentation, opentelemetry-redis-instrumentation, web-dependency-locator",
120+
"test-modules": "picocli-native, gradle, micrometer-mp-metrics, micrometer-prometheus, logging-json, jaxp, jaxb, observability-lgtm, opentelemetry, opentelemetry-jdbc-instrumentation, opentelemetry-mongodb-client-instrumentation, opentelemetry-redis-instrumentation, web-dependency-locator, micrometer-opentelemetry",
121121
"os-name": "ubuntu-latest"
122122
},
123123
{
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
////
2+
This guide is maintained in the main Quarkus repository
3+
and pull requests should be submitted there:
4+
https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
5+
////
6+
[id=telemetry-micrometer-opentelemetry]
7+
= Micrometer and OpenTelemetry extension
8+
include::_attributes.adoc[]
9+
:extension-status: preview
10+
:diataxis-type: reference
11+
:categories: observability
12+
:summary: Guide to send Micrometer data to OpenTelemetry.
13+
:topics: observability,opentelemetry,metrics,micrometer,tracing,logs
14+
:extensions: io.quarkus:quarkus-micrometer-opentelemetry
15+
16+
This extension provides support for both `Micrometer` and `OpenTelemetry` in Quarkus applications. It streamlines integration by incorporating both extensions along with a bridge that enables sending Micrometer metrics via OpenTelemetry.
17+
18+
include::{includes}/extension-status.adoc[]
19+
20+
[NOTE]
21+
====
22+
- The xref:telemetry-micrometer.adoc[Micrometer Guide] is available for detailed information about the Micrometer extension.
23+
- The xref:opentelemetry.adoc[OpenTelemetry Guide] provides information about the OpenTelemetry extension.
24+
====
25+
26+
The bridge is more than the simple OTLP registry found in Quarkiverse. In this extension, the OpenTelemetry SDK provides a Micrometer registry implementation.
27+
28+
This allows the normal use of the Micrometer API, but have the metrics handled by the OpenTelemetry extension. All the configurations of the OpenTelemetry extension are available for this bridge and enables forwarding to OpenTelemetry all the automatic instrumentation metrics generated by Micrometer in Quarkus, as well as custom user metrics.
29+
30+
The bridge is based on the https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/micrometer/micrometer-1.5/library[`micrometer/micrometer-1.5`] OpenTelemetry instrumentation library.
31+
32+
== Usage
33+
34+
If you already have your Quarkus project configured, you can add the `quarkus-micrometer-opentelemetry` extension to your project by running the following command in your project base directory:
35+
36+
:add-extension-extensions: micrometer-opentelemetry
37+
include::{includes}/devtools/extension-add.adoc[]
38+
39+
This will add the following to your build file:
40+
41+
[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"]
42+
.pom.xml
43+
----
44+
<dependency>
45+
<groupId>io.quarkus</groupId>
46+
<artifactId>quarkus-micrometer-opentelemetry</artifactId>
47+
</dependency>
48+
----
49+
50+
[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"]
51+
.build.gradle
52+
----
53+
implementation("io.quarkus:quarkus-micrometer-opentelemetry")
54+
----
55+
56+
== Configuration
57+
58+
Micrometer is enabled by default as are OpenTelemetry tracing, metrics and logs.
59+
OpenTelemetry metrics auto-instrumentation for HTTP server and JVM metrics are disabled by default because those metrics are already collected by Micrometer.
60+
61+
Particular automated metrics are not enabled by default and can be enabled by setting the, as an example:
62+
```
63+
quarkus.micrometer.binder.jvm=true
64+
```
65+
on the `application.properties` file.
66+
67+
For this and other properties you can use with the extension, Please refer to:
68+
69+
* xref:telemetry-micrometer.adoc#configuration-reference[Micrometer metrics configurations]
70+
* xref:opentelemetry.adoc#configuration-reference[OpenTelemetry configurations]
71+
72+
73+
74+
== Metric differences between Micrometer and OpenTelemetry
75+
76+
=== API differences
77+
The metrics produced with each framework follow different APIs and the mapping is not 1:1.
78+
79+
One fundamental API difference is that Micrometer uses a https://docs.micrometer.io/micrometer/reference/concepts/timers.html[Timer] and OpenTelemetry uses a https://opentelemetry.io/docs/specs/otel/metrics/data-model/#histogram[Histogram] to record latency (execution time) metrics and the frequency of the events.
80+
81+
When using the `@Timed` annotation with Micrometer, 2 different metrics are https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/324fdbdd452ddffaf2da2c5bf004d8bb3fdfa1dd/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryTimer.java#L31[created on the OpenTelemetry side], one `Gauge` for the `max` value and one `Histogram`.
82+
83+
The `DistributionSummary` from Micrometer is transformed into a `histogram` and a `DoubleGauge` for the `max` value. If slos are set in the `DistributionSummary` an addition histogram is created for them.
84+
85+
This table shows the differences between the two frameworks:
86+
87+
|===
88+
|Micrometer |OpenTelemetry
89+
90+
|DistributionSummary
91+
|`<Metric name>` (Histogram), `<Metric name>.max` (DoubleGauge)
92+
93+
|DistributionSummary with SLOs
94+
|`<Metric name>` (Histogram), `<Metric name>.max` (DoubleGauge), `<Metric name>.histogram` (DoubleGauge)
95+
96+
|LongTaskTimer
97+
|`<Metric name>.active` (ObservableLongUpDownCounter), `<Metric name>.duration` (ObservableDoubleUpDownCounter)
98+
99+
|Timer
100+
|`<Metric name>` (Histogram), `<Metric name>.max` (ObservableDoubleGauge)
101+
|===
102+
103+
104+
=== Semantic convention differences
105+
106+
The 2 frameworks follow different semantic conventions and approaches to the concept. The OpenTelemetry metrics are based on the https://opentelemetry.io/docs/concepts/semantic-conventions/[`OpenTelemetry Semantic Conventions`] and are still under active development. Micrometer metrics convention format is around for a long time and has not changed much.
107+
108+
When you set these 2 configurations are set in the `application.properties` file:
109+
110+
```
111+
quarkus.micrometer.binder.jvm=true
112+
quarkus.micrometer.binder.http-server.enabled=true
113+
114+
```
115+
The JVM and HTTP server metrics are collected by Micrometer.
116+
117+
Next, are examples of the metrics collected by Micrometer and a comparison of what would be the `quarkus-micrometer-registry-prometheus` output vs the one on this bridge. A link to the equivalent OpenTelemetry Semantic Convention is also provided for reference and is not currently used in the bridge.
118+
119+
|===
120+
|Micrometer Meter |Quarkus Micrometer Prometheus output | This bridge OpenTelemetry output name | Related OpenTelemetry Semantic Convention (not applied)
121+
122+
|Using the @Timed interceptor.
123+
|
124+
|method.timed (Histogram), method.timed.max (DoubleGauge)
125+
|NA
126+
127+
|Using the @Counted interceptor.
128+
|
129+
|method.counted (DoubleSum)
130+
|NA
131+
132+
|`http.server.active.requests` (Gauge)
133+
|`http_server_active_requests` (Gauge)
134+
|`http.server.active.requests` (DoubleGauge)
135+
|https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpserveractive_requests[`http.server.active_requests`] (UpDownCounter)
136+
137+
|`http.server.requests` (Timer)
138+
|`http_server_requests_seconds_count`, `http_server_requests_seconds_sum`, `http_server_requests_seconds_max` (Gauge)
139+
|`http.server.requests` (Histogram), `http.server.requests.max` (DoubleGauge)
140+
|https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpserverrequestduration[`http.server.request.duration`] (Histogram)
141+
142+
|`http.server.bytes.read` (DistributionSummary)
143+
|`http_server_bytes_read_count`, `http_server_bytes_read_sum` , `http_server_bytes_read_max` (Gauge)
144+
|`http.server.bytes.read` (Histogram), `http.server.bytes.read.max` (DoubleGauge)
145+
|https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpserverrequestbodysize[`http.server.request.body.size`] (Histogram)
146+
147+
|`http.server.bytes.write` (DistributionSummary)
148+
|`http_server_bytes_write_count`, `http_server_bytes_write_sum` , `http_server_bytes_write_max` (Gauge)
149+
|`http.server.bytes.write` (Histogram), `http.server.bytes.write.max` (DoubleGauge)
150+
|https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpserverresponsebodysize[`http.server.response.body.size`] (Histogram)
151+
152+
|`http.server.connections` (LongTaskTimer)
153+
|`http_server_connections_seconds_active_count`, `http_server_connections_seconds_duration_sum` `http_server_connections_seconds_max` (Gauge)
154+
|`http.server.connections.active` (LongSum), `http.server.connections.duration` (DoubleGauge)
155+
| N/A
156+
157+
|`jvm.threads.live` (Gauge)
158+
|`jvm_threads_live_threads` (Gauge)
159+
|`jvm.threads.live` (DoubleGauge)
160+
|https://opentelemetry.io/docs/specs/semconv/runtime/jvm-metrics/#metric-jvmthreadcount[`jvm.threads.live`] (UpDownCounter)
161+
162+
|`jvm.threads.started` (FunctionCounter)
163+
|`jvm_threads_started_threads_total` (Counter)
164+
|`jvm.threads.started` (DoubleSum)
165+
|https://opentelemetry.io/docs/specs/semconv/runtime/jvm-metrics/#metric-jvmthreadcount[`jvm.threads.live`] (UpDownCounter)
166+
167+
|`jvm.threads.daemon` (Gauge)
168+
|`jvm_threads_daemon_threads` (Gauge)
169+
|`jvm.threads.daemon` (DoubleGauge)
170+
|https://opentelemetry.io/docs/specs/semconv/runtime/jvm-metrics/#metric-jvmthreadcount[`jvm.threads.live`] (UpDownCounter)
171+
172+
|`jvm.threads.peak` (Gauge)
173+
|`jvm_threads_peak_threads` (Gauge)
174+
|`jvm.threads.peak` (DoubleGauge)
175+
|N/A
176+
177+
|`jvm.threads.states` (Gauge per state)
178+
|`jvm_threads_states_threads` (Gauge)
179+
|`jvm.threads.states` (DoubleGauge)
180+
|https://opentelemetry.io/docs/specs/semconv/runtime/jvm-metrics/#metric-jvmthreadcount[`jvm.threads.live`] (UpDownCounter)
181+
|===
182+
183+
184+
[NOTE]
185+
====
186+
- Some metrics might be absent of the output if they contain no data.
187+
====
188+
189+
== See the output
190+
191+
=== Grafana-OTel-LGTM Dev Service
192+
You can use the xref:observability-devservices-lgtm.adoc[Grafana-OTel-LGTM] devservice.
193+
194+
This Dev service includes a Grafana for visualizing data, Loki to store logs, Tempo to store traces and Prometheus to store metrics.
195+
Also provides and OTel collector to receive the data.
196+
197+
=== Logging exporter
198+
199+
You can output all metrics to the console by setting the exporter to `logging` in the `application.properties` file:
200+
[source, properties]
201+
----
202+
quarkus.otel.metrics.exporter=logging <1>
203+
quarkus.otel.metric.export.interval=10000ms <2>
204+
----
205+
206+
<1> Set the exporter to `logging`.
207+
Normally you don't need to set this.
208+
The default is `cdi`.
209+
<2> Set the interval to export the metrics.
210+
The default is `1m`, which is too long for debugging.
211+
212+
Also add this dependency to your project:
213+
[source,xml]
214+
----
215+
<dependency>
216+
<groupId>io.opentelemetry</groupId>
217+
<artifactId>opentelemetry-exporter-logging</artifactId>
218+
</dependency>
219+
----
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>io.quarkus</groupId>
9+
<artifactId>quarkus-micrometer-opentelemetry-parent</artifactId>
10+
<version>999-SNAPSHOT</version>
11+
<relativePath>../pom.xml</relativePath>
12+
</parent>
13+
14+
<artifactId>quarkus-micrometer-opentelemetry-deployment</artifactId>
15+
<name>Quarkus - Micrometer to OpenTelemetry Bridge - Deployment</name>
16+
<description>Micrometer registry implemented by the OpenTelemetry SDK</description>
17+
18+
<dependencies>
19+
20+
<dependency>
21+
<groupId>io.quarkus</groupId>
22+
<artifactId>quarkus-micrometer-opentelemetry</artifactId>
23+
<version>${project.version}</version>
24+
</dependency>
25+
26+
<dependency>
27+
<groupId>io.quarkus</groupId>
28+
<artifactId>quarkus-micrometer-deployment</artifactId>
29+
</dependency>
30+
31+
<dependency>
32+
<groupId>io.quarkus</groupId>
33+
<artifactId>quarkus-opentelemetry-deployment</artifactId>
34+
</dependency>
35+
36+
<!--TESTS-->
37+
<dependency>
38+
<groupId>io.quarkus</groupId>
39+
<artifactId>quarkus-junit5-internal</artifactId>
40+
<scope>test</scope>
41+
</dependency>
42+
43+
<dependency>
44+
<groupId>io.quarkus</groupId>
45+
<artifactId>quarkus-junit5</artifactId>
46+
<scope>test</scope>
47+
</dependency>
48+
49+
<dependency>
50+
<groupId>io.rest-assured</groupId>
51+
<artifactId>rest-assured</artifactId>
52+
<scope>test</scope>
53+
</dependency>
54+
55+
<dependency>
56+
<groupId>org.awaitility</groupId>
57+
<artifactId>awaitility</artifactId>
58+
<scope>test</scope>
59+
</dependency>
60+
61+
<dependency>
62+
<groupId>org.assertj</groupId>
63+
<artifactId>assertj-core</artifactId>
64+
<scope>test</scope>
65+
</dependency>
66+
67+
<dependency>
68+
<groupId>io.opentelemetry</groupId>
69+
<artifactId>opentelemetry-sdk-testing</artifactId>
70+
<scope>test</scope>
71+
</dependency>
72+
73+
<dependency>
74+
<groupId>io.smallrye.reactive</groupId>
75+
<artifactId>smallrye-mutiny-vertx-web-client</artifactId>
76+
<scope>test</scope>
77+
</dependency>
78+
79+
<dependency>
80+
<groupId>io.quarkus</groupId>
81+
<artifactId>quarkus-rest-client-deployment</artifactId>
82+
<scope>test</scope>
83+
</dependency>
84+
85+
<dependency>
86+
<groupId>io.quarkus</groupId>
87+
<artifactId>quarkus-rest-jackson-deployment</artifactId>
88+
<scope>test</scope>
89+
</dependency>
90+
91+
<dependency>
92+
<groupId>io.quarkus</groupId>
93+
<artifactId>quarkus-vertx-http-deployment</artifactId>
94+
<scope>test</scope>
95+
</dependency>
96+
97+
<dependency>
98+
<groupId>io.quarkus</groupId>
99+
<artifactId>quarkus-reactive-routes-deployment</artifactId>
100+
<scope>test</scope>
101+
</dependency>
102+
103+
</dependencies>
104+
<build>
105+
<plugins>
106+
<plugin>
107+
<artifactId>maven-surefire-plugin</artifactId>
108+
<configuration>
109+
<systemPropertyVariables>
110+
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
111+
<quarkus.log.level>INFO</quarkus.log.level>
112+
</systemPropertyVariables>
113+
</configuration>
114+
</plugin>
115+
<plugin>
116+
<artifactId>maven-compiler-plugin</artifactId>
117+
<executions>
118+
<execution>
119+
<id>default-compile</id>
120+
<configuration>
121+
<annotationProcessorPaths>
122+
<path>
123+
<groupId>io.quarkus</groupId>
124+
<artifactId>quarkus-extension-processor</artifactId>
125+
<version>${project.version}</version>
126+
</path>
127+
</annotationProcessorPaths>
128+
</configuration>
129+
</execution>
130+
</executions>
131+
</plugin>
132+
</plugins>
133+
</build>
134+
</project>

0 commit comments

Comments
 (0)