Skip to content

Commit 28df718

Browse files
brunobatgsmet
authored andcommitted
Minimal OTel
(cherry picked from commit d2b8866)
1 parent 592df03 commit 28df718

File tree

11 files changed

+353
-47
lines changed

11 files changed

+353
-47
lines changed

extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/tracing/instrumentation/InstrumentationProcessor.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ public boolean getAsBoolean() {
6868
}
6969
}
7070

71+
static class VertxHttpAvailable implements BooleanSupplier {
72+
private static final boolean IS_VERTX_HTTP_AVAILABLE = isClassPresentAtRuntime(
73+
"io.quarkus.vertx.http.runtime.VertxHttpRecorder");
74+
75+
@Override
76+
public boolean getAsBoolean() {
77+
return IS_VERTX_HTTP_AVAILABLE;
78+
}
79+
}
80+
7181
@BuildStep(onlyIf = GrpcExtensionAvailable.class)
7282
void grpcTracers(BuildProducer<AdditionalBeanBuildItem> additionalBeans, OTelBuildConfig config) {
7383
if (config.instrument().grpc()) {
@@ -100,10 +110,16 @@ void registerReactiveMessagingMessageDecorator(
100110
}
101111
}
102112

103-
@BuildStep(onlyIfNot = MetricsExtensionAvailable.class)
113+
@BuildStep(onlyIfNot = MetricsExtensionAvailable.class, onlyIf = VertxHttpAvailable.class)
114+
@Record(ExecutionTime.STATIC_INIT)
115+
VertxOptionsConsumerBuildItem vertxHttpMetricsOptions(InstrumentationRecorder recorder) {
116+
return new VertxOptionsConsumerBuildItem(recorder.getVertxHttpMetricsOptions(), LIBRARY_AFTER + 1);
117+
}
118+
119+
@BuildStep(onlyIfNot = { MetricsExtensionAvailable.class, VertxHttpAvailable.class })
104120
@Record(ExecutionTime.STATIC_INIT)
105-
VertxOptionsConsumerBuildItem vertxTracingMetricsOptions(InstrumentationRecorder recorder) {
106-
return new VertxOptionsConsumerBuildItem(recorder.getVertxTracingMetricsOptions(), LIBRARY_AFTER + 1);
121+
VertxOptionsConsumerBuildItem vertxMetricsOptions(InstrumentationRecorder recorder) {
122+
return new VertxOptionsConsumerBuildItem(recorder.getVertxMetricsOptions(), LIBRARY_AFTER + 1);
107123
}
108124

109125
@BuildStep

extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/tracing/intrumentation/InstrumentationRecorder.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.EventBusInstrumenterVertxTracer;
1111
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.HttpInstrumenterVertxTracer;
1212
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.InstrumenterVertxTracer;
13+
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxHttpMetricsFactory;
1314
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxMetricsFactory;
1415
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxTracer;
1516
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxTracingFactory;
@@ -73,7 +74,15 @@ public void setupVertxTracer(BeanContainer beanContainer, boolean sqlClientAvail
7374
}
7475

7576
/* STATIC INIT */
76-
public Consumer<VertxOptions> getVertxTracingMetricsOptions() {
77+
public Consumer<VertxOptions> getVertxHttpMetricsOptions() {
78+
MetricsOptions metricsOptions = new MetricsOptions()
79+
.setEnabled(true)
80+
.setFactory(new OpenTelemetryVertxHttpMetricsFactory());
81+
return vertxOptions -> vertxOptions.setMetricsOptions(metricsOptions);
82+
}
83+
84+
/* STATIC INIT */
85+
public Consumer<VertxOptions> getVertxMetricsOptions() {
7786
MetricsOptions metricsOptions = new MetricsOptions()
7887
.setEnabled(true)
7988
.setFactory(new OpenTelemetryVertxMetricsFactory());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx;
2+
3+
import java.util.Optional;
4+
5+
import io.vertx.core.Context;
6+
import io.vertx.core.http.impl.HttpServerRequestInternal;
7+
import io.vertx.core.spi.observability.HttpRequest;
8+
9+
public final class MetricRequest {
10+
private final HttpRequest request;
11+
12+
MetricRequest(final HttpRequest request) {
13+
this.request = request;
14+
}
15+
16+
Optional<Context> getContext() {
17+
if (request instanceof HttpServerRequestInternal) {
18+
return Optional.of(((HttpServerRequestInternal) request).context());
19+
} else {
20+
return Optional.empty();
21+
}
22+
}
23+
24+
static MetricRequest request(final HttpRequest httpRequest) {
25+
return new MetricRequest(httpRequest);
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx;
2+
3+
import io.quarkus.vertx.http.runtime.ExtendedQuarkusVertxHttpMetrics;
4+
import io.vertx.core.VertxOptions;
5+
import io.vertx.core.http.HttpServerOptions;
6+
import io.vertx.core.net.SocketAddress;
7+
import io.vertx.core.spi.VertxMetricsFactory;
8+
import io.vertx.core.spi.metrics.HttpServerMetrics;
9+
import io.vertx.core.spi.metrics.VertxMetrics;
10+
import io.vertx.core.spi.observability.HttpRequest;
11+
12+
/**
13+
* This is used to retrieve the route name from Vert.x. This is useful for OpenTelemetry to generate the Span name and
14+
* <code>http.route</code> attribute. Right now, there is no other way to retrieve the route name from Vert.x using the
15+
* Telemetry SPI, so we need to rely on the Metrics SPI.
16+
* <p>
17+
* Right now, it is not possible to register multiple <code>VertxMetrics</code>, meaning that only a single one is
18+
* available per Quarkus instance. To avoid clashing with other extensions that provide Metrics data (like the
19+
* Micrometer extension), we only register the {@link OpenTelemetryVertxHttpMetricsFactory} if the
20+
* <code>VertxHttpServerMetrics</code> is not available in the runtime.
21+
*/
22+
public class OpenTelemetryVertxHttpMetricsFactory implements VertxMetricsFactory {
23+
@Override
24+
public VertxMetrics metrics(final VertxOptions options) {
25+
return new OpenTelemetryVertxHttpServerMetrics();
26+
}
27+
28+
public static class OpenTelemetryVertxHttpServerMetrics
29+
implements HttpServerMetrics<MetricRequest, Object, Object>,
30+
VertxMetrics, ExtendedQuarkusVertxHttpMetrics {
31+
32+
@Override
33+
public HttpServerMetrics<?, ?, ?> createHttpServerMetrics(final HttpServerOptions options,
34+
final SocketAddress localAddress) {
35+
return this;
36+
}
37+
38+
@Override
39+
public MetricRequest requestBegin(final Object socketMetric, final HttpRequest request) {
40+
return MetricRequest.request(request);
41+
}
42+
43+
@Override
44+
public void requestRouted(final MetricRequest requestMetric, final String route) {
45+
if (route != null) {
46+
requestMetric.getContext().ifPresent(context -> context.putLocal("VertxRoute", route));
47+
}
48+
}
49+
50+
@Override
51+
public ConnectionTracker getHttpConnectionTracker() {
52+
// To be implemented if we decide to instrument with OpenTelemetry. See VertxMeterBinderAdapter for an example.
53+
return ExtendedQuarkusVertxHttpMetrics.NOOP_CONNECTION_TRACKER;
54+
}
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
package io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx;
22

3-
import java.util.Optional;
4-
5-
import io.quarkus.vertx.http.runtime.ExtendedQuarkusVertxHttpMetrics;
6-
import io.vertx.core.Context;
73
import io.vertx.core.VertxOptions;
84
import io.vertx.core.http.HttpServerOptions;
9-
import io.vertx.core.http.impl.HttpServerRequestInternal;
105
import io.vertx.core.net.SocketAddress;
116
import io.vertx.core.spi.VertxMetricsFactory;
127
import io.vertx.core.spi.metrics.HttpServerMetrics;
@@ -17,7 +12,7 @@
1712
* This is used to retrieve the route name from Vert.x. This is useful for OpenTelemetry to generate the Span name and
1813
* <code>http.route</code> attribute. Right now, there is no other way to retrieve the route name from Vert.x using the
1914
* Telemetry SPI, so we need to rely on the Metrics SPI.
20-
* <p>
15+
*
2116
* Right now, it is not possible to register multiple <code>VertxMetrics</code>, meaning that only a single one is
2217
* available per Quarkus instance. To avoid clashing with other extensions that provide Metrics data (like the
2318
* Micrometer extension), we only register the {@link OpenTelemetryVertxMetricsFactory} if the
@@ -26,19 +21,17 @@
2621
public class OpenTelemetryVertxMetricsFactory implements VertxMetricsFactory {
2722
@Override
2823
public VertxMetrics metrics(final VertxOptions options) {
29-
return new OpenTelemetryHttpServerMetrics();
24+
return new VertxMetrics() {
25+
@Override
26+
public HttpServerMetrics<?, ?, ?> createHttpServerMetrics(final HttpServerOptions options,
27+
final SocketAddress localAddress) {
28+
return new OpenTelemetryVertxServerMetrics();
29+
}
30+
};
3031
}
3132

32-
public static class OpenTelemetryHttpServerMetrics
33-
implements HttpServerMetrics<OpenTelemetryHttpServerMetrics.MetricRequest, Object, Object>,
34-
VertxMetrics, ExtendedQuarkusVertxHttpMetrics {
35-
36-
@Override
37-
public HttpServerMetrics<?, ?, ?> createHttpServerMetrics(final HttpServerOptions options,
38-
final SocketAddress localAddress) {
39-
return this;
40-
}
41-
33+
public static class OpenTelemetryVertxServerMetrics
34+
implements HttpServerMetrics<MetricRequest, Object, Object> {
4235
@Override
4336
public MetricRequest requestBegin(final Object socketMetric, final HttpRequest request) {
4437
return MetricRequest.request(request);
@@ -50,31 +43,5 @@ public void requestRouted(final MetricRequest requestMetric, final String route)
5043
requestMetric.getContext().ifPresent(context -> context.putLocal("VertxRoute", route));
5144
}
5245
}
53-
54-
@Override
55-
public ConnectionTracker getHttpConnectionTracker() {
56-
// To be implemented if we decide to instrument with OpenTelemetry. See VertxMeterBinderAdapter for an example.
57-
return ExtendedQuarkusVertxHttpMetrics.NOOP_CONNECTION_TRACKER;
58-
}
59-
60-
static final class MetricRequest {
61-
private final HttpRequest request;
62-
63-
MetricRequest(final HttpRequest request) {
64-
this.request = request;
65-
}
66-
67-
Optional<Context> getContext() {
68-
if (request instanceof HttpServerRequestInternal) {
69-
return Optional.of(((HttpServerRequestInternal) request).context());
70-
} else {
71-
return Optional.empty();
72-
}
73-
}
74-
75-
static MetricRequest request(final HttpRequest httpRequest) {
76-
return new MetricRequest(httpRequest);
77-
}
78-
}
7946
}
8047
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xmlns="http://maven.apache.org/POM/4.0.0"
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+
<parent>
7+
<groupId>io.quarkus</groupId>
8+
<artifactId>quarkus-integration-tests-parent</artifactId>
9+
<version>999-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>quarkus-integration-test-opentelemetry-minimal</artifactId>
13+
<name>Quarkus - Integration Tests - OpenTelemetry minimal (No HTTP)</name>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>io.quarkus</groupId>
18+
<artifactId>quarkus-vertx</artifactId>
19+
</dependency>
20+
<dependency>
21+
<groupId>io.quarkus</groupId>
22+
<artifactId>quarkus-opentelemetry</artifactId>
23+
</dependency>
24+
<dependency>
25+
<groupId>io.opentelemetry</groupId>
26+
<artifactId>opentelemetry-sdk-testing</artifactId>
27+
</dependency>
28+
29+
<dependency>
30+
<groupId>io.quarkus</groupId>
31+
<artifactId>quarkus-junit5</artifactId>
32+
<scope>test</scope>
33+
</dependency>
34+
<dependency>
35+
<groupId>org.awaitility</groupId>
36+
<artifactId>awaitility</artifactId>
37+
<scope>test</scope>
38+
</dependency>
39+
40+
<!-- Minimal test dependencies to *-deployment artifacts for consistent build order -->
41+
<dependency>
42+
<groupId>io.quarkus</groupId>
43+
44+
<artifactId>quarkus-vertx-deployment</artifactId>
45+
<version>${project.version}</version>
46+
<type>pom</type>
47+
<scope>test</scope>
48+
<exclusions>
49+
<exclusion>
50+
<groupId>*</groupId>
51+
<artifactId>*</artifactId>
52+
</exclusion>
53+
</exclusions>
54+
</dependency>
55+
<dependency>
56+
<groupId>io.quarkus</groupId>
57+
<artifactId>quarkus-opentelemetry-deployment</artifactId>
58+
<version>${project.version}</version>
59+
<type>pom</type>
60+
<scope>test</scope>
61+
<exclusions>
62+
<exclusion>
63+
<groupId>*</groupId>
64+
<artifactId>*</artifactId>
65+
</exclusion>
66+
</exclusions>
67+
</dependency>
68+
69+
</dependencies>
70+
71+
<build>
72+
<plugins>
73+
<plugin>
74+
<groupId>io.quarkus</groupId>
75+
<artifactId>quarkus-maven-plugin</artifactId>
76+
<executions>
77+
<execution>
78+
<goals>
79+
<goal>build</goal>
80+
</goals>
81+
</execution>
82+
</executions>
83+
</plugin>
84+
<plugin>
85+
<groupId>org.apache.maven.plugins</groupId>
86+
<artifactId>maven-surefire-plugin</artifactId>
87+
<configuration>
88+
<systemPropertyVariables>
89+
<vertx.disableWebsockets>false</vertx.disableWebsockets>
90+
</systemPropertyVariables>
91+
</configuration>
92+
</plugin>
93+
</plugins>
94+
</build>
95+
96+
<profiles>
97+
<profile>
98+
<id>native-image</id>
99+
<activation>
100+
<property>
101+
<name>native</name>
102+
</property>
103+
</activation>
104+
105+
<properties>
106+
<quarkus.native.enabled>true</quarkus.native.enabled>
107+
</properties>
108+
109+
<build>
110+
<plugins>
111+
<plugin>
112+
<groupId>org.apache.maven.plugins</groupId>
113+
<artifactId>maven-surefire-plugin</artifactId>
114+
<configuration>
115+
<skipTests>${native.surefire.skip}</skipTests>
116+
<systemPropertyVariables>
117+
<vertx.disableWebsockets>false</vertx.disableWebsockets>
118+
</systemPropertyVariables>
119+
</configuration>
120+
</plugin>
121+
122+
<plugin>
123+
<artifactId>maven-failsafe-plugin</artifactId>
124+
<executions>
125+
<execution>
126+
<goals>
127+
<goal>integration-test</goal>
128+
<goal>verify</goal>
129+
</goals>
130+
<configuration>
131+
<systemPropertyVariables>
132+
<vertx.disableWebsockets>false</vertx.disableWebsockets>
133+
<native.image.path>
134+
${project.build.directory}/${project.build.finalName}-runner
135+
</native.image.path>
136+
</systemPropertyVariables>
137+
</configuration>
138+
</execution>
139+
</executions>
140+
</plugin>
141+
</plugins>
142+
</build>
143+
</profile>
144+
</profiles>
145+
146+
</project>

0 commit comments

Comments
 (0)