Skip to content

Commit 558a7bf

Browse files
committed
Exclude jdbc wrappers from instrumentation
1 parent 12facf3 commit 558a7bf

File tree

4 files changed

+68
-2
lines changed

4 files changed

+68
-2
lines changed

instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/ConnectionInstrumentation.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ public static class PrepareAdvice {
6161
@Advice.OnMethodExit(suppress = Throwable.class)
6262
public static void addDbInfo(
6363
@Advice.Argument(0) String sql, @Advice.Return PreparedStatement statement) {
64+
if (JdbcSingletons.isWrapper(statement, PreparedStatement.class)) {
65+
return;
66+
}
67+
6468
JdbcData.preparedStatement.set(statement, sql);
6569
}
6670
}
@@ -74,6 +78,10 @@ public static void onEnter(
7478
@Advice.Origin("#m") String methodName,
7579
@Advice.Local("otelContext") Context context,
7680
@Advice.Local("otelScope") Scope scope) {
81+
if (JdbcSingletons.isWrapper(connection, Connection.class)) {
82+
return;
83+
}
84+
7785
Context parentContext = currentContext();
7886
DbRequest request =
7987
DbRequest.createTransaction(connection, methodName.toUpperCase(Locale.ROOT));

instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/JdbcSingletons.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@
1111
import io.opentelemetry.instrumentation.api.incubator.semconv.net.PeerServiceAttributesExtractor;
1212
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
1313
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
14+
import io.opentelemetry.instrumentation.api.internal.cache.Cache;
1415
import io.opentelemetry.instrumentation.jdbc.internal.DbRequest;
1516
import io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory;
1617
import io.opentelemetry.instrumentation.jdbc.internal.JdbcNetworkAttributesGetter;
1718
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig;
1819
import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig;
1920
import io.opentelemetry.javaagent.bootstrap.jdbc.DbInfo;
21+
import java.sql.SQLException;
22+
import java.sql.Wrapper;
2023
import java.util.Collections;
2124
import javax.sql.DataSource;
2225

@@ -68,5 +71,31 @@ public static Instrumenter<DataSource, DbInfo> dataSourceInstrumenter() {
6871
return DATASOURCE_INSTRUMENTER;
6972
}
7073

74+
private static final Cache<Class<?>, Boolean> wrapperClassCache = Cache.weak();
75+
76+
/**
77+
* Returns true if the given object is a wrapper and shouldn't be instrumented. We'll instrument
78+
* the underlying object called by the wrapper instead.
79+
*/
80+
public static <T extends Wrapper> boolean isWrapper(T object, Class<T> clazz) {
81+
return wrapperClassCache.computeIfAbsent(
82+
object.getClass(), key -> isWrapperInternal(object, clazz));
83+
}
84+
85+
private static <T extends Wrapper> boolean isWrapperInternal(T object, Class<T> clazz) {
86+
try {
87+
// we are dealing with a wrapper when the object unwraps to a different instance
88+
if (object.isWrapperFor(clazz)) {
89+
T unwrapped = object.unwrap(clazz);
90+
if (object != unwrapped) {
91+
return true;
92+
}
93+
}
94+
} catch (SQLException | AbstractMethodError e) {
95+
// ignore
96+
}
97+
return false;
98+
}
99+
71100
private JdbcSingletons() {}
72101
}

instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/PreparedStatementInstrumentation.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ public static void onEnter(
118118
return;
119119
}
120120

121+
if (JdbcSingletons.isWrapper(statement, PreparedStatement.class)) {
122+
return;
123+
}
124+
121125
// Connection#getMetaData() may execute a Statement or PreparedStatement to retrieve DB info
122126
// this happens before the DB CLIENT span is started (and put in the current context), so this
123127
// instrumentation runs again and the shouldStartSpan() check always returns true - and so on
@@ -165,6 +169,10 @@ public static class AddBatchAdvice {
165169

166170
@Advice.OnMethodExit(suppress = Throwable.class)
167171
public static void addBatch(@Advice.This PreparedStatement statement) {
172+
if (JdbcSingletons.isWrapper(statement, Statement.class)) {
173+
return;
174+
}
175+
168176
JdbcData.addPreparedStatementBatch(statement);
169177
}
170178
}
@@ -179,6 +187,9 @@ public static void onExit(
179187
if (!CAPTURE_QUERY_PARAMETERS) {
180188
return;
181189
}
190+
if (JdbcSingletons.isWrapper(statement, PreparedStatement.class)) {
191+
return;
192+
}
182193

183194
String str = null;
184195

@@ -211,6 +222,9 @@ public static void onExit(
211222
if (!CAPTURE_QUERY_PARAMETERS) {
212223
return;
213224
}
225+
if (JdbcSingletons.isWrapper(statement, PreparedStatement.class)) {
226+
return;
227+
}
214228

215229
String str = null;
216230

@@ -243,6 +257,9 @@ public static void onExit(
243257
if (!CAPTURE_QUERY_PARAMETERS) {
244258
return;
245259
}
260+
if (JdbcSingletons.isWrapper(statement, PreparedStatement.class)) {
261+
return;
262+
}
246263

247264
String str = null;
248265

instrumentation/jdbc/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jdbc/StatementInstrumentation.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ public static void onEnter(
7272
@Advice.Local("otelRequest") DbRequest request,
7373
@Advice.Local("otelContext") Context context,
7474
@Advice.Local("otelScope") Scope scope) {
75+
if (JdbcSingletons.isWrapper(statement, Statement.class)) {
76+
return;
77+
}
78+
7579
// Connection#getMetaData() may execute a Statement or PreparedStatement to retrieve DB info
7680
// this happens before the DB CLIENT span is started (and put in the current context), so this
7781
// instrumentation runs again and the shouldStartSpan() check always returns true - and so on
@@ -102,7 +106,7 @@ public static void stopSpan(
102106
@Advice.Local("otelRequest") DbRequest request,
103107
@Advice.Local("otelContext") Context context,
104108
@Advice.Local("otelScope") Scope scope) {
105-
if (callDepth.decrementAndGet() > 0) {
109+
if (callDepth == null || callDepth.decrementAndGet() > 0) {
106110
return;
107111
}
108112

@@ -121,6 +125,10 @@ public static void addBatch(@Advice.This Statement statement, @Advice.Argument(0
121125
if (statement instanceof PreparedStatement) {
122126
return;
123127
}
128+
if (JdbcSingletons.isWrapper(statement, Statement.class)) {
129+
return;
130+
}
131+
124132
JdbcData.addStatementBatch(statement, sql);
125133
}
126134
}
@@ -144,6 +152,10 @@ public static void onEnter(
144152
@Advice.Local("otelRequest") DbRequest request,
145153
@Advice.Local("otelContext") Context context,
146154
@Advice.Local("otelScope") Scope scope) {
155+
if (JdbcSingletons.isWrapper(statement, Statement.class)) {
156+
return;
157+
}
158+
147159
// Connection#getMetaData() may execute a Statement or PreparedStatement to retrieve DB info
148160
// this happens before the DB CLIENT span is started (and put in the current context), so this
149161
// instrumentation runs again and the shouldStartSpan() check always returns true - and so on
@@ -190,7 +202,7 @@ public static void stopSpan(
190202
@Advice.Local("otelRequest") DbRequest request,
191203
@Advice.Local("otelContext") Context context,
192204
@Advice.Local("otelScope") Scope scope) {
193-
if (callDepth.decrementAndGet() > 0) {
205+
if (callDepth == null || callDepth.decrementAndGet() > 0) {
194206
return;
195207
}
196208

0 commit comments

Comments
 (0)