Skip to content

Commit 99d6930

Browse files
committed
[semconv]: Add support for new formal DB semantic convention keys
ADOT Java currently uses some deprecated incubating semconv keys. This PR adds support for the newly introduced formal semconv keys that replace them, while maintaining backward compatibility by falling back to the legacy keys when necessary. **Deprecated keys:** - DB_NAME - DB_OPERATION - DB_STATEMENT - DB_SYSTEM (Reference: https://github.com/open-telemetry/semantic-conventions-java/blob/release/v1.34.0/semconv-incubating/src/main/java/io/opentelemetry/semconv/incubating/DbIncubatingAttributes.java#L322-L327) **New keys:** - DB_NAMESPACE - DB_OPERATION_NAME - DB_QUERY_TEXT - DB_SYSTEM_NAME **Tests performed:** - Unit tests: `./gradlew build test` - Smoke/contract tests: `./gradlew appsignals-tests:contract-tests:contractTests` - Manual E2E test with SpringBoot sample app.
1 parent a62f47f commit 99d6930

File tree

4 files changed

+65
-28
lines changed

4 files changed

+65
-28
lines changed

awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributeGenerator.java

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515

1616
package software.amazon.opentelemetry.javaagent.providers;
1717

18+
import static io.opentelemetry.semconv.DbAttributes.DB_NAMESPACE;
19+
import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_NAME;
20+
import static io.opentelemetry.semconv.DbAttributes.DB_QUERY_TEXT;
21+
import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME;
1822
import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD;
1923
import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE;
2024
import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PEER_ADDRESS;
@@ -26,7 +30,6 @@
2630
// https://github.com/open-telemetry/semantic-conventions-java/blob/release/v1.34.0/semconv-incubating/src/main/java/io/opentelemetry/semconv/incubating/DbIncubatingAttributes.java#L322-L327
2731
// They have been replaced with new keys:
2832
// https://github.com/open-telemetry/semantic-conventions-java/blob/release/v1.34.0/semconv/src/main/java/io/opentelemetry/semconv/DbAttributes.java#L77
29-
// TODO: Supporting new keys. Cannot do this now as new keys are not available in OTel Agent 2.11.
3033
// TODO: Delete deprecated keys once they no longer exist in binding version of the upstream code.
3134
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_CONNECTION_STRING;
3235
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_NAME;
@@ -93,6 +96,7 @@
9396
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.UNKNOWN_OPERATION;
9497
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.UNKNOWN_REMOTE_OPERATION;
9598
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.UNKNOWN_REMOTE_SERVICE;
99+
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.getKeyValueWithFallback;
96100
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isAwsSDKSpan;
97101
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isDBSpan;
98102
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isKeyPresent;
@@ -285,11 +289,12 @@ private static void setRemoteServiceAndOperation(SpanData span, AttributesBuilde
285289
remoteOperation = getRemoteOperation(span, RPC_METHOD);
286290

287291
} else if (isDBSpan(span)) {
288-
remoteService = getRemoteService(span, DB_SYSTEM);
289-
if (isKeyPresent(span, DB_OPERATION)) {
290-
remoteOperation = getRemoteOperation(span, DB_OPERATION);
292+
remoteService = getRemoteServiceWithFallback(span, DB_SYSTEM_NAME, DB_SYSTEM);
293+
if (isKeyPresentWithFallback(span, DB_OPERATION_NAME, DB_OPERATION)) {
294+
remoteOperation = getRemoteOperationWithFallback(span, DB_OPERATION_NAME, DB_OPERATION);
291295
} else {
292-
remoteOperation = getDBStatementRemoteOperation(span, DB_STATEMENT);
296+
String dbStatement = getKeyValueWithFallback(span, DB_QUERY_TEXT, DB_STATEMENT);
297+
remoteOperation = getDBStatementRemoteOperation(span, dbStatement);
293298
}
294299
} else if (isKeyPresent(span, FAAS_INVOKED_NAME) || isKeyPresent(span, FAAS_TRIGGER)) {
295300
remoteService = getRemoteService(span, FAAS_INVOKED_NAME);
@@ -349,10 +354,7 @@ private static void setRemoteEnvironment(SpanData span, AttributesBuilder builde
349354
private static String generateRemoteOperation(SpanData span) {
350355
String remoteOperation = UNKNOWN_REMOTE_OPERATION;
351356
if (isKeyPresent(span, URL_FULL) || isKeyPresent(span, HTTP_URL)) {
352-
String httpUrl =
353-
isKeyPresent(span, URL_FULL)
354-
? span.getAttributes().get(URL_FULL)
355-
: span.getAttributes().get(HTTP_URL);
357+
String httpUrl = getKeyValueWithFallback(span, URL_FULL, HTTP_URL);
356358
try {
357359
URL url;
358360
if (httpUrl != null) {
@@ -363,11 +365,8 @@ private static String generateRemoteOperation(SpanData span) {
363365
logger.log(Level.FINEST, "invalid http.url attribute: ", httpUrl);
364366
}
365367
}
366-
if (isKeyPresent(span, HTTP_REQUEST_METHOD) || isKeyPresent(span, HTTP_METHOD)) {
367-
String httpMethod =
368-
isKeyPresent(span, HTTP_REQUEST_METHOD)
369-
? span.getAttributes().get(HTTP_REQUEST_METHOD)
370-
: span.getAttributes().get(HTTP_METHOD);
368+
if (isKeyPresentWithFallback(span, HTTP_REQUEST_METHOD, HTTP_METHOD)) {
369+
String httpMethod = getKeyValueWithFallback(span, HTTP_REQUEST_METHOD, HTTP_METHOD);
371370
remoteOperation = httpMethod + " " + remoteOperation;
372371
}
373372
if (remoteOperation.equals(UNKNOWN_REMOTE_OPERATION)) {
@@ -791,7 +790,7 @@ private static Optional<String> getSnsResourceNameFromArn(Optional<String> strin
791790
* provided.
792791
*/
793792
private static Optional<String> getDbConnection(SpanData span) {
794-
String dbName = span.getAttributes().get(DB_NAME);
793+
String dbName = getKeyValueWithFallback(span, DB_NAMESPACE, DB_NAME);
795794
Optional<String> dbConnection = Optional.empty();
796795

797796
if (isKeyPresent(span, SERVER_ADDRESS)) {
@@ -949,6 +948,15 @@ private static String getRemoteService(SpanData span, AttributeKey<String> remot
949948
return remoteService;
950949
}
951950

951+
static String getRemoteServiceWithFallback(
952+
SpanData span, AttributeKey<String> remoteSvcKey, AttributeKey<String> remoteSvcFallbackKey) {
953+
String remoteService = span.getAttributes().get(remoteSvcKey);
954+
if (remoteService == null) {
955+
return getRemoteService(span, remoteSvcFallbackKey);
956+
}
957+
return remoteService;
958+
}
959+
952960
private static String getRemoteOperation(SpanData span, AttributeKey<String> remoteOperationKey) {
953961
String remoteOperation = span.getAttributes().get(remoteOperationKey);
954962
if (remoteOperation == null) {
@@ -972,9 +980,8 @@ static String getRemoteOperationWithFallback(
972980
* statement and compare to a regex list of known SQL keywords. The substring length is determined
973981
* by the longest known SQL keywords.
974982
*/
975-
private static String getDBStatementRemoteOperation(
976-
SpanData span, AttributeKey<String> remoteOperationKey) {
977-
String remoteOperation = span.getAttributes().get(remoteOperationKey);
983+
private static String getDBStatementRemoteOperation(SpanData span, String dbStatement) {
984+
String remoteOperation = dbStatement;
978985
if (remoteOperation == null) {
979986
remoteOperation = UNKNOWN_REMOTE_OPERATION;
980987
}

awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanMetricsProcessor.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE;
1919
import static io.opentelemetry.semconv.incubating.HttpIncubatingAttributes.HTTP_STATUS_CODE;
2020
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_SERVICE;
21-
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isKeyPresent;
21+
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.getKeyValueWithFallback;
2222

2323
import io.opentelemetry.api.common.Attributes;
2424
import io.opentelemetry.api.metrics.DoubleHistogram;
@@ -136,12 +136,8 @@ public boolean isEndRequired() {
136136
// possible except for the throttle
137137
// https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/exporter/awsxrayexporter/internal/translator/cause.go#L121-L160
138138
private void recordErrorOrFault(SpanData spanData, Attributes attributes) {
139-
Long httpStatusCode = null;
140-
if (isKeyPresent(spanData, HTTP_RESPONSE_STATUS_CODE)) {
141-
httpStatusCode = spanData.getAttributes().get(HTTP_RESPONSE_STATUS_CODE);
142-
} else if (isKeyPresent(spanData, HTTP_STATUS_CODE)) {
143-
httpStatusCode = spanData.getAttributes().get(HTTP_STATUS_CODE);
144-
}
139+
Long httpStatusCode =
140+
getKeyValueWithFallback(spanData, HTTP_RESPONSE_STATUS_CODE, HTTP_STATUS_CODE);
145141
StatusCode statusCode = spanData.getStatus().getStatusCode();
146142

147143
if (httpStatusCode == null) {

awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtil.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

1616
package software.amazon.opentelemetry.javaagent.providers;
1717

18+
import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_NAME;
19+
import static io.opentelemetry.semconv.DbAttributes.DB_QUERY_TEXT;
20+
import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME;
1821
import static io.opentelemetry.semconv.UrlAttributes.URL_PATH;
1922
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION;
2023
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_STATEMENT;
@@ -295,9 +298,9 @@ private static String generateIngressOperation(SpanData span) {
295298

296299
// Check if the current Span adheres to database semantic conventions
297300
static boolean isDBSpan(SpanData span) {
298-
return isKeyPresent(span, DB_SYSTEM)
299-
|| isKeyPresent(span, DB_OPERATION)
300-
|| isKeyPresent(span, DB_STATEMENT);
301+
return isKeyPresentWithFallback(span, DB_SYSTEM_NAME, DB_SYSTEM)
302+
|| isKeyPresentWithFallback(span, DB_OPERATION_NAME, DB_OPERATION)
303+
|| isKeyPresentWithFallback(span, DB_QUERY_TEXT, DB_STATEMENT);
301304
}
302305

303306
static boolean isLambdaServerSpan(ReadableSpan span) {

awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributeGeneratorTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package software.amazon.opentelemetry.javaagent.providers;
1717

18+
import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME;
1819
import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD;
1920
import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE;
2021
import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PEER_ADDRESS;
@@ -1792,4 +1793,34 @@ public void testBothMetricsWhenLocalRootConsumerProcess() {
17921793
assertThat(attributeMap.get(SERVICE_METRIC)).isEqualTo(serviceAttributes);
17931794
assertThat(attributeMap.get(DEPENDENCY_METRIC)).isEqualTo(dependencyAttributes);
17941795
}
1796+
1797+
@Test
1798+
public void testGetRemoteServiceWithFallback_PrimaryKeyPresent() {
1799+
mockAttribute(DB_SYSTEM_NAME, "mysql");
1800+
mockAttribute(DB_SYSTEM, "postgresql");
1801+
String result =
1802+
AwsMetricAttributeGenerator.getRemoteServiceWithFallback(
1803+
spanDataMock, DB_SYSTEM_NAME, DB_SYSTEM);
1804+
1805+
assertThat(result).isEqualTo("mysql");
1806+
}
1807+
1808+
@Test
1809+
public void testGetRemoteServiceWithFallback_FallbackKeyPresent() {
1810+
mockAttribute(DB_SYSTEM, "postgresql");
1811+
String result =
1812+
AwsMetricAttributeGenerator.getRemoteServiceWithFallback(
1813+
spanDataMock, DB_SYSTEM_NAME, DB_SYSTEM);
1814+
1815+
assertThat(result).isEqualTo("postgresql");
1816+
}
1817+
1818+
@Test
1819+
public void testGetRemoteServiceWithFallback_BothKeysAbsent() {
1820+
String result =
1821+
AwsMetricAttributeGenerator.getRemoteServiceWithFallback(
1822+
spanDataMock, DB_SYSTEM_NAME, DB_SYSTEM);
1823+
1824+
assertThat(result).isEqualTo(UNKNOWN_REMOTE_SERVICE);
1825+
}
17951826
}

0 commit comments

Comments
 (0)