Skip to content

Commit ee8f5a0

Browse files
Yoonena-ji
authored andcommitted
PR comments: build traceparent incl. sampling flag, exception logging
1 parent dfa23a6 commit ee8f5a0

File tree

3 files changed

+200
-6
lines changed

3 files changed

+200
-6
lines changed

dd-java-agent/instrumentation/mongo/common/src/main/java/datadog/trace/instrumentation/mongo/MongoCommentInjector.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ public static BsonDocument injectComment(String dbmComment, CommandStartedEvent
4646
log.warn(
4747
"Linking Database Monitoring profiles to spans is not supported for the following query type: {}. "
4848
+ "To disable this feature please set the following environment variable: DD_DBM_PROPAGATION_MODE=disabled",
49-
event.getCommand().getClass().getSimpleName(),
50-
e);
49+
event.getCommand().getClass().getSimpleName());
5150
return event.getCommand();
5251
}
5352
}
@@ -115,9 +114,12 @@ private static String getHostnameFromEvent(CommandStartedEvent event) {
115114

116115
private static String buildTraceParent(AgentSpan span) {
117116
// W3C traceparent format: version-traceId-spanId-flags
118-
String traceIdHex = span.getTraceId().toHexStringPadded(32);
119-
String spanIdHex = String.format("%016x", span.getSpanId());
120-
String flags = "00"; // '01' if sampled, '00' if not
121-
return String.format("00-%s-%s-%s", traceIdHex, spanIdHex, flags);
117+
StringBuilder sb = new StringBuilder(2 + 1 + 32 + 1 + 16 + 1 + 2);
118+
sb.append("00-"); // version
119+
sb.append(span.getTraceId().toHexStringPadded(32)); // traceId
120+
sb.append("-");
121+
sb.append(String.format("%016x", span.getSpanId())); // spanId
122+
sb.append(span.context().getSamplingPriority() > 0 ? "-01" : "-00");
123+
return sb.toString();
122124
}
123125
}

dd-java-agent/instrumentation/mongo/common/src/test/groovy/MongoCommentInjectorTest.groovy

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package datadog.trace.instrumentation.mongo
22

33
import datadog.trace.agent.test.InstrumentationSpecification
44
import datadog.trace.api.config.TraceInstrumentationConfig
5+
import datadog.trace.api.sampling.PrioritySampling
56
import org.bson.BsonDocument
67
import org.bson.BsonString
78

@@ -25,6 +26,66 @@ class MongoCommentInjectorTest extends InstrumentationSpecification {
2526
comment == null
2627
}
2728

29+
def "getComment with full mode builds traceParent in W3C format with sampled flag"() {
30+
setup:
31+
// Set the propagation mode to full to trigger buildTraceParent call
32+
injectSysConfig("dd." + TraceInstrumentationConfig.DB_DBM_PROPAGATION_MODE_MODE, "full")
33+
def span = TEST_TRACER.buildSpan("test-op").start()
34+
span.setSamplingPriority(PrioritySampling.SAMPLER_KEEP, 0)
35+
36+
// Create a mock event
37+
def event = Mock(com.mongodb.event.CommandStartedEvent) {
38+
getDatabaseName() >> "testdb"
39+
getConnectionDescription() >> Mock(com.mongodb.connection.ConnectionDescription) {
40+
getServerAddress() >> Mock(com.mongodb.ServerAddress) {
41+
getHost() >> "localhost"
42+
}
43+
}
44+
}
45+
46+
when:
47+
String comment = MongoCommentInjector.getComment(span, event)
48+
49+
then:
50+
comment != null
51+
comment.contains("dddbs='test-mongo-service'")
52+
comment.contains("dde='test'")
53+
comment.contains("ddh='localhost'")
54+
comment.contains("dddb='testdb'")
55+
// W3C traceparent format: 00-{32 hex chars}-{16 hex chars}-01 (sampled)
56+
comment ==~ /.*ddtp='00-[0-9a-f]{32}-[0-9a-f]{16}-01'.*/
57+
}
58+
59+
def "getComment with full mode builds traceParent in W3C format with not sampled flag"() {
60+
setup:
61+
// Set the propagation mode to full to trigger buildTraceParent call
62+
injectSysConfig("dd." + TraceInstrumentationConfig.DB_DBM_PROPAGATION_MODE_MODE, "full")
63+
def span = TEST_TRACER.buildSpan("test-op").start()
64+
span.setSamplingPriority(PrioritySampling.SAMPLER_DROP, 0)
65+
66+
// Create a mock event
67+
def event = Mock(com.mongodb.event.CommandStartedEvent) {
68+
getDatabaseName() >> "testdb"
69+
getConnectionDescription() >> Mock(com.mongodb.connection.ConnectionDescription) {
70+
getServerAddress() >> Mock(com.mongodb.ServerAddress) {
71+
getHost() >> "localhost"
72+
}
73+
}
74+
}
75+
76+
when:
77+
String comment = MongoCommentInjector.getComment(span, event)
78+
79+
then:
80+
comment != null
81+
comment.contains("dddbs='test-mongo-service'")
82+
comment.contains("dde='test'")
83+
comment.contains("ddh='localhost'")
84+
comment.contains("dddb='testdb'")
85+
// W3C traceparent format: 00-{32 hex chars}-{16 hex chars}-00 (not sampled)
86+
comment ==~ /.*ddtp='00-[0-9a-f]{32}-[0-9a-f]{16}-00'.*/
87+
}
88+
2889
def "injectComment returns null when event is null"() {
2990
when:
3091
BsonDocument result = MongoCommentInjector.injectComment("test-comment", null)

dd-java-agent/instrumentation/mongo/driver-3.1/src/test/groovy/MongoJava31ClientTest.groovy

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,20 @@ import com.mongodb.event.CommandFailedEvent
88
import com.mongodb.event.CommandListener
99
import com.mongodb.event.CommandStartedEvent
1010
import com.mongodb.event.CommandSucceededEvent
11+
import datadog.trace.api.sampling.PrioritySampling
12+
import datadog.trace.bootstrap.instrumentation.api.AgentSpan
1113
import datadog.trace.core.DDSpan
1214
import org.bson.BsonDocument
1315
import org.bson.BsonString
1416
import org.bson.Document
1517
import spock.lang.Shared
1618

19+
import java.util.concurrent.ConcurrentLinkedQueue
20+
1721
import static datadog.trace.agent.test.utils.PortUtils.UNUSABLE_PORT
1822
import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace
1923
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_CLIENT_HOST_SPLIT_BY_INSTANCE
24+
import static datadog.trace.api.config.TraceInstrumentationConfig.DB_DBM_PROPAGATION_MODE_MODE
2025
import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan
2126

2227
abstract class MongoJava31ClientTest extends MongoBaseTest {
@@ -231,6 +236,132 @@ abstract class MongoJava31ClientTest extends MongoBaseTest {
231236
// Unfortunately not caught by our instrumentation.
232237
assertTraces(0) {}
233238
}
239+
240+
def "test DBM propagation with sampled flag"() {
241+
setup:
242+
injectSysConfig("dd." + DB_DBM_PROPAGATION_MODE_MODE, "full")
243+
injectSysConfig("service.name", "test-mongo-service")
244+
injectSysConfig("dd.env", "test")
245+
246+
String collectionName = randomCollectionName()
247+
def capturedEvents = new ConcurrentLinkedQueue<CommandStartedEvent>()
248+
249+
def dbmClient = new MongoClient(new ServerAddress(mongoDbContainer.getHost(), port),
250+
MongoClientOptions.builder()
251+
.description("dbm-test-client")
252+
.addCommandListener(new CommandListener() {
253+
@Override
254+
void commandStarted(CommandStartedEvent event) {
255+
capturedEvents.add(event)
256+
}
257+
258+
@Override
259+
void commandSucceeded(CommandSucceededEvent event) {}
260+
261+
@Override
262+
void commandFailed(CommandFailedEvent event) {}
263+
})
264+
.build())
265+
266+
DDSpan setupSpan = null
267+
MongoCollection<Document> collection = runUnderTrace("setup") {
268+
setupSpan = activeSpan() as DDSpan
269+
MongoDatabase db = dbmClient.getDatabase(databaseName)
270+
db.createCollection(collectionName)
271+
return db.getCollection(collectionName)
272+
}
273+
TEST_WRITER.waitUntilReported(setupSpan)
274+
TEST_WRITER.clear()
275+
capturedEvents.clear()
276+
277+
when:
278+
runUnderTrace("dbm-test") {
279+
AgentSpan span = activeSpan() as AgentSpan
280+
span.setSamplingPriority(PrioritySampling.SAMPLER_KEEP, 0)
281+
collection.insertOne(new Document("test", "value"))
282+
}
283+
284+
then:
285+
// Find the insert command event
286+
def insertEvent = capturedEvents.find { it.commandName == "insert" }
287+
insertEvent != null
288+
def command = insertEvent.command
289+
command.containsKey('$comment')
290+
def comment = command.getString('$comment').value
291+
292+
// Verify comment contains DBM tags
293+
comment.contains("dddbs='test-mongo-service'")
294+
comment.contains("dde='test'")
295+
296+
// Verify traceparent has sampled flag (01)
297+
comment ==~ /.*ddtp='00-[0-9a-f]{32}-[0-9a-f]{16}-01'.*/
298+
299+
cleanup:
300+
dbmClient?.close()
301+
}
302+
303+
def "test DBM propagation with not sampled flag"() {
304+
setup:
305+
injectSysConfig("dd." + DB_DBM_PROPAGATION_MODE_MODE, "full")
306+
injectSysConfig("service.name", "test-mongo-service")
307+
injectSysConfig("dd.env", "test")
308+
309+
String collectionName = randomCollectionName()
310+
def capturedEvents = new ConcurrentLinkedQueue<CommandStartedEvent>()
311+
312+
def dbmClient = new MongoClient(new ServerAddress(mongoDbContainer.getHost(), port),
313+
MongoClientOptions.builder()
314+
.description("dbm-test-client")
315+
.addCommandListener(new CommandListener() {
316+
@Override
317+
void commandStarted(CommandStartedEvent event) {
318+
capturedEvents.add(event)
319+
}
320+
321+
@Override
322+
void commandSucceeded(CommandSucceededEvent event) {}
323+
324+
@Override
325+
void commandFailed(CommandFailedEvent event) {}
326+
})
327+
.build())
328+
329+
DDSpan setupSpan = null
330+
MongoCollection<Document> collection = runUnderTrace("setup") {
331+
setupSpan = activeSpan() as DDSpan
332+
MongoDatabase db = dbmClient.getDatabase(databaseName)
333+
db.createCollection(collectionName)
334+
return db.getCollection(collectionName)
335+
}
336+
TEST_WRITER.waitUntilReported(setupSpan)
337+
TEST_WRITER.clear()
338+
capturedEvents.clear()
339+
340+
when:
341+
runUnderTrace("dbm-test") {
342+
AgentSpan span = activeSpan() as AgentSpan
343+
span.setSamplingPriority(PrioritySampling.SAMPLER_DROP, 0)
344+
collection.insertOne(new Document("test", "value"))
345+
}
346+
347+
then:
348+
// Find the insert command event
349+
def insertEvent = capturedEvents.find { it.commandName == "insert" }
350+
insertEvent != null
351+
def command = insertEvent.command
352+
command.containsKey('$comment')
353+
def comment = command.getString('$comment').value
354+
355+
// Verify comment contains DBM tags
356+
comment.contains("dddbs='test-mongo-service'")
357+
comment.contains("dde='test'")
358+
359+
// Verify traceparent has not sampled flag (00)
360+
comment ==~ /.*ddtp='00-[0-9a-f]{32}-[0-9a-f]{16}-00'.*/
361+
362+
cleanup:
363+
dbmClient?.close()
364+
}
234365
}
235366

236367
class MongoJava31ClientV0Test extends MongoJava31ClientTest {

0 commit comments

Comments
 (0)