Skip to content

Commit 90944e7

Browse files
committed
Add DB client collection semconv API
1 parent f3bc077 commit 90944e7

6 files changed

Lines changed: 102 additions & 25 deletions

File tree

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitOldDatabaseSemconv;
99
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
10+
import static io.opentelemetry.semconv.DbAttributes.DB_COLLECTION_NAME;
1011
import static io.opentelemetry.semconv.DbAttributes.DB_NAMESPACE;
1112
import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_BATCH_SIZE;
1213
import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_NAME;
@@ -99,6 +100,7 @@ static <REQUEST, RESPONSE> void onStartCommon(
99100
attributes.put(
100101
DB_SYSTEM_NAME, SemconvStability.stableDbSystemName(getter.getDbSystemName(request)));
101102
attributes.put(DB_NAMESPACE, getter.getDbNamespace(request));
103+
attributes.put(DB_COLLECTION_NAME, getter.getDbCollectionName(request));
102104
attributes.put(DB_QUERY_TEXT, getter.getDbQueryText(request));
103105
attributes.put(DB_OPERATION_NAME, getter.getDbOperationName(request));
104106
attributes.put(DB_QUERY_SUMMARY, getter.getDbQuerySummary(request));
@@ -112,7 +114,7 @@ static <REQUEST, RESPONSE> void onStartCommon(
112114
attributes.put(DB_NAME, getter.getDbName(request));
113115
attributes.put(DB_CONNECTION_STRING, getter.getConnectionString(request));
114116
attributes.put(DB_STATEMENT, getter.getDbQueryText(request));
115-
attributes.put(DB_OPERATION, getter.getDbOperationName(request));
117+
attributes.put(DB_OPERATION, getter.getDbOperation(request));
116118
}
117119

118120
// Query parameters are an incubating feature and work with both old and new semconv

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ default String getDbQuerySummary(REQUEST request) {
3838
@Nullable
3939
String getDbOperationName(REQUEST request);
4040

41+
/**
42+
* Returns the old db.operation value. This is only used for old semantic conventions.
43+
*
44+
* @deprecated Use {@link #getDbOperationName(Object)} instead.
45+
*/
46+
@Deprecated // to be removed in 3.0
47+
@Nullable
48+
default String getDbOperation(REQUEST request) {
49+
return getDbOperationName(request);
50+
}
51+
4152
// TODO: make this required to implement
4253
String getDbSystemName(REQUEST request);
4354

@@ -59,6 +70,12 @@ default String getDbSystem(REQUEST request) {
5970
@Nullable
6071
String getDbNamespace(REQUEST request);
6172

73+
// TODO: make this required to implement?
74+
@Nullable
75+
default String getDbCollectionName(REQUEST request) {
76+
return null;
77+
}
78+
6279
/**
6380
* Returns the old db.name value. This is only used for old semantic conventions.
6481
*

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

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,9 @@ private static <REQUEST> String computeSpanNameStable(
106106
DbClientAttributesGetter<REQUEST, ?> getter,
107107
REQUEST request,
108108
@Nullable String operation,
109-
@Nullable String collectionName,
110109
@Nullable String storedProcedureName) {
111110

112-
String target = collectionName;
111+
String target = getter.getDbCollectionName(request);
113112
if (target == null) {
114113
target = storedProcedureName;
115114
}
@@ -164,10 +163,10 @@ public String extract(REQUEST request) {
164163
return querySummary;
165164
}
166165
String operationName = getter.getDbOperationName(request);
167-
return computeSpanNameStable(getter, request, operationName, null, null);
166+
return computeSpanNameStable(getter, request, operationName, null);
168167
}
169168
String dbName = getter.getDbName(request);
170-
String operationName = getter.getDbOperationName(request);
169+
String operationName = getter.getDbOperation(request);
171170
return computeSpanName(dbName, operationName, null, null);
172171
}
173172
}
@@ -193,11 +192,10 @@ public String extract(REQUEST request) {
193192
if (querySummary != null) {
194193
return querySummary;
195194
}
196-
String operationName = getter.getDbOperationName(request);
197-
return computeSpanNameStable(getter, request, operationName, null, null);
195+
return computeSpanNameStable(getter, request, null, null);
198196
}
199197
String dbName = getter.getDbName(request);
200-
String operationName = getter.getDbOperationName(request);
198+
String operationName = getter.getDbOperation(request);
201199
return computeSpanName(dbName, operationName, null, null);
202200
}
203201

@@ -224,16 +222,15 @@ public String extract(REQUEST request) {
224222
return batch ? "BATCH " + querySummary : querySummary;
225223
}
226224
return computeSpanNameStable(
227-
getter, request, batch ? "BATCH" : null, null, analyzedQuery.getStoredProcedureName());
225+
getter, request, batch ? "BATCH" : null, analyzedQuery.getStoredProcedureName());
228226
}
229227

230228
MultiQuery multiQuery = MultiQuery.analyzeWithSummary(rawQueryTexts, dialect);
231229
String querySummary = multiQuery.getQuerySummary();
232230
if (querySummary != null) {
233231
return querySummary;
234232
}
235-
return computeSpanNameStable(
236-
getter, request, null, null, multiQuery.getStoredProcedureName());
233+
return computeSpanNameStable(getter, request, null, multiQuery.getStoredProcedureName());
237234
}
238235

239236
private boolean isBatch(REQUEST request) {
@@ -277,7 +274,7 @@ public String extract(REQUEST request) {
277274
operationName = analyzedQuery.getOperationName();
278275
}
279276
if (operationName == null) {
280-
operationName = getter.getDbOperationName(request);
277+
operationName = getter.getDbOperation(request);
281278
}
282279
return computeSpanName(dbName, operationName, null, null);
283280
}

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ public interface SqlClientAttributesGetter<REQUEST, RESPONSE>
2323
extends DbClientAttributesGetter<REQUEST, RESPONSE> {
2424

2525
/**
26-
* SqlClientAttributesExtractor will try to populate db.operation.name based on {@link
27-
* #getRawQueryTexts(REQUEST)}, but this can be used to explicitly provide the operation name.
26+
* DO NOT USE OR OVERRIDE THIS METHOD.
27+
*
28+
* <p>{@link SqlClientAttributesExtractor} will try to populate {@code db.operation.name} based on
29+
* {@link #getRawQueryTexts(REQUEST)} when {@link
30+
* SqlClientAttributesExtractorBuilder#setSingleOperationAndCollection(boolean)} is enabled.
2831
*/
2932
@Override
3033
@Nullable
@@ -52,6 +55,19 @@ default String getDbQuerySummary(REQUEST request) {
5255
return null;
5356
}
5457

58+
/**
59+
* DO NOT USE OR OVERRIDE THIS METHOD.
60+
*
61+
* <p>{@link SqlClientAttributesExtractor} will try to populate {@code db.collection.name} based
62+
* on {@link #getRawQueryTexts(REQUEST)} when {@link
63+
* SqlClientAttributesExtractorBuilder#setSingleOperationAndCollection(boolean)} is enabled.
64+
*/
65+
@Override
66+
@Nullable
67+
default String getDbCollectionName(REQUEST request) {
68+
return null;
69+
}
70+
5571
/** Returns the SQL dialect used by the database. */
5672
SqlDialect getSqlDialect(REQUEST request);
5773

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitOldDatabaseSemconv;
99
import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
1010
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
11+
import static io.opentelemetry.semconv.DbAttributes.DB_COLLECTION_NAME;
1112
import static io.opentelemetry.semconv.DbAttributes.DB_NAMESPACE;
1213
import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_NAME;
1314
import static io.opentelemetry.semconv.DbAttributes.DB_QUERY_SUMMARY;
@@ -50,6 +51,11 @@ public String getDbNamespace(Map<String, String> map) {
5051
return map.get("db.namespace");
5152
}
5253

54+
@Override
55+
public String getDbCollectionName(Map<String, String> map) {
56+
return map.get("db.collection.name");
57+
}
58+
5359
@Deprecated
5460
@Override
5561
public String getConnectionString(Map<String, String> map) {
@@ -71,6 +77,12 @@ public String getDbQuerySummary(Map<String, String> map) {
7177
public String getDbOperationName(Map<String, String> map) {
7278
return map.get("db.operation.name");
7379
}
80+
81+
@Deprecated
82+
@Override
83+
public String getDbOperation(Map<String, String> map) {
84+
return map.get("db.operation");
85+
}
7486
}
7587

7688
@SuppressWarnings("deprecation") // TODO DB_CONNECTION_STRING deprecation
@@ -81,9 +93,11 @@ void shouldExtractAllAvailableAttributes() {
8193
request.put("db.system", "myDb");
8294
request.put("db.user", "username");
8395
request.put("db.namespace", "potatoes");
96+
request.put("db.collection.name", "potato");
8497
request.put("db.connection_string", "mydb:///potatoes");
8598
request.put("db.query.text", "SELECT * FROM potato");
8699
request.put("db.query_summary", "SELECT potato");
100+
request.put("db.operation", "old SELECT");
87101
request.put("db.operation.name", "SELECT");
88102

89103
Context context = Context.root();
@@ -108,7 +122,8 @@ void shouldExtractAllAvailableAttributes() {
108122
entry(DB_NAME, "potatoes"),
109123
entry(DB_CONNECTION_STRING, "mydb:///potatoes"),
110124
entry(DB_STATEMENT, "SELECT * FROM potato"),
111-
entry(DB_OPERATION, "SELECT"),
125+
entry(DB_OPERATION, "old SELECT"),
126+
entry(DB_COLLECTION_NAME, "potato"),
112127
entry(DB_NAMESPACE, "potatoes"),
113128
entry(DB_QUERY_TEXT, "SELECT * FROM potato"),
114129
entry(DB_QUERY_SUMMARY, "SELECT potato"),
@@ -121,11 +136,12 @@ void shouldExtractAllAvailableAttributes() {
121136
entry(DB_NAME, "potatoes"),
122137
entry(DB_CONNECTION_STRING, "mydb:///potatoes"),
123138
entry(DB_STATEMENT, "SELECT * FROM potato"),
124-
entry(DB_OPERATION, "SELECT"));
139+
entry(DB_OPERATION, "old SELECT"));
125140
} else if (emitStableDatabaseSemconv()) {
126141
assertThat(startAttributes.build())
127142
.containsOnly(
128143
entry(DB_SYSTEM_NAME, "myDb"),
144+
entry(DB_COLLECTION_NAME, "potato"),
129145
entry(DB_NAMESPACE, "potatoes"),
130146
entry(DB_QUERY_TEXT, "SELECT * FROM potato"),
131147
entry(DB_QUERY_SUMMARY, "SELECT potato"),

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

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,12 @@ void shouldExtractOperationAndName() {
100100
// given
101101
DbRequest dbRequest = new DbRequest();
102102

103-
when(dbAttributesGetter.getDbOperationName(dbRequest)).thenReturn("SELECT");
104103
if (emitStableDatabaseSemconv()) {
104+
when(dbAttributesGetter.getDbOperationName(dbRequest)).thenReturn("SELECT");
105105
when(dbAttributesGetter.getDbNamespace(dbRequest)).thenReturn("database");
106106
}
107107
if (emitOldDatabaseSemconv() && !emitStableDatabaseSemconv()) {
108+
when(dbAttributesGetter.getDbOperation(dbRequest)).thenReturn("SELECT");
108109
when(dbAttributesGetter.getDbName(dbRequest)).thenReturn("database");
109110
}
110111

@@ -117,12 +118,42 @@ void shouldExtractOperationAndName() {
117118
assertThat(spanName).isEqualTo("SELECT database");
118119
}
119120

121+
@Test
122+
void shouldPreferCollectionNameOverNamespace() {
123+
// given
124+
DbRequest dbRequest = new DbRequest();
125+
126+
if (emitStableDatabaseSemconv()) {
127+
when(dbAttributesGetter.getDbOperationName(dbRequest)).thenReturn("SELECT");
128+
lenient().when(dbAttributesGetter.getDbNamespace(dbRequest)).thenReturn("database");
129+
when(dbAttributesGetter.getDbCollectionName(dbRequest)).thenReturn("users");
130+
}
131+
if (emitOldDatabaseSemconv() && !emitStableDatabaseSemconv()) {
132+
when(dbAttributesGetter.getDbOperation(dbRequest)).thenReturn("SELECT");
133+
when(dbAttributesGetter.getDbName(dbRequest)).thenReturn("database");
134+
}
135+
136+
SpanNameExtractor<DbRequest> underTest = DbClientSpanNameExtractor.create(dbAttributesGetter);
137+
138+
// when
139+
String spanName = underTest.extract(dbRequest);
140+
141+
// then
142+
assertThat(spanName)
143+
.isEqualTo(emitStableDatabaseSemconv() ? "SELECT users" : "SELECT database");
144+
}
145+
120146
@Test
121147
void shouldExtractOperation() {
122148
// given
123149
DbRequest dbRequest = new DbRequest();
124150

125-
when(dbAttributesGetter.getDbOperationName(dbRequest)).thenReturn("SELECT");
151+
if (emitStableDatabaseSemconv()) {
152+
when(dbAttributesGetter.getDbOperationName(dbRequest)).thenReturn("SELECT");
153+
}
154+
if (emitOldDatabaseSemconv() && !emitStableDatabaseSemconv()) {
155+
when(dbAttributesGetter.getDbOperation(dbRequest)).thenReturn("SELECT");
156+
}
126157

127158
SpanNameExtractor<DbRequest> underTest = DbClientSpanNameExtractor.create(dbAttributesGetter);
128159

@@ -177,7 +208,7 @@ void shouldUseQuerySummaryWhenAvailable() {
177208
when(dbAttributesGetter.getDbQuerySummary(dbRequest)).thenReturn("SELECT users");
178209
}
179210
if (emitOldDatabaseSemconv() && !emitStableDatabaseSemconv()) {
180-
when(dbAttributesGetter.getDbOperationName(dbRequest)).thenReturn("SELECT");
211+
when(dbAttributesGetter.getDbOperation(dbRequest)).thenReturn("SELECT");
181212
when(dbAttributesGetter.getDbName(dbRequest)).thenReturn("database");
182213
}
183214

@@ -236,12 +267,11 @@ void shouldExtractFullSpanNameForSingleQueryBatch() {
236267
}
237268

238269
@Test
239-
void shouldFallBackToExplicitOperationNameForEmptySqlQuery() {
270+
void shouldFallBackToNamespaceForEmptySqlQuery() {
240271
// given
241272
DbRequest dbRequest = new DbRequest();
242273

243274
when(sqlAttributesGetter.getRawQueryTexts(dbRequest)).thenReturn(emptyList());
244-
when(sqlAttributesGetter.getDbOperationName(dbRequest)).thenReturn("WRITE");
245275
if (emitStableDatabaseSemconv()) {
246276
when(sqlAttributesGetter.getDbNamespace(dbRequest)).thenReturn("mydb");
247277
}
@@ -255,7 +285,7 @@ void shouldFallBackToExplicitOperationNameForEmptySqlQuery() {
255285
String spanName = underTest.extract(dbRequest);
256286

257287
// then
258-
assertThat(spanName).isEqualTo("WRITE mydb");
288+
assertThat(spanName).isEqualTo("mydb");
259289
}
260290

261291
@Test
@@ -283,12 +313,11 @@ void shouldPreserveOldSemconvSpanNameForMigration() {
283313

284314
@Test
285315
@SuppressWarnings("deprecation") // testing deprecated method
286-
void shouldFallBackToExplicitOperationForEmptySqlQueryInMigration() {
316+
void shouldFallBackToNamespaceForEmptySqlQueryInMigration() {
287317
// given
288318
DbRequest dbRequest = new DbRequest();
289319

290320
when(sqlAttributesGetter.getRawQueryTexts(dbRequest)).thenReturn(emptyList());
291-
when(sqlAttributesGetter.getDbOperationName(dbRequest)).thenReturn("WRITE");
292321
if (emitStableDatabaseSemconv()) {
293322
when(sqlAttributesGetter.getDbNamespace(dbRequest)).thenReturn("mydb");
294323
}
@@ -303,7 +332,7 @@ void shouldFallBackToExplicitOperationForEmptySqlQueryInMigration() {
303332
String spanName = underTest.extract(dbRequest);
304333

305334
// then
306-
assertThat(spanName).isEqualTo("WRITE mydb");
335+
assertThat(spanName).isEqualTo("mydb");
307336
}
308337

309338
static class DbRequest {}

0 commit comments

Comments
 (0)