Skip to content

Commit af23dee

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

17 files changed

Lines changed: 381 additions & 136 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/SqlClientAttributesExtractor.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
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.instrumentation.api.internal.SemconvStability.stableDbSystemName;
1011
import static io.opentelemetry.semconv.DbAttributes.DB_COLLECTION_NAME;
12+
import static io.opentelemetry.semconv.DbAttributes.DB_NAMESPACE;
1113
import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_BATCH_SIZE;
1214
import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_NAME;
1315
import static io.opentelemetry.semconv.DbAttributes.DB_QUERY_SUMMARY;
1416
import static io.opentelemetry.semconv.DbAttributes.DB_QUERY_TEXT;
1517
import static io.opentelemetry.semconv.DbAttributes.DB_STORED_PROCEDURE_NAME;
18+
import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME;
1619

1720
import io.opentelemetry.api.common.AttributeKey;
1821
import io.opentelemetry.api.common.AttributesBuilder;
@@ -22,7 +25,9 @@
2225
import io.opentelemetry.instrumentation.api.internal.SpanKeyProvider;
2326
import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor;
2427
import io.opentelemetry.instrumentation.api.semconv.network.internal.InternalNetworkAttributesExtractor;
28+
import io.opentelemetry.semconv.AttributeKeyTemplate;
2529
import java.util.Collection;
30+
import java.util.Map;
2631
import javax.annotation.Nullable;
2732

2833
/**
@@ -41,6 +46,8 @@ public final class SqlClientAttributesExtractor<REQUEST, RESPONSE>
4146
// copied from DbIncubatingAttributes
4247
private static final AttributeKey<String> DB_OPERATION = AttributeKey.stringKey("db.operation");
4348
private static final AttributeKey<String> DB_STATEMENT = AttributeKey.stringKey("db.statement");
49+
private static final AttributeKeyTemplate<String> DB_QUERY_PARAMETER =
50+
AttributeKeyTemplate.stringKeyTemplate("db.query.parameter");
4451

4552
/** Creates the SQL client attributes extractor with default configuration. */
4653
public static <REQUEST, RESPONSE> AttributesExtractor<REQUEST, RESPONSE> create(
@@ -141,10 +148,24 @@ public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST
141148
}
142149
}
143150

144-
// calling this last so explicit getDbOperationName(), getDbCollectionName(),
145-
// getDbQueryText(), and getDbQuerySummary() implementations can override
146-
// the parsed values from above
147-
DbClientAttributesExtractor.onStartCommon(attributes, getter, request, captureQueryParameters);
151+
if (emitOldDatabaseSemconv()) {
152+
// calling this last so explicit getDbOperationName(), getDbCollectionName(),
153+
// getDbQueryText(), and getDbQuerySummary() implementations can override
154+
// the parsed values from above
155+
DbClientAttributesExtractor.onStartCommon(
156+
attributes, getter, request, captureQueryParameters);
157+
} else if (emitStableDatabaseSemconv()) {
158+
attributes.put(DB_SYSTEM_NAME, stableDbSystemName(getter.getDbSystemName(request)));
159+
attributes.put(DB_NAMESPACE, getter.getDbNamespace(request));
160+
if (captureQueryParameters && !isBatch) {
161+
Map<String, String> queryParameters = getter.getDbQueryParameters(request);
162+
if (queryParameters != null && !queryParameters.isEmpty()) {
163+
for (Map.Entry<String, String> entry : queryParameters.entrySet()) {
164+
attributes.put(DB_QUERY_PARAMETER.getAttributeKey(entry.getKey()), entry.getValue());
165+
}
166+
}
167+
}
168+
}
148169
serverAttributesExtractor.onStart(attributes, parentContext, request);
149170
}
150171

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,12 @@ public SqlClientAttributesExtractorBuilder<REQUEST, RESPONSE> setCaptureQueryPar
6868
}
6969

7070
/**
71-
* Sets whether the instrumentation knows that its SQL-like language or request shape is limited
72-
* to a single operation and collection.
71+
* Sets whether {@code db.operation.name} and {@code db.collection.name} can be derived from
72+
* {@code db.query.text}.
7373
*
74-
* <p>For most instrumentations, enabling this will produce invalid semantic conventions.
74+
* <p>Enable this only when the database system does not support query text with multiple
75+
* operations or multiple collections in non-batch operations. For most instrumentations, enabling
76+
* this will produce invalid semantic conventions.
7577
*/
7678
@CanIgnoreReturnValue
7779
public SqlClientAttributesExtractorBuilder<REQUEST, RESPONSE> setSingleOperationAndCollection(

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@ 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+
* SQL instrumentations should not override this method.
27+
*
28+
* <p>Provide raw query text through {@link #getRawQueryTexts(REQUEST)} instead. When the database
29+
* system does not support query text with multiple operations in non-batch operations, enable
30+
* {@link SqlClientAttributesExtractorBuilder#setSingleOperationAndCollection(boolean)} and {@link
31+
* SqlClientAttributesExtractor} will derive {@code db.operation.name} from {@code db.query.text}.
2832
*/
2933
@Override
3034
@Nullable
@@ -52,6 +56,22 @@ default String getDbQuerySummary(REQUEST request) {
5256
return null;
5357
}
5458

59+
/**
60+
* SQL instrumentations should not override this method.
61+
*
62+
* <p>Provide raw query text through {@link #getRawQueryTexts(REQUEST)} instead. When the database
63+
* system does not support query text with multiple collections in non-batch operations, enable
64+
* {@link SqlClientAttributesExtractorBuilder#setSingleOperationAndCollection(boolean)} and {@link
65+
* SqlClientAttributesExtractor} will derive {@code db.collection.name} from {@code
66+
* db.query.text}. Do not enable that option when the database system supports query text with
67+
* multiple collections in non-batch operations.
68+
*/
69+
@Override
70+
@Nullable
71+
default String getDbCollectionName(REQUEST request) {
72+
return null;
73+
}
74+
5575
/** Returns the SQL dialect used by the database. */
5676
SqlDialect getSqlDialect(REQUEST request);
5777

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"),

0 commit comments

Comments
 (0)