Skip to content

Commit

Permalink
Minimal OTel
Browse files Browse the repository at this point in the history
  • Loading branch information
brunobat committed Oct 24, 2024
1 parent 8f7119e commit d2b8866
Show file tree
Hide file tree
Showing 11 changed files with 353 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ public boolean getAsBoolean() {
}
}

static class VertxHttpAvailable implements BooleanSupplier {
private static final boolean IS_VERTX_HTTP_AVAILABLE = isClassPresentAtRuntime(
"io.quarkus.vertx.http.runtime.VertxHttpRecorder");

@Override
public boolean getAsBoolean() {
return IS_VERTX_HTTP_AVAILABLE;
}
}

@BuildStep(onlyIf = GrpcExtensionAvailable.class)
void grpcTracers(BuildProducer<AdditionalBeanBuildItem> additionalBeans, OTelBuildConfig config) {
if (config.instrument().grpc()) {
Expand Down Expand Up @@ -100,10 +110,16 @@ void registerReactiveMessagingMessageDecorator(
}
}

@BuildStep(onlyIfNot = MetricsExtensionAvailable.class)
@BuildStep(onlyIfNot = MetricsExtensionAvailable.class, onlyIf = VertxHttpAvailable.class)
@Record(ExecutionTime.STATIC_INIT)
VertxOptionsConsumerBuildItem vertxHttpMetricsOptions(InstrumentationRecorder recorder) {
return new VertxOptionsConsumerBuildItem(recorder.getVertxHttpMetricsOptions(), LIBRARY_AFTER + 1);
}

@BuildStep(onlyIfNot = { MetricsExtensionAvailable.class, VertxHttpAvailable.class })
@Record(ExecutionTime.STATIC_INIT)
VertxOptionsConsumerBuildItem vertxTracingMetricsOptions(InstrumentationRecorder recorder) {
return new VertxOptionsConsumerBuildItem(recorder.getVertxTracingMetricsOptions(), LIBRARY_AFTER + 1);
VertxOptionsConsumerBuildItem vertxMetricsOptions(InstrumentationRecorder recorder) {
return new VertxOptionsConsumerBuildItem(recorder.getVertxMetricsOptions(), LIBRARY_AFTER + 1);
}

@BuildStep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.EventBusInstrumenterVertxTracer;
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.HttpInstrumenterVertxTracer;
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.InstrumenterVertxTracer;
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxHttpMetricsFactory;
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxMetricsFactory;
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxTracer;
import io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx.OpenTelemetryVertxTracingFactory;
Expand Down Expand Up @@ -74,7 +75,15 @@ public void setupVertxTracer(BeanContainer beanContainer, boolean sqlClientAvail
}

/* STATIC INIT */
public Consumer<VertxOptions> getVertxTracingMetricsOptions() {
public Consumer<VertxOptions> getVertxHttpMetricsOptions() {
MetricsOptions metricsOptions = new MetricsOptions()
.setEnabled(true)
.setFactory(new OpenTelemetryVertxHttpMetricsFactory());
return vertxOptions -> vertxOptions.setMetricsOptions(metricsOptions);
}

/* STATIC INIT */
public Consumer<VertxOptions> getVertxMetricsOptions() {
MetricsOptions metricsOptions = new MetricsOptions()
.setEnabled(true)
.setFactory(new OpenTelemetryVertxMetricsFactory());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx;

import java.util.Optional;

import io.vertx.core.Context;
import io.vertx.core.http.impl.HttpServerRequestInternal;
import io.vertx.core.spi.observability.HttpRequest;

public final class MetricRequest {
private final HttpRequest request;

MetricRequest(final HttpRequest request) {
this.request = request;
}

Optional<Context> getContext() {
if (request instanceof HttpServerRequestInternal) {
return Optional.of(((HttpServerRequestInternal) request).context());
} else {
return Optional.empty();
}
}

static MetricRequest request(final HttpRequest httpRequest) {
return new MetricRequest(httpRequest);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx;

import io.quarkus.vertx.http.runtime.ExtendedQuarkusVertxHttpMetrics;
import io.vertx.core.VertxOptions;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.net.SocketAddress;
import io.vertx.core.spi.VertxMetricsFactory;
import io.vertx.core.spi.metrics.HttpServerMetrics;
import io.vertx.core.spi.metrics.VertxMetrics;
import io.vertx.core.spi.observability.HttpRequest;

/**
* This is used to retrieve the route name from Vert.x. This is useful for OpenTelemetry to generate the Span name and
* <code>http.route</code> attribute. Right now, there is no other way to retrieve the route name from Vert.x using the
* Telemetry SPI, so we need to rely on the Metrics SPI.
* <p>
* Right now, it is not possible to register multiple <code>VertxMetrics</code>, meaning that only a single one is
* available per Quarkus instance. To avoid clashing with other extensions that provide Metrics data (like the
* Micrometer extension), we only register the {@link OpenTelemetryVertxHttpMetricsFactory} if the
* <code>VertxHttpServerMetrics</code> is not available in the runtime.
*/
public class OpenTelemetryVertxHttpMetricsFactory implements VertxMetricsFactory {
@Override
public VertxMetrics metrics(final VertxOptions options) {
return new OpenTelemetryVertxHttpServerMetrics();
}

public static class OpenTelemetryVertxHttpServerMetrics
implements HttpServerMetrics<MetricRequest, Object, Object>,
VertxMetrics, ExtendedQuarkusVertxHttpMetrics {

@Override
public HttpServerMetrics<?, ?, ?> createHttpServerMetrics(final HttpServerOptions options,
final SocketAddress localAddress) {
return this;
}

@Override
public MetricRequest requestBegin(final Object socketMetric, final HttpRequest request) {
return MetricRequest.request(request);
}

@Override
public void requestRouted(final MetricRequest requestMetric, final String route) {
if (route != null) {
requestMetric.getContext().ifPresent(context -> context.putLocal("VertxRoute", route));
}
}

@Override
public ConnectionTracker getHttpConnectionTracker() {
// To be implemented if we decide to instrument with OpenTelemetry. See VertxMeterBinderAdapter for an example.
return ExtendedQuarkusVertxHttpMetrics.NOOP_CONNECTION_TRACKER;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
package io.quarkus.opentelemetry.runtime.tracing.intrumentation.vertx;

import java.util.Optional;

import io.quarkus.vertx.http.runtime.ExtendedQuarkusVertxHttpMetrics;
import io.vertx.core.Context;
import io.vertx.core.VertxOptions;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.http.impl.HttpServerRequestInternal;
import io.vertx.core.net.SocketAddress;
import io.vertx.core.spi.VertxMetricsFactory;
import io.vertx.core.spi.metrics.HttpServerMetrics;
Expand All @@ -17,7 +12,7 @@
* This is used to retrieve the route name from Vert.x. This is useful for OpenTelemetry to generate the Span name and
* <code>http.route</code> attribute. Right now, there is no other way to retrieve the route name from Vert.x using the
* Telemetry SPI, so we need to rely on the Metrics SPI.
* <p>
*
* Right now, it is not possible to register multiple <code>VertxMetrics</code>, meaning that only a single one is
* available per Quarkus instance. To avoid clashing with other extensions that provide Metrics data (like the
* Micrometer extension), we only register the {@link OpenTelemetryVertxMetricsFactory} if the
Expand All @@ -26,19 +21,17 @@
public class OpenTelemetryVertxMetricsFactory implements VertxMetricsFactory {
@Override
public VertxMetrics metrics(final VertxOptions options) {
return new OpenTelemetryHttpServerMetrics();
return new VertxMetrics() {
@Override
public HttpServerMetrics<?, ?, ?> createHttpServerMetrics(final HttpServerOptions options,
final SocketAddress localAddress) {
return new OpenTelemetryVertxServerMetrics();
}
};
}

public static class OpenTelemetryHttpServerMetrics
implements HttpServerMetrics<OpenTelemetryHttpServerMetrics.MetricRequest, Object, Object>,
VertxMetrics, ExtendedQuarkusVertxHttpMetrics {

@Override
public HttpServerMetrics<?, ?, ?> createHttpServerMetrics(final HttpServerOptions options,
final SocketAddress localAddress) {
return this;
}

public static class OpenTelemetryVertxServerMetrics
implements HttpServerMetrics<MetricRequest, Object, Object> {
@Override
public MetricRequest requestBegin(final Object socketMetric, final HttpRequest request) {
return MetricRequest.request(request);
Expand All @@ -50,31 +43,5 @@ public void requestRouted(final MetricRequest requestMetric, final String route)
requestMetric.getContext().ifPresent(context -> context.putLocal("VertxRoute", route));
}
}

@Override
public ConnectionTracker getHttpConnectionTracker() {
// To be implemented if we decide to instrument with OpenTelemetry. See VertxMeterBinderAdapter for an example.
return ExtendedQuarkusVertxHttpMetrics.NOOP_CONNECTION_TRACKER;
}

static final class MetricRequest {
private final HttpRequest request;

MetricRequest(final HttpRequest request) {
this.request = request;
}

Optional<Context> getContext() {
if (request instanceof HttpServerRequestInternal) {
return Optional.of(((HttpServerRequestInternal) request).context());
} else {
return Optional.empty();
}
}

static MetricRequest request(final HttpRequest httpRequest) {
return new MetricRequest(httpRequest);
}
}
}
}
146 changes: 146 additions & 0 deletions integration-tests/opentelemetry-minimal/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-integration-tests-parent</artifactId>
<version>999-SNAPSHOT</version>
</parent>

<artifactId>quarkus-integration-test-opentelemetry-minimal</artifactId>
<name>Quarkus - Integration Tests - OpenTelemetry minimal (No HTTP)</name>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-testing</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>

<!-- Minimal test dependencies to *-deployment artifacts for consistent build order -->
<dependency>
<groupId>io.quarkus</groupId>

<artifactId>quarkus-vertx-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<vertx.disableWebsockets>false</vertx.disableWebsockets>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>native-image</id>
<activation>
<property>
<name>native</name>
</property>
</activation>

<properties>
<quarkus.native.enabled>true</quarkus.native.enabled>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>${native.surefire.skip}</skipTests>
<systemPropertyVariables>
<vertx.disableWebsockets>false</vertx.disableWebsockets>
</systemPropertyVariables>
</configuration>
</plugin>

<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemPropertyVariables>
<vertx.disableWebsockets>false</vertx.disableWebsockets>
<native.image.path>
${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

</project>
Loading

0 comments on commit d2b8866

Please sign in to comment.