Skip to content

Commit 536afa5

Browse files
committed
Fix Mongo stable DB span names
1 parent 90944e7 commit 536afa5

9 files changed

Lines changed: 138 additions & 108 deletions

File tree

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/DbClientAttributesExtractor.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,13 @@ public final class DbClientAttributesExtractor<REQUEST, RESPONSE>
5454
private final DbClientAttributesGetter<REQUEST, RESPONSE> getter;
5555
private final InternalNetworkAttributesExtractor<REQUEST, RESPONSE> internalNetworkExtractor;
5656
private final ServerAttributesExtractor<REQUEST, RESPONSE> serverAttributesExtractor;
57+
@Nullable private final AttributeKey<String> oldSemconvCollectionAttribute;
5758
private final boolean captureQueryParameters;
5859

5960
/** Creates the database client attributes extractor with default configuration. */
6061
public static <REQUEST, RESPONSE> AttributesExtractor<REQUEST, RESPONSE> create(
6162
DbClientAttributesGetter<REQUEST, RESPONSE> getter) {
62-
return new DbClientAttributesExtractor<>(getter, false);
63+
return new DbClientAttributesExtractor<>(getter, null, false);
6364
}
6465

6566
/**
@@ -72,8 +73,11 @@ public static <REQUEST, RESPONSE> DbClientAttributesExtractorBuilder<REQUEST, RE
7273
}
7374

7475
DbClientAttributesExtractor(
75-
DbClientAttributesGetter<REQUEST, RESPONSE> getter, boolean captureQueryParameters) {
76+
DbClientAttributesGetter<REQUEST, RESPONSE> getter,
77+
@Nullable AttributeKey<String> oldSemconvCollectionAttribute,
78+
boolean captureQueryParameters) {
7679
this.getter = getter;
80+
this.oldSemconvCollectionAttribute = oldSemconvCollectionAttribute;
7781
this.captureQueryParameters = captureQueryParameters;
7882
internalNetworkExtractor =
7983
new InternalNetworkAttributesExtractor<>(getter, emitOldDatabaseSemconv(), false);
@@ -84,6 +88,9 @@ public static <REQUEST, RESPONSE> DbClientAttributesExtractorBuilder<REQUEST, RE
8488
@Override
8589
public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST request) {
8690
onStartCommon(attributes, getter, request, captureQueryParameters);
91+
if (emitOldDatabaseSemconv() && oldSemconvCollectionAttribute != null) {
92+
attributes.put(oldSemconvCollectionAttribute, getter.getDbCollectionName(request));
93+
}
8794
serverAttributesExtractor.onStart(attributes, parentContext, request);
8895
}
8996

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/DbClientAttributesExtractorBuilder.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,35 @@
66
package io.opentelemetry.instrumentation.api.incubator.semconv.db;
77

88
import com.google.errorprone.annotations.CanIgnoreReturnValue;
9+
import io.opentelemetry.api.common.AttributeKey;
910
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
11+
import javax.annotation.Nullable;
1012

1113
/** A builder of {@link DbClientAttributesExtractor}. */
1214
public final class DbClientAttributesExtractorBuilder<REQUEST, RESPONSE> {
1315

1416
final DbClientAttributesGetter<REQUEST, RESPONSE> getter;
17+
@Nullable AttributeKey<String> oldSemconvCollectionAttribute;
1518
boolean captureQueryParameters = false;
1619

1720
DbClientAttributesExtractorBuilder(DbClientAttributesGetter<REQUEST, RESPONSE> getter) {
1821
this.getter = getter;
1922
}
2023

24+
/**
25+
* Sets the attribute key for the old semconv collection attribute. Pass {@code null} to disable
26+
* emitting any collection attribute under old semconv.
27+
*
28+
* @deprecated new semantic conventions always use db.collection.name
29+
*/
30+
@CanIgnoreReturnValue
31+
@Deprecated // to be removed in 3.0
32+
public DbClientAttributesExtractorBuilder<REQUEST, RESPONSE> setOldSemconvCollectionAttribute(
33+
@Nullable AttributeKey<String> oldSemconvCollectionAttribute) {
34+
this.oldSemconvCollectionAttribute = oldSemconvCollectionAttribute;
35+
return this;
36+
}
37+
2138
/**
2239
* Sets whether the query parameters should be captured as span attributes named {@code
2340
* db.query.parameter.<key>}. Disabled by default.
@@ -37,6 +54,7 @@ public DbClientAttributesExtractorBuilder<REQUEST, RESPONSE> setCaptureQueryPara
3754
* DbClientAttributesExtractorBuilder}.
3855
*/
3956
public AttributesExtractor<REQUEST, RESPONSE> build() {
40-
return new DbClientAttributesExtractor<>(getter, captureQueryParameters);
57+
return new DbClientAttributesExtractor<>(
58+
getter, oldSemconvCollectionAttribute, captureQueryParameters);
4159
}
4260
}

instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/db/DbClientAttributesExtractorTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import static java.util.Collections.emptyMap;
2424
import static org.assertj.core.api.Assertions.entry;
2525

26+
import io.opentelemetry.api.common.AttributeKey;
2627
import io.opentelemetry.api.common.Attributes;
2728
import io.opentelemetry.api.common.AttributesBuilder;
2829
import io.opentelemetry.context.Context;
@@ -34,6 +35,9 @@
3435

3536
class DbClientAttributesExtractorTest {
3637

38+
private static final AttributeKey<String> DB_OLD_COLLECTION =
39+
AttributeKey.stringKey("db.old.collection");
40+
3741
static class TestAttributesGetter implements DbClientAttributesGetter<Map<String, String>, Void> {
3842
@Override
3943
public String getDbSystemName(Map<String, String> map) {
@@ -85,6 +89,33 @@ public String getDbOperation(Map<String, String> map) {
8589
}
8690
}
8791

92+
@SuppressWarnings("deprecation") // until old db semconv are dropped
93+
@Test
94+
void shouldExtractConfiguredOldCollectionAttribute() {
95+
// given
96+
Map<String, String> request = new HashMap<>();
97+
request.put("db.collection.name", "potato");
98+
99+
AttributesExtractor<Map<String, String>, Void> underTest =
100+
DbClientAttributesExtractor.builder(new TestAttributesGetter())
101+
.setOldSemconvCollectionAttribute(DB_OLD_COLLECTION)
102+
.build();
103+
104+
// when
105+
AttributesBuilder attributes = Attributes.builder();
106+
underTest.onStart(attributes, Context.root(), request);
107+
108+
// then
109+
if (emitStableDatabaseSemconv() && emitOldDatabaseSemconv()) {
110+
assertThat(attributes.build())
111+
.containsOnly(entry(DB_OLD_COLLECTION, "potato"), entry(DB_COLLECTION_NAME, "potato"));
112+
} else if (emitOldDatabaseSemconv()) {
113+
assertThat(attributes.build()).containsOnly(entry(DB_OLD_COLLECTION, "potato"));
114+
} else if (emitStableDatabaseSemconv()) {
115+
assertThat(attributes.build()).containsOnly(entry(DB_COLLECTION_NAME, "potato"));
116+
}
117+
}
118+
88119
@SuppressWarnings("deprecation") // TODO DB_CONNECTION_STRING deprecation
89120
@Test
90121
void shouldExtractAllAvailableAttributes() {

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

Lines changed: 0 additions & 84 deletions
This file was deleted.

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: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import com.mongodb.event.CommandStartedEvent;
1111
import io.opentelemetry.api.OpenTelemetry;
12+
import io.opentelemetry.api.common.AttributeKey;
1213
import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientAttributesExtractor;
1314
import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientMetrics;
1415
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
@@ -22,6 +23,10 @@
2223
*/
2324
public final class MongoInstrumenterFactory {
2425

26+
// copied from DbIncubatingAttributes
27+
private static final AttributeKey<String> DB_MONGODB_COLLECTION =
28+
AttributeKey.stringKey("db.mongodb.collection");
29+
2530
static final int DEFAULT_MAX_NORMALIZED_QUERY_LENGTH = 32 * 1024;
2631

2732
public static Instrumenter<CommandStartedEvent, Void> createInstrumenter(
@@ -33,23 +38,25 @@ public static Instrumenter<CommandStartedEvent, Void> createInstrumenter(
3338
DEFAULT_MAX_NORMALIZED_QUERY_LENGTH);
3439
}
3540

41+
@SuppressWarnings("deprecation") // to support old database semantic conventions
3642
public static Instrumenter<CommandStartedEvent, Void> createInstrumenter(
3743
OpenTelemetry openTelemetry,
3844
String instrumentationName,
3945
boolean querySanitizationEnabled,
4046
int maxNormalizedQueryLength) {
4147

42-
MongoAttributesExtractor attributesExtractor = new MongoAttributesExtractor();
4348
MongoDbAttributesGetter dbAttributesGetter =
4449
new MongoDbAttributesGetter(querySanitizationEnabled, maxNormalizedQueryLength);
4550
SpanNameExtractor<CommandStartedEvent> spanNameExtractor =
46-
new MongoSpanNameExtractor(dbAttributesGetter, attributesExtractor);
51+
new MongoSpanNameExtractor(dbAttributesGetter);
4752

4853
InstrumenterBuilder<CommandStartedEvent, Void> builder =
4954
Instrumenter.<CommandStartedEvent, Void>builder(
5055
openTelemetry, instrumentationName, spanNameExtractor)
51-
.addAttributesExtractor(DbClientAttributesExtractor.create(dbAttributesGetter))
52-
.addAttributesExtractor(attributesExtractor)
56+
.addAttributesExtractor(
57+
DbClientAttributesExtractor.builder(dbAttributesGetter)
58+
.setOldSemconvCollectionAttribute(DB_MONGODB_COLLECTION)
59+
.build())
5360
.addOperationMetrics(DbClientMetrics.get());
5461
setDbClientExceptionEventExtractor(builder);
5562
return builder.buildInstrumenter(SpanKindExtractor.alwaysClient());

0 commit comments

Comments
 (0)