Skip to content

Commit 4593933

Browse files
authored
Fix Mongo stable DB span names (#18987)
1 parent 65a62d0 commit 4593933

7 files changed

Lines changed: 94 additions & 71 deletions

File tree

instrumentation/kafka/kafka-connect-2.6/testing/src/test/java/io/opentelemetry/instrumentation/kafkaconnect/v2_6/MongoKafkaConnectSinkTaskTest.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package io.opentelemetry.instrumentation.kafkaconnect.v2_6;
77

88
import static io.opentelemetry.api.trace.SpanKind.CONSUMER;
9+
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
910
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
1011
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
1112
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_BATCH_MESSAGE_COUNT;
@@ -157,7 +158,10 @@ void testSingleMessage() throws IOException {
157158
satisfies(THREAD_ID, val -> val.isNotZero()),
158159
satisfies(THREAD_NAME, val -> val.isNotBlank())),
159160
span ->
160-
span.hasName("update " + DATABASE_NAME + "." + COLLECTION_NAME)
161+
span.hasName(
162+
emitStableDatabaseSemconv()
163+
? "update " + COLLECTION_NAME
164+
: "update " + DATABASE_NAME + "." + COLLECTION_NAME)
161165
.hasKind(SpanKind.CLIENT)
162166
.hasParent(trace.getSpan(0))),
163167
trace ->
@@ -268,15 +272,24 @@ void testMultiTopic() throws IOException {
268272
satisfies(THREAD_ID, val -> val.isNotZero()),
269273
satisfies(THREAD_NAME, val -> val.isNotBlank())),
270274
span ->
271-
span.hasName("update " + DATABASE_NAME + "." + COLLECTION_NAME)
275+
span.hasName(
276+
emitStableDatabaseSemconv()
277+
? "update " + COLLECTION_NAME
278+
: "update " + DATABASE_NAME + "." + COLLECTION_NAME)
272279
.hasKind(SpanKind.CLIENT)
273280
.hasParent(trace.getSpan(0)),
274281
span ->
275-
span.hasName("update " + DATABASE_NAME + "." + COLLECTION_NAME)
282+
span.hasName(
283+
emitStableDatabaseSemconv()
284+
? "update " + COLLECTION_NAME
285+
: "update " + DATABASE_NAME + "." + COLLECTION_NAME)
276286
.hasKind(SpanKind.CLIENT)
277287
.hasParent(trace.getSpan(0)),
278288
span ->
279-
span.hasName("update " + DATABASE_NAME + "." + COLLECTION_NAME)
289+
span.hasName(
290+
emitStableDatabaseSemconv()
291+
? "update " + COLLECTION_NAME
292+
: "update " + DATABASE_NAME + "." + COLLECTION_NAME)
280293
.hasKind(SpanKind.CLIENT)
281294
.hasParent(trace.getSpan(0))),
282295
trace ->

instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/internal/MongoAttributesExtractor.java

Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,31 @@
66
package io.opentelemetry.instrumentation.mongo.v3_1.internal;
77

88
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitOldDatabaseSemconv;
9-
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
10-
import static io.opentelemetry.semconv.DbAttributes.DB_COLLECTION_NAME;
11-
import static java.util.Arrays.asList;
129

1310
import com.mongodb.event.CommandStartedEvent;
1411
import io.opentelemetry.api.common.AttributeKey;
1512
import io.opentelemetry.api.common.AttributesBuilder;
1613
import io.opentelemetry.context.Context;
1714
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
18-
import java.util.HashSet;
19-
import java.util.Set;
2015
import javax.annotation.Nullable;
21-
import org.bson.BsonValue;
2216

2317
class MongoAttributesExtractor implements AttributesExtractor<CommandStartedEvent, Void> {
18+
2419
// copied from DbIncubatingAttributes
2520
private static final AttributeKey<String> DB_MONGODB_COLLECTION =
2621
AttributeKey.stringKey("db.mongodb.collection");
2722

28-
private static final Set<String> COMMANDS_WITH_COLLECTION_NAME_AS_VALUE =
29-
new HashSet<>(
30-
asList(
31-
"aggregate",
32-
"count",
33-
"distinct",
34-
"mapReduce",
35-
"geoSearch",
36-
"delete",
37-
"find",
38-
"killCursors",
39-
"findAndModify",
40-
"insert",
41-
"update",
42-
"create",
43-
"drop",
44-
"createIndexes",
45-
"listIndexes"));
23+
private final MongoDbAttributesGetter getter;
24+
25+
MongoAttributesExtractor(MongoDbAttributesGetter getter) {
26+
this.getter = getter;
27+
}
4628

4729
@Override
4830
public void onStart(
4931
AttributesBuilder attributes, Context parentContext, CommandStartedEvent event) {
50-
String collectionName = collectionName(event);
51-
if (emitStableDatabaseSemconv()) {
52-
attributes.put(DB_COLLECTION_NAME, collectionName);
53-
}
5432
if (emitOldDatabaseSemconv()) {
55-
attributes.put(DB_MONGODB_COLLECTION, collectionName);
33+
attributes.put(DB_MONGODB_COLLECTION, getter.getDbCollectionName(event));
5634
}
5735
}
5836

@@ -63,22 +41,4 @@ public void onEnd(
6341
CommandStartedEvent event,
6442
@Nullable Void unused,
6543
@Nullable Throwable error) {}
66-
67-
@Nullable
68-
String collectionName(CommandStartedEvent event) {
69-
if (event.getCommandName().equals("getMore")) {
70-
BsonValue collectionValue = event.getCommand().get("collection");
71-
if (collectionValue != null) {
72-
if (collectionValue.isString()) {
73-
return collectionValue.asString().getValue();
74-
}
75-
}
76-
} else if (COMMANDS_WITH_COLLECTION_NAME_AS_VALUE.contains(event.getCommandName())) {
77-
BsonValue commandValue = event.getCommand().get(event.getCommandName());
78-
if (commandValue != null && commandValue.isString()) {
79-
return commandValue.asString().getValue();
80-
}
81-
}
82-
return null;
83-
}
8444
}

instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/internal/MongoDbAttributesGetter.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
package io.opentelemetry.instrumentation.mongo.v3_1.internal;
77

8+
import static java.util.Arrays.asList;
9+
810
import com.mongodb.MongoException;
911
import com.mongodb.ServerAddress;
1012
import com.mongodb.connection.ConnectionDescription;
@@ -13,8 +15,10 @@
1315
import java.lang.reflect.InvocationTargetException;
1416
import java.lang.reflect.Method;
1517
import java.util.Arrays;
18+
import java.util.HashSet;
1619
import java.util.Map;
1720
import java.util.Optional;
21+
import java.util.Set;
1822
import javax.annotation.Nullable;
1923
import org.bson.BsonArray;
2024
import org.bson.BsonDocument;
@@ -29,8 +33,27 @@ class MongoDbAttributesGetter implements DbClientAttributesGetter<CommandStarted
2933
// copied from DbIncubatingAttributes.DbSystemNameIncubatingValues
3034
private static final String MONGODB = "mongodb";
3135

32-
@Nullable private static final Method IS_TRUNCATED_METHOD;
3336
private static final String HIDDEN_CHAR = "?";
37+
private static final Set<String> COMMANDS_WITH_COLLECTION_NAME_AS_VALUE =
38+
new HashSet<>(
39+
asList(
40+
"aggregate",
41+
"count",
42+
"distinct",
43+
"mapReduce",
44+
"geoSearch",
45+
"delete",
46+
"find",
47+
"killCursors",
48+
"findAndModify",
49+
"insert",
50+
"update",
51+
"create",
52+
"drop",
53+
"createIndexes",
54+
"listIndexes"));
55+
56+
@Nullable private static final Method IS_TRUNCATED_METHOD;
3457

3558
static {
3659
IS_TRUNCATED_METHOD =
@@ -61,6 +84,25 @@ public String getDbNamespace(CommandStartedEvent event) {
6184
return event.getDatabaseName();
6285
}
6386

87+
@Override
88+
@Nullable
89+
public String getDbCollectionName(CommandStartedEvent event) {
90+
if (event.getCommandName().equals("getMore")) {
91+
BsonValue collectionValue = event.getCommand().get("collection");
92+
if (collectionValue != null) {
93+
if (collectionValue.isString()) {
94+
return collectionValue.asString().getValue();
95+
}
96+
}
97+
} else if (COMMANDS_WITH_COLLECTION_NAME_AS_VALUE.contains(event.getCommandName())) {
98+
BsonValue commandValue = event.getCommand().get(event.getCommandName());
99+
if (commandValue != null && commandValue.isString()) {
100+
return commandValue.asString().getValue();
101+
}
102+
}
103+
return null;
104+
}
105+
64106
@Deprecated // to be removed in 3.0
65107
@Override
66108
@Nullable

instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/internal/MongoInstrumenterFactory.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,16 @@ public static Instrumenter<CommandStartedEvent, Void> createInstrumenter(
3939
boolean querySanitizationEnabled,
4040
int maxNormalizedQueryLength) {
4141

42-
MongoAttributesExtractor attributesExtractor = new MongoAttributesExtractor();
4342
MongoDbAttributesGetter dbAttributesGetter =
4443
new MongoDbAttributesGetter(querySanitizationEnabled, maxNormalizedQueryLength);
4544
SpanNameExtractor<CommandStartedEvent> spanNameExtractor =
46-
new MongoSpanNameExtractor(dbAttributesGetter, attributesExtractor);
45+
new MongoSpanNameExtractor(dbAttributesGetter);
4746

4847
InstrumenterBuilder<CommandStartedEvent, Void> builder =
4948
Instrumenter.<CommandStartedEvent, Void>builder(
5049
openTelemetry, instrumentationName, spanNameExtractor)
5150
.addAttributesExtractor(DbClientAttributesExtractor.create(dbAttributesGetter))
52-
.addAttributesExtractor(attributesExtractor)
51+
.addAttributesExtractor(new MongoAttributesExtractor(dbAttributesGetter))
5352
.addOperationMetrics(DbClientMetrics.get());
5453
setDbClientExceptionEventExtractor(builder);
5554
return builder.buildInstrumenter(SpanKindExtractor.alwaysClient());

instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/internal/MongoSpanNameExtractor.java

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,49 @@
55

66
package io.opentelemetry.instrumentation.mongo.v3_1.internal;
77

8+
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
9+
810
import com.mongodb.event.CommandStartedEvent;
11+
import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientSpanNameExtractor;
912
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
1013

1114
class MongoSpanNameExtractor implements SpanNameExtractor<CommandStartedEvent> {
1215
private static final String DEFAULT_SPAN_NAME = "DB Query";
1316

1417
private final MongoDbAttributesGetter dbAttributesGetter;
15-
private final MongoAttributesExtractor attributesExtractor;
18+
private final SpanNameExtractor<CommandStartedEvent> stableDelegate;
1619

17-
MongoSpanNameExtractor(
18-
MongoDbAttributesGetter dbAttributesGetter, MongoAttributesExtractor attributesExtractor) {
20+
MongoSpanNameExtractor(MongoDbAttributesGetter dbAttributesGetter) {
1921
this.dbAttributesGetter = dbAttributesGetter;
20-
this.attributesExtractor = attributesExtractor;
22+
stableDelegate = DbClientSpanNameExtractor.create(dbAttributesGetter);
2123
}
2224

25+
@SuppressWarnings("deprecation") // getDbName/getDbOperation are used for old semconv span names
2326
@Override
2427
public String extract(CommandStartedEvent event) {
25-
String operation = dbAttributesGetter.getDbOperationName(event);
26-
String dbName = dbAttributesGetter.getDbNamespace(event);
28+
if (emitStableDatabaseSemconv()) {
29+
return stableDelegate.extract(event);
30+
}
31+
32+
String operation = dbAttributesGetter.getDbOperation(event);
33+
String dbName = dbAttributesGetter.getDbName(event);
2734
if (operation == null) {
2835
return dbName == null ? DEFAULT_SPAN_NAME : dbName;
2936
}
3037

31-
String table = attributesExtractor.collectionName(event);
38+
String collectionName = dbAttributesGetter.getDbCollectionName(event);
3239
StringBuilder name = new StringBuilder(operation);
33-
if (dbName != null || table != null) {
40+
if (dbName != null || collectionName != null) {
3441
name.append(' ');
3542
}
36-
// skip db name if table already has a db name prefixed to it
37-
if (dbName != null && (table == null || table.indexOf('.') == -1)) {
43+
if (dbName != null && (collectionName == null || collectionName.indexOf('.') == -1)) {
3844
name.append(dbName);
39-
if (table != null) {
45+
if (collectionName != null) {
4046
name.append('.');
4147
}
4248
}
43-
if (table != null) {
44-
name.append(table);
49+
if (collectionName != null) {
50+
name.append(collectionName);
4551
}
4652
return name.toString();
4753
}

instrumentation/mongo/mongo-3.1/library/src/test/java/io/opentelemetry/instrumentation/mongo/v3_1/internal/MongoSpanNameExtractorTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ class MongoSpanNameExtractorTest {
2121
void testSpanNameWithNoDbName() {
2222
MongoSpanNameExtractor nameExtractor =
2323
new MongoSpanNameExtractor(
24-
new MongoDbAttributesGetter(true, DEFAULT_MAX_NORMALIZED_QUERY_LENGTH),
25-
new MongoAttributesExtractor());
24+
new MongoDbAttributesGetter(true, DEFAULT_MAX_NORMALIZED_QUERY_LENGTH));
2625

2726
String command = "listDatabases";
2827
CommandStartedEvent event =

instrumentation/mongo/mongo-common/testing/src/main/java/io/opentelemetry/instrumentation/mongo/testing/AbstractMongoClientTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,11 @@ void mongoSpan(
543543
String dbName,
544544
SpanData parentSpan,
545545
List<String> statements) {
546-
span.hasName(operation + " " + dbName + "." + collection).hasKind(CLIENT);
546+
span.hasName(
547+
emitStableDatabaseSemconv()
548+
? operation + " " + collection
549+
: operation + " " + dbName + "." + collection)
550+
.hasKind(CLIENT);
547551
if (parentSpan == null) {
548552
span.hasNoParent();
549553
} else {

0 commit comments

Comments
 (0)