Skip to content

Commit

Permalink
Docs
Browse files Browse the repository at this point in the history
  • Loading branch information
brunobat committed Jan 9, 2025
1 parent fc4ee8a commit 73b8d37
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 2 deletions.
110 changes: 109 additions & 1 deletion docs/src/main/asciidoc/telemetry-micrometer-to-opentelemetry.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ This extension provides support for both `Micrometer` and `OpenTelemetry` in Qua
- The xref:opentelemetry.adoc[OpenTelemetry Guide] provides information about the OpenTelemetry extension.
====

The bridge is much more than the simple OTLP registry found in Quarkiverse. In this extension, the OpenTelemetry SDK provides a Micrometer registry implementation.
The bridge is more than the simple OTLP registry found in Quarkiverse. In this extension, the OpenTelemetry SDK provides a Micrometer registry implementation.

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.

The bridge enables to forward to OpenTelemetry all the automatic instrumentation metrics generated by Micrometer in Quarkus, as well as custom user metrics.

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.

== Usage

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:
Expand All @@ -50,4 +52,110 @@ This will add the following to your build file:
implementation("io.quarkus:quarkus-micrometer-opentelemetry")
----

== Metric differences between Micrometer and OpenTelemetry

=== API differences
The metrics produced with each framework follow different APIs and the mapping is not 1:1.

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.

When using the `Timed` 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`.

The `DistributionSummary` from Micrometer is transformed into a `histogram` represented by a `DoubleGauge' with data points matching the buckets, another `DoubleGauge` for the `max` value and finally an actually OpenTelemetry `Histogram`. There is data duplication that might be optimized in the future.

|===
|Micrometer |OpenTelemetry

|DistributionSummary
|`<Metric name>` (Histogram), `<Metric name>.max` (DoubleGauge)

|DistributionSummary with SLOs
|`<Metric name>` (Histogram), `<Metric name>.max` (DoubleGauge), `<Metric name>.histogram` (DoubleGauge)

|LongTaskTimer
|`<Metric name>.active` (ObservableLongUpDownCounter), `<Metric name>.duration` (ObservableDoubleUpDownCounter)

|Timer
|`<Metric name>` (Histogram), `<Metric name>.max` (ObservableDoubleGauge)
|===



=== Semantic convention differences

The following table shows some differences between the two frameworks. This list is not exhaustive and only shows some examples, for reference.

When `quarkus.micrometer.binder.jvm=true` is set, the JVM metrics are collected by Micrometer. Here we show a subset related with `Threads`.


|===
|Micrometer Meter |Quarkus Micrometer Prometheus output | This bridge OpenTelemetry output name | Related OpenTelemetry Semantic Convention (not applied)

|Using the @Timed interceptor.
|
|method.timed (Histogram), method.timed.max (DoubleGauge)
|NA

|Using the @Counted interceptor.
|
|method.counted (DoubleSum)
|NA

|`http.server.active.requests` (Gauge)
|`http_server_active_requests` (Gauge)
|`http.server.active.requests` (DoubleGauge)
|https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpserveractive_requests[`http.server.active_requests`] (UpDownCounter)

|`http.server.requests` (Timer)
|`http_server_requests_seconds_count`, `http_server_requests_seconds_sum`, `http_server_requests_seconds_max` (Gauge)
|`http.server.requests` (Histogram), `http.server.requests.max` (DoubleGauge)
|https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpserverrequestduration[`http.server.request.duration`] (Histogram)

|`http.server.bytes.read` (DistributionSummary)
|`http_server_bytes_read_count`, `http_server_bytes_read_sum` , `http_server_bytes_read_max` (Gauge)
|`http.server.bytes.read` (Histogram), `http.server.bytes.read.max` (DoubleGauge)
|https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpserverrequestbodysize[`http.server.request.body.size`] (Histogram)

|`http.server.bytes.write` (DistributionSummary)
|`http_server_bytes_write_count`, `http_server_bytes_write_sum` , `http_server_bytes_write_max` (Gauge)
|`http.server.bytes.write` (Histogram), `http.server.bytes.write.max` (DoubleGauge)
|https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpserverresponsebodysize[`http.server.response.body.size`] (Histogram)

|`http.server.connections` (LongTaskTimer)
|`http_server_connections_seconds_active_count`, `http_server_connections_seconds_duration_sum` `http_server_connections_seconds_max` (Gauge)
|`http.server.connections.active` (LongSum), `http.server.connections.duration` (DoubleGauge)
| N/A

|`jvm.threads.live` (Gauge)
|`jvm_threads_live_threads` (Gauge)
|`jvm.threads.live` (DoubleGauge)
|https://opentelemetry.io/docs/specs/semconv/runtime/jvm-metrics/#metric-jvmthreadcount[`jvm.threads.live`] (UpDownCounter)

|`jvm.threads.started` (FunctionCounter)
|`jvm_threads_started_threads_total` (Counter)
|`jvm.threads.started` (DoubleSum)
|https://opentelemetry.io/docs/specs/semconv/runtime/jvm-metrics/#metric-jvmthreadcount[`jvm.threads.live`] (UpDownCounter)

|`jvm.threads.daemon` (Gauge)
|`jvm_threads_daemon_threads` (Gauge)
|`jvm.threads.daemon` (DoubleGauge)
|https://opentelemetry.io/docs/specs/semconv/runtime/jvm-metrics/#metric-jvmthreadcount[`jvm.threads.live`] (UpDownCounter)

|`jvm.threads.peak` (Gauge)
|`jvm_threads_peak_threads` (Gauge)
|`jvm.threads.peak` (DoubleGauge)
|N/A

|`jvm.threads.states` (Gauge per state)
|`jvm_threads_states_threads` (Gauge)
|`jvm.threads.states` (DoubleGauge)
|https://opentelemetry.io/docs/specs/semconv/runtime/jvm-metrics/#metric-jvmthreadcount[`jvm.threads.live`] (UpDownCounter)
|===


[NOTE]
====
- Some metrics might be absent of the output if they contain no data.
====

== See output
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void histogramTest() {
.hasValue(500)
.hasAttributes(attributeEntry("tag", "value"))));

MetricData testSummaryHistogram = exporter.getFinishedMetricItem("testSummary.histogram");
MetricData testSummaryHistogram = exporter.getFinishedMetricItem("testSummary.histogram"); // present when SLOs are set
assertNotNull(testSummaryHistogram);
assertThat(testSummaryHistogram)
.hasDoubleGaugeSatisfying(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Don't instrument with OTel
quarkus.otel.instrument.http-server-metrics=false
quarkus.otel.instrument.jvm-metrics=false

0 comments on commit 73b8d37

Please sign in to comment.