Skip to content

Commit 8312e06

Browse files
authored
Merge pull request #31567 from michalvavrik/feature/opentelemetry-tracing-enabled
Use a property to enable OpenTelemetry for JDBC and use the OpenTelemetry datasource instead of the OpenTelemetry driver
2 parents 912fc9e + 956f31a commit 8312e06

File tree

20 files changed

+305
-179
lines changed

20 files changed

+305
-179
lines changed

docs/src/main/asciidoc/opentelemetry.adoc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,15 +243,16 @@ The https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/ma
243243
implementation("io.opentelemetry.instrumentation:opentelemetry-jdbc")
244244
----
245245

246-
As it uses a dedicated JDBC driver, you must configure your datasource and Hibernate ORM to use it.
246+
As it uses a dedicated JDBC datasource wrapper, you must enable telemetry for your datasource:
247247

248248
[source, properties]
249249
----
250+
# enable tracing
251+
quarkus.datasource.jdbc.telemetry=true
252+
253+
# configure datasource
250254
quarkus.datasource.db-kind=postgresql
251-
# add ':otel' to your database URL
252-
quarkus.datasource.jdbc.url=jdbc:otel:postgresql://localhost:5432/mydatabase
253-
# use the 'OpenTelemetryDriver' instead of the one for your database
254-
quarkus.datasource.jdbc.driver=io.opentelemetry.instrumentation.jdbc.OpenTelemetryDriver
255+
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydatabase
255256
----
256257

257258
== Additional configuration

extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalProcessor.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.quarkus.agroal.deployment;
22

3+
import static io.quarkus.deployment.Capability.OPENTELEMETRY_TRACER;
4+
35
import java.sql.Driver;
46
import java.util.ArrayList;
57
import java.util.HashMap;
@@ -77,8 +79,10 @@ void build(
7779
List<JdbcDriverBuildItem> jdbcDriverBuildItems,
7880
BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
7981
BuildProducer<NativeImageResourceBuildItem> resource,
82+
Capabilities capabilities,
8083
BuildProducer<ExtensionSslNativeSupportBuildItem> sslNativeSupport,
8184
BuildProducer<AggregatedDataSourceBuildTimeConfigBuildItem> aggregatedConfig,
85+
BuildProducer<AdditionalBeanBuildItem> additionalBeans,
8286
CurateOutcomeBuildItem curateOutcomeBuildItem) throws Exception {
8387
if (dataSourcesBuildTimeConfig.driver.isPresent() || dataSourcesBuildTimeConfig.url.isPresent()) {
8488
throw new ConfigurationException(
@@ -96,6 +100,7 @@ void build(
96100
return;
97101
}
98102

103+
boolean otelJdbcInstrumentationActive = false;
99104
for (AggregatedDataSourceBuildTimeConfigBuildItem aggregatedDataSourceBuildTimeConfig : aggregatedDataSourceBuildTimeConfigs) {
100105
validateBuildTimeConfig(aggregatedDataSourceBuildTimeConfig);
101106

@@ -105,13 +110,25 @@ void build(
105110
DataSources.TRACING_DRIVER_CLASSNAME));
106111
}
107112

113+
if (aggregatedDataSourceBuildTimeConfig.getJdbcConfig().telemetry) {
114+
otelJdbcInstrumentationActive = true;
115+
}
116+
108117
reflectiveClass
109118
.produce(new ReflectiveClassBuildItem(true, false,
110119
aggregatedDataSourceBuildTimeConfig.getResolvedDriverClass()));
111120

112121
aggregatedConfig.produce(aggregatedDataSourceBuildTimeConfig);
113122
}
114123

124+
if (otelJdbcInstrumentationActive && capabilities.isPresent(OPENTELEMETRY_TRACER)) {
125+
// at least one datasource is using OpenTelemetry JDBC instrumentation,
126+
// therefore we register the OpenTelemetry data source wrapper bean
127+
additionalBeans.produce(new AdditionalBeanBuildItem.Builder()
128+
.addBeanClass("io.quarkus.agroal.runtime.AgroalOpenTelemetryWrapper")
129+
.setDefaultScope(DotNames.SINGLETON).build());
130+
}
131+
115132
// For now, we can't push the security providers to Agroal so we need to include
116133
// the service file inside the image. Hopefully, we will get an entry point to
117134
// resolve them at build time and push them to Agroal soon.

extensions/agroal/runtime/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@
7171
<scope>test</scope>
7272
</dependency>
7373

74+
<!-- Required for OpenTelemetry JDBC instrumentation -->
75+
<dependency>
76+
<groupId>io.opentelemetry.instrumentation</groupId>
77+
<artifactId>opentelemetry-jdbc</artifactId>
78+
<optional>true</optional>
79+
</dependency>
80+
7481
</dependencies>
7582

7683
<build>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.quarkus.agroal.runtime;
2+
3+
import java.util.function.Function;
4+
5+
import io.agroal.api.AgroalDataSource;
6+
7+
public class AgroalOpenTelemetryWrapper implements Function<AgroalDataSource, AgroalDataSource> {
8+
9+
@Override
10+
public AgroalDataSource apply(AgroalDataSource originalDataSource) {
11+
return new OpenTelemetryAgroalDataSource(originalDataSource);
12+
}
13+
}

extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSourceJdbcBuildTimeConfig.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,10 @@ public class DataSourceJdbcBuildTimeConfig {
4343
*/
4444
@ConfigItem(defaultValue = "false")
4545
public boolean tracing = false;
46+
47+
/**
48+
* Enable OpenTelemetry JDBC instrumentation.
49+
*/
50+
@ConfigItem(defaultValue = "false")
51+
public boolean telemetry = false;
4652
}

extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSourceJdbcRuntimeConfig.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,10 @@ public class DataSourceJdbcRuntimeConfig {
145145
@ConfigItem
146146
public DataSourceJdbcTracingRuntimeConfig tracing = new DataSourceJdbcTracingRuntimeConfig();
147147

148+
/**
149+
* Enable OpenTelemetry JDBC instrumentation.
150+
*/
151+
@ConfigItem(name = "telemetry.enabled", defaultValueDocumentation = "false if quarkus.datasource.jdbc.telemetry=false and true if quarkus.datasource.jdbc.telemetry=true")
152+
public Optional<Boolean> telemetry;
153+
148154
}

extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public class DataSources {
7979
private final TransactionSynchronizationRegistry transactionSynchronizationRegistry;
8080
private final DataSourceSupport dataSourceSupport;
8181
private final Instance<AgroalPoolInterceptor> agroalPoolInterceptors;
82+
private final Instance<AgroalOpenTelemetryWrapper> agroalOpenTelemetryWrapper;
8283

8384
private final ConcurrentMap<String, AgroalDataSource> dataSources = new ConcurrentHashMap<>();
8485

@@ -88,8 +89,10 @@ public DataSources(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
8889
TransactionManagerConfiguration transactionRuntimeConfig,
8990
TransactionManager transactionManager,
9091
XAResourceRecoveryRegistry xaResourceRecoveryRegistry,
91-
TransactionSynchronizationRegistry transactionSynchronizationRegistry, DataSourceSupport dataSourceSupport,
92-
@Any Instance<AgroalPoolInterceptor> agroalPoolInterceptors) {
92+
TransactionSynchronizationRegistry transactionSynchronizationRegistry,
93+
DataSourceSupport dataSourceSupport,
94+
@Any Instance<AgroalPoolInterceptor> agroalPoolInterceptors,
95+
Instance<AgroalOpenTelemetryWrapper> agroalOpenTelemetryWrapper) {
9396
this.dataSourcesBuildTimeConfig = dataSourcesBuildTimeConfig;
9497
this.dataSourcesRuntimeConfig = dataSourcesRuntimeConfig;
9598
this.dataSourcesJdbcBuildTimeConfig = dataSourcesJdbcBuildTimeConfig;
@@ -100,6 +103,7 @@ public DataSources(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig,
100103
this.transactionSynchronizationRegistry = transactionSynchronizationRegistry;
101104
this.dataSourceSupport = dataSourceSupport;
102105
this.agroalPoolInterceptors = agroalPoolInterceptors;
106+
this.agroalOpenTelemetryWrapper = agroalOpenTelemetryWrapper;
103107
}
104108

105109
/**
@@ -127,6 +131,7 @@ public AgroalDataSource apply(String s) {
127131
});
128132
}
129133

134+
@SuppressWarnings("resource")
130135
public AgroalDataSource doCreateDataSource(String dataSourceName) {
131136
if (!dataSourceSupport.entries.containsKey(dataSourceName)) {
132137
throw new IllegalArgumentException("No datasource named '" + dataSourceName + "' exists");
@@ -252,6 +257,12 @@ public AgroalDataSource doCreateDataSource(String dataSourceName) {
252257
dataSource.setPoolInterceptors(interceptorList);
253258
}
254259

260+
if (dataSourceJdbcBuildTimeConfig.telemetry && dataSourceJdbcRuntimeConfig.telemetry.orElse(true)) {
261+
// activate OpenTelemetry JDBC instrumentation by wrapping AgroalDatasource
262+
// use an optional CDI bean as we can't reference optional OpenTelemetry classes here
263+
dataSource = agroalOpenTelemetryWrapper.get().apply(dataSource);
264+
}
265+
255266
return dataSource;
256267
}
257268

@@ -444,5 +455,4 @@ public void stop() {
444455
}
445456
}
446457
}
447-
448458
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package io.quarkus.agroal.runtime;
2+
3+
import java.sql.SQLException;
4+
import java.sql.ShardingKeyBuilder;
5+
import java.util.Collection;
6+
import java.util.List;
7+
8+
import io.agroal.api.AgroalDataSource;
9+
import io.agroal.api.AgroalDataSourceMetrics;
10+
import io.agroal.api.AgroalPoolInterceptor;
11+
import io.agroal.api.configuration.AgroalDataSourceConfiguration;
12+
import io.opentelemetry.api.GlobalOpenTelemetry;
13+
import io.opentelemetry.instrumentation.jdbc.datasource.OpenTelemetryDataSource;
14+
15+
/**
16+
* The {@link AgroalDataSource} wrapper that activates OpenTelemetry JDBC instrumentation.
17+
*/
18+
public class OpenTelemetryAgroalDataSource extends OpenTelemetryDataSource implements AgroalDataSource {
19+
20+
private final AgroalDataSource delegate;
21+
22+
public OpenTelemetryAgroalDataSource(AgroalDataSource delegate) {
23+
super(delegate, GlobalOpenTelemetry.get());
24+
this.delegate = delegate;
25+
}
26+
27+
@Override
28+
public boolean isHealthy(boolean newConnection) throws SQLException {
29+
return delegate.isHealthy(newConnection);
30+
}
31+
32+
@Override
33+
public AgroalDataSourceConfiguration getConfiguration() {
34+
return delegate.getConfiguration();
35+
}
36+
37+
@Override
38+
public AgroalDataSourceMetrics getMetrics() {
39+
return delegate.getMetrics();
40+
}
41+
42+
@Override
43+
public void flush(FlushMode mode) {
44+
delegate.flush(mode);
45+
}
46+
47+
@Override
48+
public void setPoolInterceptors(Collection<? extends AgroalPoolInterceptor> interceptors) {
49+
delegate.setPoolInterceptors(interceptors);
50+
}
51+
52+
@Override
53+
public List<AgroalPoolInterceptor> getPoolInterceptors() {
54+
return delegate.getPoolInterceptors();
55+
}
56+
57+
@Override
58+
public ShardingKeyBuilder createShardingKeyBuilder() throws SQLException {
59+
return delegate.createShardingKeyBuilder();
60+
}
61+
62+
@Override
63+
public void close() {
64+
delegate.close();
65+
}
66+
}

extensions/opentelemetry/deployment/pom.xml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,6 @@
111111
<artifactId>quarkus-agroal-deployment</artifactId>
112112
<scope>test</scope>
113113
</dependency>
114-
<dependency>
115-
<groupId>io.quarkus</groupId>
116-
<artifactId>quarkus-jdbc-h2-deployment</artifactId>
117-
<scope>test</scope>
118-
</dependency>
119114
<dependency>
120115
<groupId>io.opentelemetry.instrumentation</groupId>
121116
<artifactId>opentelemetry-jdbc</artifactId>
@@ -137,6 +132,17 @@
137132
<artifactId>opentelemetry-aws-xray</artifactId>
138133
<scope>test</scope>
139134
</dependency>
135+
<dependency>
136+
<groupId>io.quarkus</groupId>
137+
<artifactId>quarkus-jdbc-h2-deployment</artifactId>
138+
<scope>test</scope>
139+
</dependency>
140+
141+
<!-- Needed for InMemorySpanExporter to verify captured traces -->
142+
<dependency>
143+
<groupId>io.opentelemetry</groupId>
144+
<artifactId>opentelemetry-sdk-testing</artifactId>
145+
</dependency>
140146
</dependencies>
141147

142148
<build>

extensions/opentelemetry/deployment/src/main/java/io/quarkus/opentelemetry/deployment/OpenTelemetryDriverJdbcDataSourcesBuildItem.java

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)