Skip to content

Commit

Permalink
Support new semantice conventions. (#972)
Browse files Browse the repository at this point in the history
*Description of changes:*
This PR adding support of new semantic conventions in latest version
from otel upstream:
`http.url` -> `url.full`
`http.method` -> `http.request.method`
`http.status_code` -> `http.response.status_code`
`net.peer.name` -> `server.address`
`net.peer.port` -> `server.port`

Testing are done for both old upstream ve
<img width="749" alt="Screenshot 2024-12-10 at 3 42 53 PM"
src="https://github.com/user-attachments/assets/a4125a78-82fa-45a6-9006-44165d8ac34f">
rsion v1.32.1 and new upstream version v2.10.0. 


By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license.
  • Loading branch information
zzhlogin authored Dec 11, 2024
1 parent 12f770e commit 448d680
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 19 deletions.
4 changes: 2 additions & 2 deletions awsagentprovider/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ base {

dependencies {
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api")
compileOnly("io.opentelemetry.semconv:opentelemetry-semconv")
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv")
compileOnly("io.opentelemetry.semconv:opentelemetry-semconv:1.28.0-alpha")
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv:1.28.0-alpha")
compileOnly("com.google.errorprone:error_prone_annotations:2.19.1")
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
compileOnly("org.slf4j:slf4j-api")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@
import static io.opentelemetry.semconv.SemanticAttributes.FAAS_TRIGGER;
import static io.opentelemetry.semconv.SemanticAttributes.GRAPHQL_OPERATION_TYPE;
import static io.opentelemetry.semconv.SemanticAttributes.HTTP_METHOD;
import static io.opentelemetry.semconv.SemanticAttributes.HTTP_REQUEST_METHOD;
import static io.opentelemetry.semconv.SemanticAttributes.HTTP_RESPONSE_STATUS_CODE;
import static io.opentelemetry.semconv.SemanticAttributes.HTTP_STATUS_CODE;
import static io.opentelemetry.semconv.SemanticAttributes.HTTP_URL;
import static io.opentelemetry.semconv.SemanticAttributes.MESSAGING_OPERATION;
import static io.opentelemetry.semconv.SemanticAttributes.MESSAGING_SYSTEM;
import static io.opentelemetry.semconv.SemanticAttributes.NETWORK_PEER_ADDRESS;
import static io.opentelemetry.semconv.SemanticAttributes.NETWORK_PEER_PORT;
import static io.opentelemetry.semconv.SemanticAttributes.NET_PEER_NAME;
import static io.opentelemetry.semconv.SemanticAttributes.NET_PEER_PORT;
import static io.opentelemetry.semconv.SemanticAttributes.NET_SOCK_PEER_ADDR;
Expand All @@ -40,6 +44,7 @@
import static io.opentelemetry.semconv.SemanticAttributes.SERVER_PORT;
import static io.opentelemetry.semconv.SemanticAttributes.SERVER_SOCKET_ADDRESS;
import static io.opentelemetry.semconv.SemanticAttributes.SERVER_SOCKET_PORT;
import static io.opentelemetry.semconv.SemanticAttributes.URL_FULL;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_AGENT_ID;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_BUCKET_NAME;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER;
Expand Down Expand Up @@ -292,8 +297,11 @@ private static void setRemoteServiceAndOperation(SpanData span, AttributesBuilde
*/
private static String generateRemoteOperation(SpanData span) {
String remoteOperation = UNKNOWN_REMOTE_OPERATION;
if (isKeyPresent(span, HTTP_URL)) {
String httpUrl = span.getAttributes().get(HTTP_URL);
if (isKeyPresent(span, URL_FULL) || isKeyPresent(span, HTTP_URL)) {
String httpUrl =
isKeyPresent(span, URL_FULL)
? span.getAttributes().get(URL_FULL)
: span.getAttributes().get(HTTP_URL);
try {
URL url;
if (httpUrl != null) {
Expand All @@ -304,8 +312,11 @@ private static String generateRemoteOperation(SpanData span) {
logger.log(Level.FINEST, "invalid http.url attribute: ", httpUrl);
}
}
if (isKeyPresent(span, HTTP_METHOD)) {
String httpMethod = span.getAttributes().get(HTTP_METHOD);
if (isKeyPresent(span, HTTP_REQUEST_METHOD) || isKeyPresent(span, HTTP_METHOD)) {
String httpMethod =
isKeyPresent(span, HTTP_REQUEST_METHOD)
? span.getAttributes().get(HTTP_REQUEST_METHOD)
: span.getAttributes().get(HTTP_METHOD);
remoteOperation = httpMethod + " " + remoteOperation;
}
if (remoteOperation.equals(UNKNOWN_REMOTE_OPERATION)) {
Expand All @@ -316,20 +327,35 @@ private static String generateRemoteOperation(SpanData span) {

private static String generateRemoteService(SpanData span) {
String remoteService = UNKNOWN_REMOTE_SERVICE;
if (isKeyPresent(span, NET_PEER_NAME)) {
if (isKeyPresent(span, SERVER_ADDRESS)) {
remoteService = getRemoteService(span, SERVER_ADDRESS);
if (isKeyPresent(span, SERVER_PORT)) {
Long port = span.getAttributes().get(SERVER_PORT);
remoteService += ":" + port;
}
} else if (isKeyPresent(span, NET_PEER_NAME)) {
remoteService = getRemoteService(span, NET_PEER_NAME);
if (isKeyPresent(span, NET_PEER_PORT)) {
Long port = span.getAttributes().get(NET_PEER_PORT);
remoteService += ":" + port;
}
} else if (isKeyPresent(span, NETWORK_PEER_ADDRESS)) {
remoteService = getRemoteService(span, NETWORK_PEER_ADDRESS);
if (isKeyPresent(span, NETWORK_PEER_PORT)) {
Long port = span.getAttributes().get(NETWORK_PEER_PORT);
remoteService += ":" + port;
}
} else if (isKeyPresent(span, NET_SOCK_PEER_ADDR)) {
remoteService = getRemoteService(span, NET_SOCK_PEER_ADDR);
if (isKeyPresent(span, NET_SOCK_PEER_PORT)) {
Long port = span.getAttributes().get(NET_SOCK_PEER_PORT);
remoteService += ":" + port;
}
} else if (isKeyPresent(span, HTTP_URL)) {
String httpUrl = span.getAttributes().get(HTTP_URL);
} else if (isKeyPresent(span, URL_FULL) || isKeyPresent(span, HTTP_URL)) {
String httpUrl =
isKeyPresent(span, URL_FULL)
? span.getAttributes().get(URL_FULL)
: span.getAttributes().get(HTTP_URL);
try {
URL url = new URL(httpUrl);
if (!url.getHost().isEmpty()) {
Expand Down Expand Up @@ -633,6 +659,12 @@ private static void setHttpStatus(SpanData span, AttributesBuilder builder) {
return;
}

if (isKeyPresent(span, HTTP_RESPONSE_STATUS_CODE)) {
Long statusCode = span.getAttributes().get(HTTP_RESPONSE_STATUS_CODE);
builder.put(HTTP_STATUS_CODE, statusCode);
return;
}

Long statusCode = getAwsStatusCode(span);
if (statusCode != null) {
builder.put(HTTP_STATUS_CODE, statusCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@

package software.amazon.opentelemetry.javaagent.providers;

import static io.opentelemetry.semconv.SemanticAttributes.HTTP_RESPONSE_STATUS_CODE;
import static io.opentelemetry.semconv.SemanticAttributes.HTTP_STATUS_CODE;
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isKeyPresent;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
Expand Down Expand Up @@ -129,7 +131,12 @@ public boolean isEndRequired() {
// possible except for the throttle
// https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/exporter/awsxrayexporter/internal/translator/cause.go#L121-L160
private void recordErrorOrFault(SpanData spanData, Attributes attributes) {
Long httpStatusCode = spanData.getAttributes().get(HTTP_STATUS_CODE);
Long httpStatusCode = null;
if (isKeyPresent(spanData, HTTP_RESPONSE_STATUS_CODE)) {
httpStatusCode = spanData.getAttributes().get(HTTP_RESPONSE_STATUS_CODE);
} else if (isKeyPresent(spanData, HTTP_STATUS_CODE)) {
httpStatusCode = spanData.getAttributes().get(HTTP_STATUS_CODE);
}
StatusCode statusCode = spanData.getStatus().getStatusCode();

if (httpStatusCode == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
import static io.opentelemetry.semconv.SemanticAttributes.DB_STATEMENT;
import static io.opentelemetry.semconv.SemanticAttributes.DB_SYSTEM;
import static io.opentelemetry.semconv.SemanticAttributes.HTTP_METHOD;
import static io.opentelemetry.semconv.SemanticAttributes.HTTP_REQUEST_METHOD;
import static io.opentelemetry.semconv.SemanticAttributes.HTTP_TARGET;
import static io.opentelemetry.semconv.SemanticAttributes.MESSAGING_OPERATION;
import static io.opentelemetry.semconv.SemanticAttributes.MessagingOperationValues.PROCESS;
import static io.opentelemetry.semconv.SemanticAttributes.RPC_SYSTEM;
import static io.opentelemetry.semconv.SemanticAttributes.URL_PATH;
import static software.amazon.opentelemetry.javaagent.providers.AwsApplicationSignalsCustomizerProvider.AWS_LAMBDA_FUNCTION_NAME_CONFIG;
import static software.amazon.opentelemetry.javaagent.providers.AwsApplicationSignalsCustomizerProvider.isLambdaEnvironment;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_OPERATION;
Expand Down Expand Up @@ -200,7 +202,10 @@ private static boolean isValidOperation(SpanData span, String operation) {
if (operation == null || operation.equals(UNKNOWN_OPERATION)) {
return false;
}
if (isKeyPresent(span, HTTP_METHOD)) {
if (isKeyPresent(span, HTTP_REQUEST_METHOD)) {
String httpMethod = span.getAttributes().get(HTTP_REQUEST_METHOD);
return !operation.equals(httpMethod);
} else if (isKeyPresent(span, HTTP_METHOD)) {
String httpMethod = span.getAttributes().get(HTTP_METHOD);
return !operation.equals(httpMethod);
}
Expand All @@ -213,15 +218,21 @@ private static boolean isValidOperation(SpanData span, String operation) {
*/
private static String generateIngressOperation(SpanData span) {
String operation = UNKNOWN_OPERATION;
if (isKeyPresent(span, HTTP_TARGET)) {
String httpTarget = span.getAttributes().get(HTTP_TARGET);
if (isKeyPresent(span, URL_PATH) || isKeyPresent(span, HTTP_TARGET)) {
String httpTarget =
isKeyPresent(span, URL_PATH)
? span.getAttributes().get(URL_PATH)
: span.getAttributes().get(HTTP_TARGET);
// get the first part from API path string as operation value
// the more levels/parts we get from API path the higher chance for getting high cardinality
// data
if (httpTarget != null) {
operation = extractAPIPathValue(httpTarget);
if (isKeyPresent(span, HTTP_METHOD)) {
String httpMethod = span.getAttributes().get(HTTP_METHOD);
if (isKeyPresent(span, HTTP_REQUEST_METHOD) || isKeyPresent(span, HTTP_METHOD)) {
String httpMethod =
isKeyPresent(span, HTTP_REQUEST_METHOD)
? span.getAttributes().get(HTTP_REQUEST_METHOD)
: span.getAttributes().get(HTTP_METHOD);
if (httpMethod != null) {
operation = httpMethod + " " + operation;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,23 +374,25 @@ public void testServerSpanWithNullSpanName() {
public void testServerSpanWithSpanNameAsHttpMethod() {
updateResourceWithServiceName();
when(spanDataMock.getName()).thenReturn("GET");
mockAttribute(HTTP_METHOD, "GET");

Attributes expectedAttributes =
Attributes.of(
AWS_SPAN_KIND, SpanKind.SERVER.name(),
AWS_LOCAL_SERVICE, SERVICE_NAME_VALUE,
AWS_LOCAL_OPERATION, UNKNOWN_OPERATION);
// Validate the span with http.method.
mockAttribute(HTTP_METHOD, "GET");
validateAttributesProducedForNonLocalRootSpanOfKind(expectedAttributes, SpanKind.SERVER);
mockAttribute(HTTP_METHOD, null);
// Validate the span with http.request.method.
mockAttribute(HTTP_REQUEST_METHOD, "GET");
validateAttributesProducedForNonLocalRootSpanOfKind(expectedAttributes, SpanKind.SERVER);
mockAttribute(HTTP_REQUEST_METHOD, null);
}

@Test
public void testServerSpanWithSpanNameWithHttpTarget() {
updateResourceWithServiceName();
when(spanDataMock.getName()).thenReturn("POST");
mockAttribute(HTTP_METHOD, "POST");
mockAttribute(HTTP_TARGET, "/payment/123");

Attributes expectedAttributes =
Attributes.of(
Expand All @@ -400,9 +402,18 @@ public void testServerSpanWithSpanNameWithHttpTarget() {
SERVICE_NAME_VALUE,
AWS_LOCAL_OPERATION,
"POST /payment");
// Validate the span with http.method and http.target.
mockAttribute(HTTP_METHOD, "POST");
mockAttribute(HTTP_TARGET, "/payment/123");
validateAttributesProducedForNonLocalRootSpanOfKind(expectedAttributes, SpanKind.SERVER);
mockAttribute(HTTP_METHOD, null);
mockAttribute(HTTP_TARGET, null);
// Validate the span with http.request.method and url.path.
mockAttribute(HTTP_REQUEST_METHOD, "POST");
mockAttribute(URL_PATH, "/payment/123");
validateAttributesProducedForNonLocalRootSpanOfKind(expectedAttributes, SpanKind.SERVER);
mockAttribute(HTTP_REQUEST_METHOD, null);
mockAttribute(URL_PATH, null);
}

@Test
Expand Down Expand Up @@ -507,18 +518,35 @@ public void testRemoteAttributesCombinations() {
validateExpectedRemoteAttributes("www.example.com", UNKNOWN_REMOTE_OPERATION);
mockAttribute(NET_PEER_NAME, null);

// Validate behaviour of extracting Remote Service from service.address
mockAttribute(SERVER_ADDRESS, "www.example.com");
validateExpectedRemoteAttributes("www.example.com", UNKNOWN_REMOTE_OPERATION);
mockAttribute(SERVER_ADDRESS, null);

// Validate behaviour of extracting Remote Service from net.peer.name and net.peer.port
mockAttribute(NET_PEER_NAME, "192.168.0.0");
mockAttribute(NET_PEER_PORT, 8081L);
validateExpectedRemoteAttributes("192.168.0.0:8081", UNKNOWN_REMOTE_OPERATION);
mockAttribute(NET_PEER_NAME, null);
mockAttribute(NET_PEER_PORT, null);

// Validate behaviour of extracting Remote Service from service.address and service.port
mockAttribute(SERVER_ADDRESS, "192.168.0.0");
mockAttribute(SERVER_PORT, 8081L);
validateExpectedRemoteAttributes("192.168.0.0:8081", UNKNOWN_REMOTE_OPERATION);
mockAttribute(SERVER_ADDRESS, null);
mockAttribute(SERVER_PORT, null);

// Validate behaviour of extracting Remote Service from net.peer.socket.addr
mockAttribute(NET_SOCK_PEER_ADDR, "www.example.com");
validateExpectedRemoteAttributes("www.example.com", UNKNOWN_REMOTE_OPERATION);
mockAttribute(NET_SOCK_PEER_ADDR, null);

// Validate behaviour of extracting Remote Service from net.peer.socket.addr
mockAttribute(NETWORK_PEER_ADDRESS, "www.example.com");
validateExpectedRemoteAttributes("www.example.com", UNKNOWN_REMOTE_OPERATION);
mockAttribute(NETWORK_PEER_ADDRESS, null);

// Validate behaviour of extracting Remote Service from net.peer.socket.addr and
// net.sock.peer.port
mockAttribute(NET_SOCK_PEER_ADDR, "192.168.0.0");
Expand All @@ -527,43 +555,86 @@ public void testRemoteAttributesCombinations() {
mockAttribute(NET_SOCK_PEER_ADDR, null);
mockAttribute(NET_SOCK_PEER_PORT, null);

// Validate behaviour of extracting Remote Service from net.peer.socket.addr and
// net.sock.peer.port
mockAttribute(NETWORK_PEER_ADDRESS, "192.168.0.0");
mockAttribute(NETWORK_PEER_PORT, 8081L);
validateExpectedRemoteAttributes("192.168.0.0:8081", UNKNOWN_REMOTE_OPERATION);
mockAttribute(NETWORK_PEER_ADDRESS, null);
mockAttribute(NETWORK_PEER_PORT, null);

// Validate behavior of Remote Operation from HttpTarget - with 1st api part. Also validates
// that RemoteService is extracted from HttpUrl.
mockAttribute(HTTP_URL, "http://www.example.com/payment/123");
validateExpectedRemoteAttributes("www.example.com", "/payment");
mockAttribute(HTTP_URL, null);

// that RemoteService is extracted from url.full.
mockAttribute(URL_FULL, "http://www.example.com/payment/123");
validateExpectedRemoteAttributes("www.example.com", "/payment");
mockAttribute(URL_FULL, null);

// Validate behavior of Remote Operation from HttpTarget - with 1st api part. Also validates
// that RemoteService is extracted from HttpUrl.
mockAttribute(HTTP_URL, "http://www.example.com");
validateExpectedRemoteAttributes("www.example.com", "/");
mockAttribute(HTTP_URL, null);

// that RemoteService is extracted from url.full.
mockAttribute(URL_FULL, "http://www.example.com");
validateExpectedRemoteAttributes("www.example.com", "/");
mockAttribute(URL_FULL, null);

// Validate behavior of Remote Service from HttpUrl
mockAttribute(HTTP_URL, "http://192.168.1.1:8000");
validateExpectedRemoteAttributes("192.168.1.1:8000", "/");
mockAttribute(HTTP_URL, null);

// Validate behavior of Remote Service from url.full
mockAttribute(URL_FULL, "http://192.168.1.1:8000");
validateExpectedRemoteAttributes("192.168.1.1:8000", "/");
mockAttribute(URL_FULL, null);

// Validate behavior of Remote Service from HttpUrl
mockAttribute(HTTP_URL, "http://192.168.1.1");
validateExpectedRemoteAttributes("192.168.1.1", "/");
mockAttribute(HTTP_URL, null);

// Validate behavior of Remote Service from url.full
mockAttribute(URL_FULL, "http://192.168.1.1");
validateExpectedRemoteAttributes("192.168.1.1", "/");
mockAttribute(URL_FULL, null);

// Validate behavior of Remote Service from HttpUrl
mockAttribute(HTTP_URL, "");
validateExpectedRemoteAttributes(UNKNOWN_REMOTE_SERVICE, UNKNOWN_REMOTE_OPERATION);
mockAttribute(HTTP_URL, null);

// Validate behavior of Remote Service from url.full
mockAttribute(URL_FULL, "");
validateExpectedRemoteAttributes(UNKNOWN_REMOTE_SERVICE, UNKNOWN_REMOTE_OPERATION);
mockAttribute(URL_FULL, null);

// Validate behavior of Remote Service from HttpUrl
mockAttribute(HTTP_URL, null);
validateExpectedRemoteAttributes(UNKNOWN_REMOTE_SERVICE, UNKNOWN_REMOTE_OPERATION);
mockAttribute(HTTP_URL, null);

// Validate behavior of Remote Service from url.full
mockAttribute(URL_FULL, null);
validateExpectedRemoteAttributes(UNKNOWN_REMOTE_SERVICE, UNKNOWN_REMOTE_OPERATION);
mockAttribute(URL_FULL, null);

// Validate behavior of Remote Operation from HttpTarget - invalid url, then remove it
mockAttribute(HTTP_URL, "abc");
validateExpectedRemoteAttributes(UNKNOWN_REMOTE_SERVICE, UNKNOWN_REMOTE_OPERATION);
mockAttribute(HTTP_URL, null);

// Validate behavior of Remote Operation from url.full - invalid url, then remove it
mockAttribute(URL_FULL, "abc");
validateExpectedRemoteAttributes(UNKNOWN_REMOTE_SERVICE, UNKNOWN_REMOTE_OPERATION);
mockAttribute(URL_FULL, null);

// Validate behaviour of Peer service attribute, then remove it.
mockAttribute(PEER_SERVICE, "Peer service");
validateExpectedRemoteAttributes("Peer service", UNKNOWN_REMOTE_OPERATION);
Expand Down Expand Up @@ -660,7 +731,9 @@ public void testPeerServiceDoesOverrideOtherRemoteServices() {
validatePeerServiceDoesOverride(MESSAGING_SYSTEM);
validatePeerServiceDoesOverride(GRAPHQL_OPERATION_TYPE);
validatePeerServiceDoesOverride(NET_PEER_NAME);
validatePeerServiceDoesOverride(SERVER_ADDRESS);
validatePeerServiceDoesOverride(NET_SOCK_PEER_ADDR);
validatePeerServiceDoesOverride(NETWORK_PEER_ADDRESS);
// Actually testing that peer service overrides "UnknownRemoteService".
validatePeerServiceDoesOverride(AttributeKey.stringKey("unknown.service.key"));
}
Expand Down

0 comments on commit 448d680

Please sign in to comment.