Skip to content

Commit f02d1ad

Browse files
authored
Merge pull request #44016 from brunobat/micrometer-exemplars-on-http
Micrometer exemplars on HTTP
2 parents 173e489 + fffb6cb commit f02d1ad

File tree

14 files changed

+213
-13
lines changed

14 files changed

+213
-13
lines changed

extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/MicrometerProcessor.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import io.quarkus.micrometer.runtime.MicrometerRecorder;
5959
import io.quarkus.micrometer.runtime.MicrometerTimedInterceptor;
6060
import io.quarkus.micrometer.runtime.config.MicrometerConfig;
61+
import io.quarkus.micrometer.runtime.export.exemplars.NoopOpenTelemetryExemplarContextUnwrapper;
6162
import io.quarkus.runtime.RuntimeValue;
6263
import io.quarkus.runtime.metrics.MetricsFactory;
6364
import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem;
@@ -93,6 +94,15 @@ MetricsCapabilityBuildItem metricsCapabilityBuildItem() {
9394
null);
9495
}
9596

97+
@BuildStep(onlyIfNot = PrometheusRegistryProcessor.PrometheusEnabled.class)
98+
void registerEmptyExamplarProvider(
99+
BuildProducer<AdditionalBeanBuildItem> additionalBeans) {
100+
additionalBeans.produce(AdditionalBeanBuildItem.builder()
101+
.addBeanClass(NoopOpenTelemetryExemplarContextUnwrapper.class)
102+
.setUnremovable()
103+
.build());
104+
}
105+
96106
@BuildStep(onlyIf = { PrometheusRegistryProcessor.PrometheusEnabled.class })
97107
MetricsCapabilityBuildItem metricsCapabilityPrometheusBuildItem(
98108
NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem) {

extensions/micrometer/deployment/src/main/java/io/quarkus/micrometer/deployment/export/PrometheusRegistryProcessor.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
import io.quarkus.micrometer.runtime.MicrometerRecorder;
1717
import io.quarkus.micrometer.runtime.config.MicrometerConfig;
1818
import io.quarkus.micrometer.runtime.config.PrometheusConfigGroup;
19-
import io.quarkus.micrometer.runtime.export.EmptyExemplarSamplerProvider;
20-
import io.quarkus.micrometer.runtime.export.OpentelemetryExemplarSamplerProvider;
2119
import io.quarkus.micrometer.runtime.export.PrometheusRecorder;
20+
import io.quarkus.micrometer.runtime.export.exemplars.EmptyExemplarSamplerProvider;
21+
import io.quarkus.micrometer.runtime.export.exemplars.NoopOpenTelemetryExemplarContextUnwrapper;
22+
import io.quarkus.micrometer.runtime.export.exemplars.OpenTelemetryExemplarContextUnwrapper;
23+
import io.quarkus.micrometer.runtime.export.exemplars.OpentelemetryExemplarSamplerProvider;
2224
import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem;
2325
import io.quarkus.vertx.http.deployment.RouteBuildItem;
2426
import io.quarkus.vertx.http.runtime.management.ManagementInterfaceBuildTimeConfig;
@@ -73,6 +75,7 @@ void registerOpentelemetryExemplarSamplerProvider(
7375
BuildProducer<AdditionalBeanBuildItem> additionalBeans) {
7476
additionalBeans.produce(AdditionalBeanBuildItem.builder()
7577
.addBeanClass(OpentelemetryExemplarSamplerProvider.class)
78+
.addBeanClass(OpenTelemetryExemplarContextUnwrapper.class)
7679
.setUnremovable()
7780
.build());
7881
}
@@ -82,6 +85,7 @@ void registerEmptyExamplarProvider(
8285
BuildProducer<AdditionalBeanBuildItem> additionalBeans) {
8386
additionalBeans.produce(AdditionalBeanBuildItem.builder()
8487
.addBeanClass(EmptyExemplarSamplerProvider.class)
88+
.addBeanClass(NoopOpenTelemetryExemplarContextUnwrapper.class)
8589
.setUnremovable()
8690
.build());
8791
}

extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/vertx/VertxHttpServerMetrics.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io.quarkus.micrometer.runtime.HttpServerMetricsTagsContributor;
2121
import io.quarkus.micrometer.runtime.binder.HttpBinderConfiguration;
2222
import io.quarkus.micrometer.runtime.binder.HttpCommonTags;
23+
import io.quarkus.micrometer.runtime.export.exemplars.OpenTelemetryContextUnwrapper;
2324
import io.vertx.core.http.HttpMethod;
2425
import io.vertx.core.http.HttpServerRequest;
2526
import io.vertx.core.http.ServerWebSocket;
@@ -40,6 +41,7 @@ public class VertxHttpServerMetrics extends VertxTcpServerMetrics
4041
static final Logger log = Logger.getLogger(VertxHttpServerMetrics.class);
4142

4243
HttpBinderConfiguration config;
44+
OpenTelemetryContextUnwrapper openTelemetryContextUnwrapper;
4345

4446
final LongAdder activeRequests;
4547

@@ -49,9 +51,12 @@ public class VertxHttpServerMetrics extends VertxTcpServerMetrics
4951

5052
private final List<HttpServerMetricsTagsContributor> httpServerMetricsTagsContributors;
5153

52-
VertxHttpServerMetrics(MeterRegistry registry, HttpBinderConfiguration config) {
54+
VertxHttpServerMetrics(MeterRegistry registry,
55+
HttpBinderConfiguration config,
56+
OpenTelemetryContextUnwrapper openTelemetryContextUnwrapper) {
5357
super(registry, "http.server", null);
5458
this.config = config;
59+
this.openTelemetryContextUnwrapper = openTelemetryContextUnwrapper;
5560

5661
activeRequests = new LongAdder();
5762
Gauge.builder(config.getHttpServerActiveRequestsName(), activeRequests, LongAdder::doubleValue)
@@ -164,12 +169,14 @@ public void requestReset(HttpRequestMetric requestMetric) {
164169
if (path != null) {
165170
Timer.Sample sample = requestMetric.getSample();
166171

167-
sample.stop(requestsTimer
168-
.withTags(Tags.of(
172+
openTelemetryContextUnwrapper.executeInContext(
173+
sample::stop,
174+
requestsTimer.withTags(Tags.of(
169175
VertxMetricsTags.method(requestMetric.request().method()),
170176
HttpCommonTags.uri(path, requestMetric.initialPath, 0),
171177
Outcome.CLIENT_ERROR.asTag(),
172-
HttpCommonTags.STATUS_RESET)));
178+
HttpCommonTags.STATUS_RESET)),
179+
requestMetric.request().context());
173180
}
174181
requestMetric.requestEnded();
175182
}
@@ -207,7 +214,10 @@ public void responseEnd(HttpRequestMetric requestMetric, HttpResponse response,
207214
}
208215
}
209216

210-
sample.stop(requestsTimer.withTags(allTags));
217+
openTelemetryContextUnwrapper.executeInContext(
218+
sample::stop,
219+
requestsTimer.withTags(allTags),
220+
requestMetric.request().context());
211221
}
212222
requestMetric.requestEnded();
213223
}

extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/vertx/VertxMeterBinderAdapter.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.micrometer.core.instrument.Tag;
1212
import io.micrometer.core.instrument.Tags;
1313
import io.quarkus.micrometer.runtime.binder.HttpBinderConfiguration;
14+
import io.quarkus.micrometer.runtime.export.exemplars.OpenTelemetryContextUnwrapper;
1415
import io.quarkus.vertx.http.runtime.ExtendedQuarkusVertxHttpMetrics;
1516
import io.vertx.core.VertxOptions;
1617
import io.vertx.core.datagram.DatagramSocketOptions;
@@ -37,11 +38,14 @@ public class VertxMeterBinderAdapter extends MetricsOptions
3738
public static final String METRIC_NAME_SEPARATOR = "|";
3839

3940
private HttpBinderConfiguration httpBinderConfiguration;
41+
private OpenTelemetryContextUnwrapper openTelemetryContextUnwrapper;
4042

4143
public VertxMeterBinderAdapter() {
4244
}
4345

44-
void setHttpConfig(HttpBinderConfiguration httpBinderConfiguration) {
46+
void initBinder(HttpBinderConfiguration httpBinderConfiguration,
47+
OpenTelemetryContextUnwrapper openTelemetryContextUnwrapper) {
48+
this.openTelemetryContextUnwrapper = openTelemetryContextUnwrapper;
4549
this.httpBinderConfiguration = httpBinderConfiguration;
4650
}
4751

@@ -70,9 +74,12 @@ public MetricsOptions newOptions() {
7074
if (httpBinderConfiguration == null) {
7175
throw new NoStackTraceException("HttpBinderConfiguration was not found");
7276
}
77+
if (openTelemetryContextUnwrapper == null) {
78+
throw new NoStackTraceException("OpenTelemetryContextUnwrapper was not found");
79+
}
7380
if (httpBinderConfiguration.isServerEnabled()) {
7481
log.debugf("Create HttpServerMetrics with options %s and address %s", options, localAddress);
75-
return new VertxHttpServerMetrics(Metrics.globalRegistry, httpBinderConfiguration);
82+
return new VertxHttpServerMetrics(Metrics.globalRegistry, httpBinderConfiguration, openTelemetryContextUnwrapper);
7683
}
7784
return null;
7885
}

extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/vertx/VertxMeterBinderRecorder.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import io.quarkus.arc.Arc;
88
import io.quarkus.micrometer.runtime.binder.HttpBinderConfiguration;
9+
import io.quarkus.micrometer.runtime.export.exemplars.OpenTelemetryContextUnwrapper;
910
import io.quarkus.runtime.LaunchMode;
1011
import io.quarkus.runtime.annotations.Recorder;
1112
import io.vertx.core.VertxOptions;
@@ -30,18 +31,20 @@ public void accept(VertxOptions vertxOptions) {
3031
/* RUNTIME_INIT */
3132
public void configureBinderAdapter() {
3233
HttpBinderConfiguration httpConfig = Arc.container().instance(HttpBinderConfiguration.class).get();
34+
OpenTelemetryContextUnwrapper openTelemetryContextUnwrapper = Arc.container()
35+
.instance(OpenTelemetryContextUnwrapper.class).get();
3336
if (LaunchMode.current() == LaunchMode.DEVELOPMENT) {
3437
if (devModeConfig == null) {
3538
// Create an object whose attributes we can update
3639
devModeConfig = httpConfig.unwrap();
37-
binderAdapter.setHttpConfig(devModeConfig);
40+
binderAdapter.initBinder(devModeConfig, openTelemetryContextUnwrapper);
3841
} else {
3942
// update config attributes
4043
devModeConfig.update(httpConfig);
4144
}
4245
} else {
4346
// unwrap the CDI bean (use POJO)
44-
binderAdapter.setHttpConfig(httpConfig.unwrap());
47+
binderAdapter.initBinder(httpConfig.unwrap(), openTelemetryContextUnwrapper);
4548
}
4649
}
4750
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.quarkus.micrometer.runtime.export;
1+
package io.quarkus.micrometer.runtime.export.exemplars;
22

33
import java.util.Optional;
44

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.quarkus.micrometer.runtime.export.exemplars;
2+
3+
import java.util.function.Function;
4+
5+
import jakarta.enterprise.context.Dependent;
6+
7+
import io.vertx.core.Context;
8+
9+
@Dependent
10+
public class NoopOpenTelemetryExemplarContextUnwrapper implements OpenTelemetryContextUnwrapper {
11+
12+
@Override
13+
public <P, R> R executeInContext(Function<P, R> methodReference, P parameter, Context requestContext) {
14+
return methodReference.apply(parameter);// pass through
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.quarkus.micrometer.runtime.export.exemplars;
2+
3+
import java.util.function.Function;
4+
5+
public interface OpenTelemetryContextUnwrapper {
6+
/**
7+
* Called when an HTTP server response has ended.
8+
* Makes sure exemplars are produced because they have an OTel context.
9+
*
10+
* @param methodReference Ex: Sample stop method reference
11+
* @param parameter The parameter to pass to the method
12+
* @param requestContext The request context
13+
* @param <P> The parameter type is a type of metric, ex: Timer
14+
* @param <R> The return type of the method pointed by the methodReference
15+
* @return The result of the method
16+
*/
17+
<P, R> R executeInContext(Function<P, R> methodReference, P parameter, io.vertx.core.Context requestContext);
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package io.quarkus.micrometer.runtime.export.exemplars;
2+
3+
import java.util.function.Function;
4+
5+
import jakarta.enterprise.context.Dependent;
6+
7+
import io.opentelemetry.context.Context;
8+
import io.opentelemetry.context.Scope;
9+
import io.quarkus.opentelemetry.runtime.QuarkusContextStorage;
10+
11+
@Dependent
12+
public class OpenTelemetryExemplarContextUnwrapper implements OpenTelemetryContextUnwrapper {
13+
14+
@Override
15+
public <P, R> R executeInContext(Function<P, R> methodReference, P parameter, io.vertx.core.Context requestContext) {
16+
if (requestContext == null) {
17+
return methodReference.apply(parameter);
18+
}
19+
20+
Context newContext = QuarkusContextStorage.getContext(requestContext);
21+
22+
if (newContext == null) {
23+
return methodReference.apply(parameter);
24+
}
25+
26+
io.opentelemetry.context.Context oldContext = QuarkusContextStorage.INSTANCE.current();
27+
try (Scope scope = QuarkusContextStorage.INSTANCE.attach(newContext)) {
28+
return methodReference.apply(parameter);
29+
}
30+
}
31+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.quarkus.micrometer.runtime.export;
1+
package io.quarkus.micrometer.runtime.export.exemplars;
22

33
import java.util.Optional;
44
import java.util.function.Function;

0 commit comments

Comments
 (0)