Prevent JDBC spans from nesting

This commit is contained in:
Tyler Benson 2018-05-01 10:57:47 +10:00
parent 11ecff0726
commit 6f64b0e021
3 changed files with 30 additions and 15 deletions

View File

@ -273,7 +273,7 @@ class JDBCInstrumentationTest extends Specification {
where: where:
driver | connection | username | query driver | connection | username | query
"h2" | connections.get("h2") | null | "CREATE TABLE PS_H2 (id INTEGER not NULL, PRIMARY KEY ( id ))" "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 ))" "hsqldb" | connections.get("hsqldb") | "SA" | "CREATE TABLE PUBLIC.PS_HSQLDB (id INTEGER not NULL, PRIMARY KEY ( id ))"
} }
} }

View File

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

View File

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