Skip to content

Commit 11a429c

Browse files
nenadnoveljicvandonramarziali
authored
Add trace injection for prepared statements in Postgres (#7940)
* trace injection for prepared statements * parmeter * measure instrumentation time * test cases * test cases * restored remote tests * check concatenated string * SpotBugs annotation * new test cases * renamed TIME_MS to INSTRUMENTATION_TIME_MS * compile regex * catch Throwable * fix sized StringBuilder * removed inner catch * pattern as class variable * Update dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java Co-authored-by: Raphaël Vandon <[email protected]> * log only if isDebugEnabled * switched to setClientInfo --------- Co-authored-by: Raphaël Vandon <[email protected]> Co-authored-by: Andrea Marziali <[email protected]>
1 parent 5dd63de commit 11a429c

File tree

7 files changed

+203
-75
lines changed

7 files changed

+203
-75
lines changed

dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/AbstractPreparedStatementInstrumentation.java

+14-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan;
66
import static datadog.trace.bootstrap.instrumentation.api.InstrumentationTags.DBM_TRACE_INJECTED;
77
import static datadog.trace.instrumentation.jdbc.JDBCDecorator.DATABASE_QUERY;
8+
import static datadog.trace.instrumentation.jdbc.JDBCDecorator.DBM_TRACE_PREPARED_STATEMENTS;
89
import static datadog.trace.instrumentation.jdbc.JDBCDecorator.DECORATE;
910
import static datadog.trace.instrumentation.jdbc.JDBCDecorator.INJECT_COMMENT;
1011
import static datadog.trace.instrumentation.jdbc.JDBCDecorator.logMissingQueryInfo;
@@ -80,12 +81,19 @@ public static AgentScope onEnter(@Advice.This final Statement statement) {
8081
connection, InstrumentationContext.get(Connection.class, DBInfo.class));
8182
final boolean injectTraceContext = DECORATE.shouldInjectTraceContext(dbInfo);
8283

83-
if (INJECT_COMMENT && injectTraceContext && DECORATE.isSqlServer(dbInfo)) {
84-
// The span ID is pre-determined so that we can reference it when setting the context
85-
final long spanID = DECORATE.setContextInfo(connection, dbInfo);
86-
// we then force that pre-determined span ID for the span covering the actual query
87-
span = AgentTracer.get().buildSpan(DATABASE_QUERY).withSpanId(spanID).start();
88-
span.setTag(DBM_TRACE_INJECTED, true);
84+
if (INJECT_COMMENT && injectTraceContext) {
85+
if (DECORATE.isSqlServer(dbInfo)) {
86+
// The span ID is pre-determined so that we can reference it when setting the context
87+
final long spanID = DECORATE.setContextInfo(connection, dbInfo);
88+
// we then force that pre-determined span ID for the span covering the actual query
89+
span = AgentTracer.get().buildSpan(DATABASE_QUERY).withSpanId(spanID).start();
90+
span.setTag(DBM_TRACE_INJECTED, true);
91+
} else if (DECORATE.isPostgres(dbInfo) && DBM_TRACE_PREPARED_STATEMENTS) {
92+
span = startSpan(DATABASE_QUERY);
93+
DECORATE.setApplicationName(span, connection);
94+
} else {
95+
span = startSpan(DATABASE_QUERY);
96+
}
8997
} else {
9098
span = startSpan(DATABASE_QUERY);
9199
}

dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/JDBCDecorator.java

+46
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package datadog.trace.instrumentation.jdbc;
22

33
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan;
4+
import static datadog.trace.bootstrap.instrumentation.api.InstrumentationTags.DBM_TRACE_INJECTED;
5+
import static datadog.trace.bootstrap.instrumentation.api.InstrumentationTags.INSTRUMENTATION_TIME_MS;
46
import static datadog.trace.bootstrap.instrumentation.api.Tags.*;
57

68
import datadog.trace.api.Config;
@@ -53,6 +55,8 @@ public class JDBCDecorator extends DatabaseClientDecorator<DBInfo> {
5355
|| DBM_PROPAGATION_MODE.equals(DBM_PROPAGATION_MODE_STATIC);
5456
private static final boolean INJECT_TRACE_CONTEXT =
5557
DBM_PROPAGATION_MODE.equals(DBM_PROPAGATION_MODE_FULL);
58+
public static final boolean DBM_TRACE_PREPARED_STATEMENTS =
59+
Config.get().isDBMTracePreparedStatements();
5660

5761
private volatile boolean warnedAboutDBMPropagationMode = false; // to log a warning only once
5862

@@ -248,6 +252,10 @@ public String traceParent(AgentSpan span, int samplingPriority) {
248252
return sb.toString();
249253
}
250254

255+
public boolean isPostgres(final DBInfo dbInfo) {
256+
return dbInfo.getType().startsWith("postgres");
257+
}
258+
251259
public boolean isSqlServer(final DBInfo dbInfo) {
252260
return "sqlserver".equals(dbInfo.getType());
253261
}
@@ -312,6 +320,44 @@ public long setContextInfo(Connection connection, DBInfo dbInfo) {
312320
return spanID;
313321
}
314322

323+
/**
324+
* Executes `SET application_name` statement on the Postgres DB to set the trace parent in
325+
* `pg_stat_activity.application_name`. This is used for prepared statements where it isn't
326+
* possible to propagate trace parent with the comment. Downside: makes an additional round trip
327+
* to the database.
328+
*
329+
* @param span The span of the instrumented statement
330+
* @param connection The same connection as the one that will be used for the actual statement
331+
*/
332+
public void setApplicationName(AgentSpan span, Connection connection) {
333+
final long startTime = System.currentTimeMillis();
334+
try {
335+
336+
Integer priority = span.forceSamplingDecision();
337+
if (priority == null) {
338+
return;
339+
}
340+
final String traceParent = DECORATE.traceParent(span, priority);
341+
final String traceContext = "_DD_" + traceParent;
342+
343+
connection.setClientInfo("ApplicationName", traceContext);
344+
} catch (Throwable e) {
345+
if (log.isDebugEnabled()) {
346+
log.debug(
347+
"Failed to set extra DBM data in application_name for trace {}. "
348+
+ "To disable this behavior, set trace_prepared_statements to 'false'. "
349+
+ "See https://docs.datadoghq.com/database_monitoring/connect_dbm_and_apm/ for more info.{}",
350+
span.getTraceId().toHexString(),
351+
e);
352+
}
353+
DECORATE.onError(span, e);
354+
} finally {
355+
span.setTag(DBM_TRACE_INJECTED, true);
356+
final long elapsed = System.currentTimeMillis() - startTime;
357+
span.setTag(INSTRUMENTATION_TIME_MS, elapsed);
358+
}
359+
}
360+
315361
@Override
316362
protected void postProcessServiceAndOperationName(
317363
AgentSpan span, DatabaseClientDecorator.NamingEntry namingEntry) {

0 commit comments

Comments
 (0)