Prevent JDBC spans from nesting
MODIFY
dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/jdbc/JDBCInstrumentationTest.groovy
dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/jdbc/JDBCInstrumentationTest.groovy
@@ -273,7 +273,7 @@ class JDBCInstrumentationTest extends Specification {
where:
driver | connection | username | query
"h2" | connections.get("h2") | null | "CREATE TABLE PS_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))"
- // Derby calls executeLargeUpdate from executeUpdate thus generating a nested span breaking this test.
+ "derby" | connections.get("derby") | "APP" | "CREATE TABLE PS_DERBY (id INTEGER not NULL, PRIMARY KEY ( id ))"
"hsqldb" | connections.get("hsqldb") | "SA" | "CREATE TABLE PUBLIC.PS_HSQLDB (id INTEGER not NULL, PRIMARY KEY ( id ))"
}
}

MODIFY
dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java
dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java
@@ -14,10 +14,10 @@ import datadog.trace.agent.tooling.DDAdvice;
import datadog.trace.agent.tooling.DDTransformers;
import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.api.DDTags;
+import datadog.trace.bootstrap.CallDepthThreadLocalMap;
import datadog.trace.bootstrap.JDBCMaps;
import io.opentracing.Scope;
import io.opentracing.Span;
-import io.opentracing.noop.NoopScopeManager;
import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer;
import java.sql.Connection;
@@ -50,13 +50,18 @@ public final class PreparedStatementInstrumentation extends Instrumenter.Configu
@Advice.OnMethodEnter(suppress = Throwable.class)
public static Scope startSpan(@Advice.This final PreparedStatement statement) {
+ final int callDepth =
+ CallDepthThreadLocalMap.get(PreparedStatement.class).incrementCallDepth();
+ if (callDepth > 0) {
+ return null;
+ }
final String sql = JDBCMaps.preparedStatements.get(statement);
final Connection connection;
try {
connection = statement.getConnection();
} catch (final Throwable e) {
// Had some problem getting the connection.
- return NoopScopeManager.NoopScope.INSTANCE;
+ return null;
}
JDBCMaps.DBInfo dbInfo = JDBCMaps.connectionInfo.get(connection);
@@ -86,12 +91,15 @@ public final class PreparedStatementInstrumentation extends Instrumenter.Configu
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
+ if (scope != null) {
if (throwable != null) {
final Span span = scope.span();
Tags.ERROR.set(span, true);
span.log(Collections.singletonMap(ERROR_OBJECT, throwable));
}
scope.close();
+ CallDepthThreadLocalMap.get(PreparedStatement.class).reset();
+ }
}
}
}

MODIFY
dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java
dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java
@@ -14,10 +14,10 @@ import datadog.trace.agent.tooling.DDAdvice;
import datadog.trace.agent.tooling.DDTransformers;
import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.api.DDTags;
+import datadog.trace.bootstrap.CallDepthThreadLocalMap;
import datadog.trace.bootstrap.JDBCMaps;
import io.opentracing.Scope;
import io.opentracing.Span;
-import io.opentracing.noop.NoopScopeManager;
import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer;
import java.sql.Connection;
@@ -51,12 +51,16 @@ public final class StatementInstrumentation extends Instrumenter.Configurable {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static Scope startSpan(
@Advice.Argument(0) final String sql, @Advice.This final Statement statement) {
+ final int callDepth = CallDepthThreadLocalMap.get(Statement.class).incrementCallDepth();
+ if (callDepth > 0) {
+ return null;
+ }
final Connection connection;
try {
connection = statement.getConnection();
} catch (final Throwable e) {
// Had some problem getting the connection.
- return NoopScopeManager.NoopScope.INSTANCE;
+ return null;
}
JDBCMaps.DBInfo dbInfo = JDBCMaps.connectionInfo.get(connection);
@@ -88,12 +92,15 @@ public final class StatementInstrumentation extends Instrumenter.Configurable {
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
+ if (scope != null) {
if (throwable != null) {
final Span span = scope.span();
Tags.ERROR.set(span, true);
span.log(Collections.singletonMap(ERROR_OBJECT, throwable));
}
scope.close();
+ CallDepthThreadLocalMap.get(Statement.class).reset();
+ }
}
}
}

Prevent JDBC spans from nesting