diff --git a/semantic-convention-utils/src/main/java/org/hypertrace/semantic/convention/utils/http/HttpSemanticConventionUtils.java b/semantic-convention-utils/src/main/java/org/hypertrace/semantic/convention/utils/http/HttpSemanticConventionUtils.java index 22128c115..e594692a8 100644 --- a/semantic-convention-utils/src/main/java/org/hypertrace/semantic/convention/utils/http/HttpSemanticConventionUtils.java +++ b/semantic-convention-utils/src/main/java/org/hypertrace/semantic/convention/utils/http/HttpSemanticConventionUtils.java @@ -9,7 +9,11 @@ import static org.hypertrace.core.semantic.convention.constants.http.OTelHttpSemanticConventions.HTTP_URL; import static org.hypertrace.core.span.constants.v1.Envoy.ENVOY_REQUEST_SIZE; import static org.hypertrace.core.span.constants.v1.Envoy.ENVOY_RESPONSE_SIZE; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_HTTP_REQUEST_BODY; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_HTTP_RESPONSE_BODY; import static org.hypertrace.core.span.constants.v1.Http.HTTP_PATH; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_BODY_TRUNCATED; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_CONTENT_LENGTH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_CONTENT_TYPE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_HEADER_PATH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_METHOD; @@ -18,6 +22,8 @@ import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_SIZE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_URL; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_X_FORWARDED_FOR_HEADER; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_BODY_TRUNCATED; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_CONTENT_LENGTH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_SIZE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_STATUS_CODE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_USER_AGENT; @@ -71,6 +77,14 @@ public class HttpSemanticConventionUtils { private static final String OTEL_HTTP_TARGET = OTelHttpSemanticConventions.HTTP_TARGET.getValue(); private static final String RELATIVE_URL_CONTEXT = "http://hypertrace.org"; + private static final String HTTP_REQUEST_BODY = RawSpanConstants.getValue(HTTP_HTTP_REQUEST_BODY); + private static final String HTTP_REQUEST_BODY_TRUNCATED_ATTR = + RawSpanConstants.getValue(HTTP_REQUEST_BODY_TRUNCATED); + private static final String HTTP_RESPONSE_BODY = + RawSpanConstants.getValue(HTTP_HTTP_RESPONSE_BODY); + private static final String HTTP_RESPONSE_BODY_TRUNCATED_ATTR = + RawSpanConstants.getValue(HTTP_RESPONSE_BODY_TRUNCATED); + private static final String SLASH = "/"; private static final List USER_AGENT_ATTRIBUTES = @@ -116,13 +130,15 @@ public class HttpSemanticConventionUtils { List.of( RawSpanConstants.getValue(ENVOY_REQUEST_SIZE), RawSpanConstants.getValue(HTTP_REQUEST_SIZE), - OTelHttpSemanticConventions.HTTP_REQUEST_SIZE.getValue()); + OTelHttpSemanticConventions.HTTP_REQUEST_SIZE.getValue(), + RawSpanConstants.getValue(HTTP_REQUEST_CONTENT_LENGTH)); private static final List RESPONSE_SIZE_ATTRIBUTES = List.of( RawSpanConstants.getValue(ENVOY_RESPONSE_SIZE), RawSpanConstants.getValue(HTTP_RESPONSE_SIZE), - OTelHttpSemanticConventions.HTTP_RESPONSE_SIZE.getValue()); + OTelHttpSemanticConventions.HTTP_RESPONSE_SIZE.getValue(), + RawSpanConstants.getValue(HTTP_RESPONSE_CONTENT_LENGTH)); private static final List STATUS_CODE_ATTRIBUTES = List.of( @@ -474,13 +490,31 @@ public static Optional getHttpQueryString(Event event) { public static Optional getHttpRequestSize(Event event) { String httpRequestSize = SpanAttributeUtils.getFirstAvailableStringAttribute(event, REQUEST_SIZE_ATTRIBUTES); - return Optional.ofNullable(httpRequestSize).map(Integer::parseInt); + + Optional requestSize = Optional.ofNullable(httpRequestSize); + if (!requestSize.isEmpty()) return requestSize.map(Integer::parseInt); + + if (SpanAttributeUtils.getBooleanAttribute(event, HTTP_REQUEST_BODY_TRUNCATED_ATTR)) { + return Optional.empty(); + } + + String requestBody = SpanAttributeUtils.getStringAttribute(event, HTTP_REQUEST_BODY); + return Optional.ofNullable(requestBody).map(String::length); } public static Optional getHttpResponseSize(Event event) { String httpResponseSize = SpanAttributeUtils.getFirstAvailableStringAttribute(event, RESPONSE_SIZE_ATTRIBUTES); - return Optional.ofNullable(httpResponseSize).map(Integer::parseInt); + + Optional responseSize = Optional.ofNullable(httpResponseSize); + if (!responseSize.isEmpty()) return responseSize.map(Integer::parseInt); + + if (SpanAttributeUtils.getBooleanAttribute(event, HTTP_RESPONSE_BODY_TRUNCATED_ATTR)) { + return Optional.empty(); + } + + String responseBody = SpanAttributeUtils.getStringAttribute(event, HTTP_RESPONSE_BODY); + return Optional.ofNullable(responseBody).map(String::length); } public static int getHttpResponseStatusCode(Event event) { diff --git a/semantic-convention-utils/src/main/java/org/hypertrace/semantic/convention/utils/rpc/RpcSemanticConventionUtils.java b/semantic-convention-utils/src/main/java/org/hypertrace/semantic/convention/utils/rpc/RpcSemanticConventionUtils.java index f1d3073ce..40f53cb15 100644 --- a/semantic-convention-utils/src/main/java/org/hypertrace/semantic/convention/utils/rpc/RpcSemanticConventionUtils.java +++ b/semantic-convention-utils/src/main/java/org/hypertrace/semantic/convention/utils/rpc/RpcSemanticConventionUtils.java @@ -6,16 +6,22 @@ import static org.hypertrace.core.span.constants.v1.Envoy.ENVOY_RESPONSE_SIZE; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_ERROR_MESSAGE; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_BODY; +import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_BODY_TRUNCATED; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_RESPONSE_BODY; +import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_RESPONSE_BODY_TRUNCATED; import static org.hypertrace.core.span.normalizer.constants.OTelSpanTag.OTEL_SPAN_TAG_RPC_METHOD; import static org.hypertrace.core.span.normalizer.constants.OTelSpanTag.OTEL_SPAN_TAG_RPC_SYSTEM; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_ERROR_MESSAGE; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_BODY; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_BODY_TRUNCATED; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_AUTHORITY; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_CONTENT_LENGTH; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_PATH; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_USER_AGENT; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_X_FORWARDED_FOR; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_BODY; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_BODY_TRUNCATED; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_METADATA_CONTENT_LENGTH; import com.google.common.base.Joiner; import com.google.common.base.Splitter; @@ -79,6 +85,28 @@ public class RpcSemanticConventionUtils { RawSpanConstants.getValue(CENSUS_RESPONSE_STATUS_MESSAGE), RawSpanConstants.getValue(ENVOY_GRPC_STATUS_MESSAGE)); + private static final String GRPC_REQUEST_BODY_TRUNCATED_ATTR = + RawSpanConstants.getValue(GRPC_REQUEST_BODY_TRUNCATED); + private static final String RPC_REQUEST_BODY_TRUNCATED_ATTR = + RPC_REQUEST_BODY_TRUNCATED.getValue(); + private static final String ENVOY_REQUEST_SIZE_ATTR = + RawSpanConstants.getValue(ENVOY_REQUEST_SIZE); + private static final String RPC_REQUEST_METADATA_CONTENT_LENGTH_ATTR = + RPC_REQUEST_METADATA_CONTENT_LENGTH.getValue(); + private static final String GRPC_REQUEST_BODY_ATTR = RawSpanConstants.getValue(GRPC_REQUEST_BODY); + private static final String RPC_REQUEST_BODY_ATTR = RPC_REQUEST_BODY.getValue(); + private static final String GRPC_RESPONSE_BODY_TRUNCATED_ATTR = + RawSpanConstants.getValue(GRPC_RESPONSE_BODY_TRUNCATED); + private static final String RPC_RESPONSE_BODY_TRUNCATED_ATTR = + RPC_RESPONSE_BODY_TRUNCATED.getValue(); + private static final String ENVOY_RESPONSE_SIZE_ATTR = + RawSpanConstants.getValue(ENVOY_RESPONSE_SIZE); + private static final String RPC_RESPONSE_METADATA_CONTENT_LENGTH_ATTR = + RPC_RESPONSE_METADATA_CONTENT_LENGTH.getValue(); + private static final String GRPC_RESPONSE_BODY_ATTR = + RawSpanConstants.getValue(GRPC_RESPONSE_BODY); + private static final String RPC_RESPONSE_BODY_ATTR = RPC_RESPONSE_BODY.getValue(); + /** * Differs from {@link * org.hypertrace.semantic.convention.utils.rpc.RpcSemanticConventionUtils#getGrpcURI(Event) in @@ -269,55 +297,99 @@ public static Optional getGrpcAuthority(Event event) { return Optional.empty(); } + private static boolean isGrpcRequestBodyTruncated(Map attributeValueMap) { + Optional attributeValue = + Optional.ofNullable(attributeValueMap.get(GRPC_REQUEST_BODY_TRUNCATED_ATTR)); + + return attributeValue.filter(av -> Boolean.parseBoolean(av.getValue())).isPresent(); + } + + private static boolean isRpcRequestBodyTruncated(Map attributeValueMap) { + Optional attributeValue = + Optional.ofNullable(attributeValueMap.get(RPC_REQUEST_BODY_TRUNCATED_ATTR)); + + return attributeValue.filter(av -> Boolean.parseBoolean(av.getValue())).isPresent(); + } + public static Optional getGrpcRequestSize(Event event) { if (event.getAttributes() == null || event.getAttributes().getAttributeMap() == null) { return Optional.empty(); } Map attributeValueMap = event.getAttributes().getAttributeMap(); - if ((attributeValueMap.get(RawSpanConstants.getValue(GRPC_REQUEST_BODY)) != null) - || (isRpcSystemGrpc(attributeValueMap) - && attributeValueMap.get(RPC_REQUEST_BODY.getValue()) != null)) { - - if (attributeValueMap.get(RawSpanConstants.getValue(ENVOY_REQUEST_SIZE)) != null) { - return Optional.of( - Integer.parseInt( - attributeValueMap.get(RawSpanConstants.getValue(ENVOY_REQUEST_SIZE)).getValue())); - } else if (attributeValueMap.get(RawSpanConstants.getValue(GRPC_REQUEST_BODY)) != null) { - String requestBody = - attributeValueMap.get(RawSpanConstants.getValue(GRPC_REQUEST_BODY)).getValue(); - return Optional.of(requestBody.length()); - } else if (attributeValueMap.get(RPC_REQUEST_BODY.getValue()) != null) { - String requestBody = attributeValueMap.get(RPC_REQUEST_BODY.getValue()).getValue(); - return Optional.of(requestBody.length()); - } + + Optional attributeValue = + Optional.ofNullable(attributeValueMap.get(ENVOY_REQUEST_SIZE_ATTR)); + if (attributeValue.isPresent()) { + return attributeValue.map(av -> av.getValue()).map(Integer::parseInt); + } + + attributeValue = + Optional.ofNullable(attributeValueMap.get(RPC_REQUEST_METADATA_CONTENT_LENGTH_ATTR)); + if (attributeValue.isPresent() && isRpcSystemGrpc(attributeValueMap)) { + return attributeValue.map(av -> av.getValue()).map(Integer::parseInt); + } + + attributeValue = Optional.ofNullable(attributeValueMap.get(GRPC_REQUEST_BODY_ATTR)); + if (attributeValue.isPresent() && !isGrpcRequestBodyTruncated(attributeValueMap)) { + return attributeValue.map(av -> av.getValue()).map(String::length); + } + + attributeValue = Optional.ofNullable(attributeValueMap.get(RPC_REQUEST_BODY_ATTR)); + if (attributeValue.isPresent() + && isRpcSystemGrpc(attributeValueMap) + && !isRpcRequestBodyTruncated(attributeValueMap)) { + return attributeValue.map(av -> av.getValue()).map(String::length); } + return Optional.empty(); } + private static boolean isGrpcResponseBodyTruncated( + Map attributeValueMap) { + Optional attributeValue = + Optional.ofNullable(attributeValueMap.get(GRPC_RESPONSE_BODY_TRUNCATED_ATTR)); + + return attributeValue.filter(av -> Boolean.parseBoolean(av.getValue())).isPresent(); + } + + private static boolean isRpcResponseBodyTruncated(Map attributeValueMap) { + Optional attributeValue = + Optional.ofNullable(attributeValueMap.get(RPC_RESPONSE_BODY_TRUNCATED_ATTR)); + + return attributeValue.filter(av -> Boolean.parseBoolean(av.getValue())).isPresent(); + } + public static Optional getGrpcResponseSize(Event event) { if (event.getAttributes() == null || event.getAttributes().getAttributeMap() == null) { return Optional.empty(); } Map attributeValueMap = event.getAttributes().getAttributeMap(); - if ((attributeValueMap.get(RawSpanConstants.getValue(GRPC_RESPONSE_BODY)) != null) - || (isRpcSystemGrpc(attributeValueMap) - && attributeValueMap.get(RPC_RESPONSE_BODY.getValue()) != null)) { - - if (attributeValueMap.get(RawSpanConstants.getValue(ENVOY_RESPONSE_SIZE)) != null) { - return Optional.of( - Integer.parseInt( - attributeValueMap.get(RawSpanConstants.getValue(ENVOY_RESPONSE_SIZE)).getValue())); - } else if (attributeValueMap.get(RawSpanConstants.getValue(GRPC_RESPONSE_BODY)) != null) { - String requestBody = - attributeValueMap.get(RawSpanConstants.getValue(GRPC_RESPONSE_BODY)).getValue(); - return Optional.of(requestBody.length()); - } else if (attributeValueMap.get(RPC_RESPONSE_BODY.getValue()) != null) { - String requestBody = attributeValueMap.get(RPC_RESPONSE_BODY.getValue()).getValue(); - return Optional.of(requestBody.length()); - } + Optional attributeValue = + Optional.ofNullable(attributeValueMap.get(ENVOY_RESPONSE_SIZE_ATTR)); + if (attributeValue.isPresent()) { + return attributeValue.map(av -> av.getValue()).map(Integer::parseInt); } + + attributeValue = + Optional.ofNullable(attributeValueMap.get(RPC_RESPONSE_METADATA_CONTENT_LENGTH_ATTR)); + if (attributeValue.isPresent() && isRpcSystemGrpc(attributeValueMap)) { + return attributeValue.map(av -> av.getValue()).map(Integer::parseInt); + } + + attributeValue = Optional.ofNullable(attributeValueMap.get(GRPC_RESPONSE_BODY_ATTR)); + if (attributeValue.isPresent() && !isGrpcResponseBodyTruncated(attributeValueMap)) { + return attributeValue.map(av -> av.getValue()).map(String::length); + } + + attributeValue = Optional.ofNullable(attributeValueMap.get(RPC_RESPONSE_BODY_ATTR)); + if (attributeValue.isPresent() + && isRpcSystemGrpc(attributeValueMap) + && !isRpcResponseBodyTruncated(attributeValueMap)) { + return attributeValue.map(av -> av.getValue()).map(String::length); + } + return Optional.empty(); } diff --git a/semantic-convention-utils/src/test/java/org/hypertrace/semantic/convention/utils/http/HttpSemanticConventionUtilsTest.java b/semantic-convention-utils/src/test/java/org/hypertrace/semantic/convention/utils/http/HttpSemanticConventionUtilsTest.java index fbf7211e7..0e8961444 100644 --- a/semantic-convention-utils/src/test/java/org/hypertrace/semantic/convention/utils/http/HttpSemanticConventionUtilsTest.java +++ b/semantic-convention-utils/src/test/java/org/hypertrace/semantic/convention/utils/http/HttpSemanticConventionUtilsTest.java @@ -13,7 +13,11 @@ import static org.hypertrace.core.span.constants.v1.CensusResponse.CENSUS_RESPONSE_CENSUS_STATUS_CODE; import static org.hypertrace.core.span.constants.v1.Envoy.ENVOY_REQUEST_SIZE; import static org.hypertrace.core.span.constants.v1.Envoy.ENVOY_RESPONSE_SIZE; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_HTTP_REQUEST_BODY; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_HTTP_RESPONSE_BODY; import static org.hypertrace.core.span.constants.v1.Http.HTTP_PATH; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_BODY_TRUNCATED; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_CONTENT_LENGTH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_CONTENT_TYPE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_HEADER_PATH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_METHOD; @@ -22,6 +26,8 @@ import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_SIZE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_URL; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_X_FORWARDED_FOR_HEADER; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_BODY_TRUNCATED; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_CONTENT_LENGTH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_SIZE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_USER_AGENT_REQUEST_HEADER; import static org.hypertrace.core.span.constants.v1.Http.HTTP_USER_AGENT_WITH_DASH; @@ -385,9 +391,35 @@ public void testGetHttpRequestSize() { OTelHttpSemanticConventions.HTTP_REQUEST_SIZE.getValue(), AttributeValue.newBuilder().setValue("150").build(), RawSpanConstants.getValue(HTTP_REQUEST_SIZE), - AttributeValue.newBuilder().setValue("200").build())) + AttributeValue.newBuilder().setValue("200").build(), + RawSpanConstants.getValue(HTTP_REQUEST_CONTENT_LENGTH), + AttributeValue.newBuilder().setValue("300").build(), + RawSpanConstants.getValue(HTTP_HTTP_REQUEST_BODY), + AttributeValue.newBuilder().setValue("Hello, there!").build())) .build()); assertEquals(Optional.of(100), HttpSemanticConventionUtils.getHttpRequestSize(event)); + + event = + createMockEventWithAttribute(RawSpanConstants.getValue(HTTP_REQUEST_CONTENT_LENGTH), "300"); + assertEquals(Optional.of(300), HttpSemanticConventionUtils.getHttpRequestSize(event)); + + event = + createMockEventWithAttribute( + RawSpanConstants.getValue(HTTP_HTTP_REQUEST_BODY), "Hello, there!"); + assertEquals(Optional.of(13), HttpSemanticConventionUtils.getHttpRequestSize(event)); + + event = mock(Event.class); + when(event.getAttributes()) + .thenReturn( + Attributes.newBuilder() + .setAttributeMap( + Map.of( + RawSpanConstants.getValue(HTTP_HTTP_REQUEST_BODY), + AttributeValue.newBuilder().setValue("Hello, there!").build(), + RawSpanConstants.getValue(HTTP_REQUEST_BODY_TRUNCATED), + AttributeValue.newBuilder().setValue("true").build())) + .build()); + assertEquals(Optional.empty(), HttpSemanticConventionUtils.getHttpRequestSize(event)); } @Test @@ -407,9 +439,36 @@ public void testGetHttpResponseSize() { RawSpanConstants.getValue(HTTP_RESPONSE_SIZE), AttributeValue.newBuilder().setValue("150").build(), OTelHttpSemanticConventions.HTTP_RESPONSE_SIZE.getValue(), - AttributeValue.newBuilder().setValue("200").build())) + AttributeValue.newBuilder().setValue("200").build(), + RawSpanConstants.getValue(HTTP_RESPONSE_CONTENT_LENGTH), + AttributeValue.newBuilder().setValue("300").build(), + RawSpanConstants.getValue(HTTP_HTTP_RESPONSE_BODY), + AttributeValue.newBuilder().setValue("Hello World!").build())) .build()); assertEquals(Optional.of(100), HttpSemanticConventionUtils.getHttpResponseSize(event)); + + event = + createMockEventWithAttribute( + RawSpanConstants.getValue(HTTP_RESPONSE_CONTENT_LENGTH), "300"); + assertEquals(Optional.of(300), HttpSemanticConventionUtils.getHttpResponseSize(event)); + + event = + createMockEventWithAttribute( + RawSpanConstants.getValue(HTTP_HTTP_RESPONSE_BODY), "Hello World!"); + assertEquals(Optional.of(12), HttpSemanticConventionUtils.getHttpResponseSize(event)); + + event = mock(Event.class); + when(event.getAttributes()) + .thenReturn( + Attributes.newBuilder() + .setAttributeMap( + Map.of( + RawSpanConstants.getValue(HTTP_HTTP_RESPONSE_BODY), + AttributeValue.newBuilder().setValue("Hello World!").build(), + RawSpanConstants.getValue(HTTP_RESPONSE_BODY_TRUNCATED), + AttributeValue.newBuilder().setValue("true").build())) + .build()); + assertEquals(Optional.empty(), HttpSemanticConventionUtils.getHttpResponseSize(event)); } @Test diff --git a/semantic-convention-utils/src/test/java/org/hypertrace/semantic/convention/utils/rpc/RpcSemanticConventionUtilsTest.java b/semantic-convention-utils/src/test/java/org/hypertrace/semantic/convention/utils/rpc/RpcSemanticConventionUtilsTest.java index 17b238286..014574d30 100644 --- a/semantic-convention-utils/src/test/java/org/hypertrace/semantic/convention/utils/rpc/RpcSemanticConventionUtilsTest.java +++ b/semantic-convention-utils/src/test/java/org/hypertrace/semantic/convention/utils/rpc/RpcSemanticConventionUtilsTest.java @@ -7,16 +7,22 @@ import static org.hypertrace.core.span.constants.v1.Envoy.ENVOY_RESPONSE_SIZE; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_ERROR_MESSAGE; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_BODY; +import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_BODY_TRUNCATED; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_RESPONSE_BODY; +import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_RESPONSE_BODY_TRUNCATED; import static org.hypertrace.core.span.normalizer.constants.OTelSpanTag.OTEL_SPAN_TAG_RPC_METHOD; import static org.hypertrace.core.span.normalizer.constants.OTelSpanTag.OTEL_SPAN_TAG_RPC_SYSTEM; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_ERROR_MESSAGE; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_BODY; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_BODY_TRUNCATED; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_AUTHORITY; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_CONTENT_LENGTH; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_PATH; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_USER_AGENT; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_X_FORWARDED_FOR; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_BODY; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_BODY_TRUNCATED; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_METADATA_CONTENT_LENGTH; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -366,6 +372,9 @@ public void testGetGrpcRequestSizePriority() { put( RawSpanConstants.getValue(ENVOY_REQUEST_SIZE), AttributeValue.newBuilder().setValue("1").build()); + put( + RPC_REQUEST_METADATA_CONTENT_LENGTH.getValue(), + AttributeValue.newBuilder().setValue("2").build()); put( RawSpanConstants.getValue(GRPC_REQUEST_BODY), AttributeValue.newBuilder().setValue("some grpc request body").build()); @@ -381,6 +390,27 @@ public void testGetGrpcRequestSizePriority() { .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); assertEquals(Optional.of(1), RpcSemanticConventionUtils.getGrpcRequestSize(event)); + tagsMap = + new HashMap<>() { + { + put( + RPC_REQUEST_METADATA_CONTENT_LENGTH.getValue(), + AttributeValue.newBuilder().setValue("2").build()); + put( + RawSpanConstants.getValue(GRPC_REQUEST_BODY), + AttributeValue.newBuilder().setValue("some grpc request body").build()); + put( + RPC_REQUEST_BODY.getValue(), + AttributeValue.newBuilder().setValue("some rpc request body").build()); + put("rpc.system", AttributeValue.newBuilder().setValue("grpc").build()); + } + }; + + event = mock(Event.class); + when(event.getAttributes()) + .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); + assertEquals(Optional.of(2), RpcSemanticConventionUtils.getGrpcRequestSize(event)); + tagsMap = new HashMap<>() { { @@ -413,6 +443,57 @@ public void testGetGrpcRequestSizePriority() { when(event.getAttributes()) .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); assertEquals(Optional.of(21), RpcSemanticConventionUtils.getGrpcRequestSize(event)); + + tagsMap = + new HashMap<>() { + { + put( + RPC_REQUEST_BODY.getValue(), + AttributeValue.newBuilder().setValue("some rpc request body").build()); + } + }; + + event = mock(Event.class); + when(event.getAttributes()) + .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); + assertEquals(Optional.empty(), RpcSemanticConventionUtils.getGrpcRequestSize(event)); + + // test truncated grpc request body + tagsMap = + new HashMap<>() { + { + put( + RawSpanConstants.getValue(GRPC_REQUEST_BODY), + AttributeValue.newBuilder().setValue("some grpc request body").build()); + put( + RawSpanConstants.getValue(GRPC_REQUEST_BODY_TRUNCATED), + AttributeValue.newBuilder().setValue("true").build()); + } + }; + + event = mock(Event.class); + when(event.getAttributes()) + .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); + assertEquals(Optional.empty(), RpcSemanticConventionUtils.getGrpcRequestSize(event)); + + // test truncated rpc request body + tagsMap = + new HashMap<>() { + { + put( + RPC_REQUEST_BODY.getValue(), + AttributeValue.newBuilder().setValue("some rpc request body").build()); + put("rpc.system", AttributeValue.newBuilder().setValue("grpc").build()); + put( + RPC_REQUEST_BODY_TRUNCATED.getValue(), + AttributeValue.newBuilder().setValue("true").build()); + } + }; + + event = mock(Event.class); + when(event.getAttributes()) + .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); + assertEquals(Optional.empty(), RpcSemanticConventionUtils.getGrpcRequestSize(event)); } @Test @@ -448,6 +529,9 @@ public void testGetGrpcResponseSizePriority() { put( RawSpanConstants.getValue(ENVOY_RESPONSE_SIZE), AttributeValue.newBuilder().setValue("1").build()); + put( + RPC_RESPONSE_METADATA_CONTENT_LENGTH.getValue(), + AttributeValue.newBuilder().setValue("2").build()); put( RawSpanConstants.getValue(GRPC_RESPONSE_BODY), AttributeValue.newBuilder().setValue("some grpc response body").build()); @@ -463,6 +547,27 @@ public void testGetGrpcResponseSizePriority() { .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); assertEquals(Optional.of(1), RpcSemanticConventionUtils.getGrpcResponseSize(event)); + tagsMap = + new HashMap<>() { + { + put( + RPC_RESPONSE_METADATA_CONTENT_LENGTH.getValue(), + AttributeValue.newBuilder().setValue("2").build()); + put( + RawSpanConstants.getValue(GRPC_RESPONSE_BODY), + AttributeValue.newBuilder().setValue("some grpc response body").build()); + put( + RPC_RESPONSE_BODY.getValue(), + AttributeValue.newBuilder().setValue("some rpc response body").build()); + put("rpc.system", AttributeValue.newBuilder().setValue("grpc").build()); + } + }; + + event = mock(Event.class); + when(event.getAttributes()) + .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); + assertEquals(Optional.of(2), RpcSemanticConventionUtils.getGrpcResponseSize(event)); + tagsMap = new HashMap<>() { { @@ -495,6 +600,57 @@ public void testGetGrpcResponseSizePriority() { when(event.getAttributes()) .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); assertEquals(Optional.of(22), RpcSemanticConventionUtils.getGrpcResponseSize(event)); + + tagsMap = + new HashMap<>() { + { + put( + RPC_RESPONSE_BODY.getValue(), + AttributeValue.newBuilder().setValue("some rpc response body").build()); + } + }; + + event = mock(Event.class); + when(event.getAttributes()) + .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); + assertEquals(Optional.empty(), RpcSemanticConventionUtils.getGrpcResponseSize(event)); + + // test truncated grpc response body + tagsMap = + new HashMap<>() { + { + put( + RawSpanConstants.getValue(GRPC_RESPONSE_BODY), + AttributeValue.newBuilder().setValue("some grpc response body").build()); + put( + RawSpanConstants.getValue(GRPC_RESPONSE_BODY_TRUNCATED), + AttributeValue.newBuilder().setValue("true").build()); + } + }; + + event = mock(Event.class); + when(event.getAttributes()) + .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); + assertEquals(Optional.empty(), RpcSemanticConventionUtils.getGrpcResponseSize(event)); + + // test truncated rpc response body + tagsMap = + new HashMap<>() { + { + put( + RPC_RESPONSE_BODY.getValue(), + AttributeValue.newBuilder().setValue("some rpc response body").build()); + put("rpc.system", AttributeValue.newBuilder().setValue("grpc").build()); + put( + RPC_RESPONSE_BODY_TRUNCATED.getValue(), + AttributeValue.newBuilder().setValue("true").build()); + } + }; + + event = mock(Event.class); + when(event.getAttributes()) + .thenReturn(Attributes.newBuilder().setAttributeMap(tagsMap).build()); + assertEquals(Optional.empty(), RpcSemanticConventionUtils.getGrpcResponseSize(event)); } @Test diff --git a/span-normalizer/raw-span-constants/src/main/proto/org/hypertrace/core/span/constants/v1/span_attribute.proto b/span-normalizer/raw-span-constants/src/main/proto/org/hypertrace/core/span/constants/v1/span_attribute.proto index acb876f5b..c9a79dc6f 100644 --- a/span-normalizer/raw-span-constants/src/main/proto/org/hypertrace/core/span/constants/v1/span_attribute.proto +++ b/span-normalizer/raw-span-constants/src/main/proto/org/hypertrace/core/span/constants/v1/span_attribute.proto @@ -67,6 +67,10 @@ enum Http { HTTP_REQUEST_HEADER_PATH = 36 [(string_value) = "http.request.header.:path"]; HTTP_REQUEST_BODY = 37 [(string_value) = "request.body"]; HTTP_RESPONSE_BODY = 38 [(string_value) = "response.body"]; + HTTP_REQUEST_CONTENT_LENGTH = 39 [(string_value) = "http.request.header.content-length"]; + HTTP_RESPONSE_CONTENT_LENGTH = 40 [(string_value) = "http.response.header.content-length"]; + HTTP_REQUEST_BODY_TRUNCATED = 41 [(string_value) = "http.request.body.truncated"]; + HTTP_RESPONSE_BODY_TRUNCATED = 42 [(string_value) = "http.response.body.truncated"]; } // Model View Controller framework related attributes @@ -90,6 +94,8 @@ enum Grpc { GRPC_ERROR_MESSAGE = 8 [(string_value) = "grpc.error_message"]; GRPC_HOST_PORT = 9 [(string_value) = "grpc.host_port"]; GRPC_METHOD = 10 [(string_value) = "grpc.method"]; + GRPC_REQUEST_BODY_TRUNCATED = 11 [(string_value) = "grpc.request.body.truncated"]; + GRPC_RESPONSE_BODY_TRUNCATED = 12 [(string_value) = "grpc.response.body.truncated"]; } // Error related attributes diff --git a/span-normalizer/span-normalizer-constants/src/main/java/org/hypertrace/core/span/normalizer/constants/RpcSpanTag.java b/span-normalizer/span-normalizer-constants/src/main/java/org/hypertrace/core/span/normalizer/constants/RpcSpanTag.java index b010b4d5c..dfcd27690 100644 --- a/span-normalizer/span-normalizer-constants/src/main/java/org/hypertrace/core/span/normalizer/constants/RpcSpanTag.java +++ b/span-normalizer/span-normalizer-constants/src/main/java/org/hypertrace/core/span/normalizer/constants/RpcSpanTag.java @@ -11,10 +11,14 @@ public enum RpcSpanTag { RPC_REQUEST_METADATA_X_FORWARDED_FOR("rpc.request.metadata.x-forwarded-for"), RPC_REQUEST_METADATA_AUTHORITY("rpc.request.metadata.:authority"), RPC_REQUEST_METADATA_CONTENT_TYPE("rpc.request.metadata.content-type"), + RPC_REQUEST_METADATA_CONTENT_LENGTH("rpc.request.metadata.content-length"), RPC_REQUEST_METADATA_PATH("rpc.request.metadata.:path"), RPC_REQUEST_METADATA_USER_AGENT("rpc.request.metadata.user-agent"), RPC_RESPONSE_METADATA_CONTENT_TYPE("rpc.response.metadata.content-type"), - RPC_BODY_DECODE_RAW("rpc.body.decode_raw"); + RPC_RESPONSE_METADATA_CONTENT_LENGTH("rpc.response.metadata.content-length"), + RPC_BODY_DECODE_RAW("rpc.body.decode_raw"), + RPC_REQUEST_BODY_TRUNCATED("rpc.request.body.truncated"), + RPC_RESPONSE_BODY_TRUNCATED("rpc.response.body.truncated"); private final String value; diff --git a/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/fieldgenerators/GrpcFieldsGenerator.java b/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/fieldgenerators/GrpcFieldsGenerator.java index 446c04d7f..8d2a5a1eb 100644 --- a/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/fieldgenerators/GrpcFieldsGenerator.java +++ b/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/fieldgenerators/GrpcFieldsGenerator.java @@ -8,19 +8,25 @@ import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_ERROR_NAME; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_HOST_PORT; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_BODY; +import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_BODY_TRUNCATED; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_CALL_OPTIONS; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_METADATA; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_RESPONSE_BODY; +import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_RESPONSE_BODY_TRUNCATED; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_RESPONSE_METADATA; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_ERROR_MESSAGE; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_ERROR_NAME; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_BODY; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_BODY_TRUNCATED; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_AUTHORITY; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_CONTENT_LENGTH; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_CONTENT_TYPE; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_PATH; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_USER_AGENT; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_X_FORWARDED_FOR; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_BODY; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_BODY_TRUNCATED; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_METADATA_CONTENT_LENGTH; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_METADATA_CONTENT_TYPE; import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_STATUS_CODE; @@ -126,6 +132,14 @@ private static Map> initializeFieldGenerato .getMetadata() .putAll(parseMetadataString(ValueConverter.getString(keyValue)))); + fieldGeneratorMap.put( + RawSpanConstants.getValue(ENVOY_REQUEST_SIZE), + (key, keyValue, builder, tagsMap) -> setRequestSize(builder, tagsMap)); + + fieldGeneratorMap.put( + RawSpanConstants.getValue(ENVOY_RESPONSE_SIZE), + (key, keyValue, builder, tagsMap) -> setResponseSize(builder, tagsMap)); + return fieldGeneratorMap; } @@ -206,6 +220,14 @@ private static Map> initializeRpcFieldGener .getResponseMetadataBuilder() .setContentType(ValueConverter.getString(keyValue))); + fieldGeneratorMap.put( + RPC_REQUEST_METADATA_CONTENT_LENGTH.getValue(), + (key, keyValue, builder, tagsMap) -> setRequestSize(builder, tagsMap)); + + fieldGeneratorMap.put( + RPC_RESPONSE_METADATA_CONTENT_LENGTH.getValue(), + (key, keyValue, builder, tagsMap) -> setResponseSize(builder, tagsMap)); + return fieldGeneratorMap; } @@ -239,16 +261,41 @@ private static void setRequestSize( .setSize( ValueConverter.getInteger( tagsMap.get(RawSpanConstants.getValue(ENVOY_REQUEST_SIZE)))); - } else if (tagsMap.containsKey(RawSpanConstants.getValue(GRPC_REQUEST_BODY))) { + } else if (tagsMap.containsKey(RPC_REQUEST_METADATA_CONTENT_LENGTH.getValue())) { + grpcBuilder + .getRequestBuilder() + .setSize( + ValueConverter.getInteger( + tagsMap.get(RPC_REQUEST_METADATA_CONTENT_LENGTH.getValue()))); + } else if (tagsMap.containsKey(RawSpanConstants.getValue(GRPC_REQUEST_BODY)) + && !isGrpcRequestBodyTruncated(tagsMap)) { String requestBody = ValueConverter.getString(tagsMap.get(RawSpanConstants.getValue(GRPC_REQUEST_BODY))); grpcBuilder.getRequestBuilder().setSize(requestBody.length()); - } else if (tagsMap.containsKey(RPC_REQUEST_BODY.getValue())) { + } else if (tagsMap.containsKey(RPC_REQUEST_BODY.getValue()) + && !isRpcRequestBodyTruncated(tagsMap)) { String requestBody = ValueConverter.getString(tagsMap.get(RPC_REQUEST_BODY.getValue())); grpcBuilder.getRequestBuilder().setSize(requestBody.length()); } } + private static boolean isGrpcRequestBodyTruncated( + Map tagsMap) { + if (tagsMap.containsKey(RawSpanConstants.getValue(GRPC_REQUEST_BODY_TRUNCATED))) { + return ValueConverter.getBoolean( + tagsMap.get(RawSpanConstants.getValue(GRPC_REQUEST_BODY_TRUNCATED))); + } + return false; + } + + private static boolean isRpcRequestBodyTruncated( + Map tagsMap) { + if (tagsMap.containsKey(RPC_REQUEST_BODY_TRUNCATED.getValue())) { + return ValueConverter.getBoolean(tagsMap.get(RPC_REQUEST_BODY_TRUNCATED.getValue())); + } + return false; + } + private static void setResponseSize( Grpc.Builder grpcBuilder, Map tagsMap) { if (tagsMap.containsKey(RawSpanConstants.getValue(ENVOY_RESPONSE_SIZE))) { @@ -257,16 +304,41 @@ private static void setResponseSize( .setSize( ValueConverter.getInteger( tagsMap.get(RawSpanConstants.getValue(ENVOY_RESPONSE_SIZE)))); - } else if (tagsMap.containsKey(RawSpanConstants.getValue(GRPC_RESPONSE_BODY))) { + } else if (tagsMap.containsKey(RPC_RESPONSE_METADATA_CONTENT_LENGTH.getValue())) { + grpcBuilder + .getResponseBuilder() + .setSize( + ValueConverter.getInteger( + tagsMap.get(RPC_RESPONSE_METADATA_CONTENT_LENGTH.getValue()))); + } else if (tagsMap.containsKey(RawSpanConstants.getValue(GRPC_RESPONSE_BODY)) + && !isGrpcResponseBodyTruncated(tagsMap)) { String responseBody = ValueConverter.getString(tagsMap.get(RawSpanConstants.getValue(GRPC_RESPONSE_BODY))); grpcBuilder.getResponseBuilder().setSize(responseBody.length()); - } else if (tagsMap.containsKey(RPC_RESPONSE_BODY.getValue())) { + } else if (tagsMap.containsKey(RPC_RESPONSE_BODY.getValue()) + && !isRpcResponseBodyTruncated(tagsMap)) { String responseBody = ValueConverter.getString(tagsMap.get(RPC_RESPONSE_BODY.getValue())); grpcBuilder.getResponseBuilder().setSize(responseBody.length()); } } + private static boolean isGrpcResponseBodyTruncated( + Map tagsMap) { + if (tagsMap.containsKey(RawSpanConstants.getValue(GRPC_RESPONSE_BODY_TRUNCATED))) { + return ValueConverter.getBoolean( + tagsMap.get(RawSpanConstants.getValue(GRPC_RESPONSE_BODY_TRUNCATED))); + } + return false; + } + + private static boolean isRpcResponseBodyTruncated( + Map tagsMap) { + if (tagsMap.containsKey(RPC_RESPONSE_BODY_TRUNCATED.getValue())) { + return ValueConverter.getBoolean(tagsMap.get(RPC_RESPONSE_BODY_TRUNCATED.getValue())); + } + return false; + } + private static Map parseMetadataString(String metadataString) { if (!metadataString.startsWith(METADATA_STR_VAL_PREFIX)) { return EMPTY_METADATA_MAP; diff --git a/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/fieldgenerators/HttpFieldsGenerator.java b/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/fieldgenerators/HttpFieldsGenerator.java index 60e3e1077..29a221dde 100644 --- a/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/fieldgenerators/HttpFieldsGenerator.java +++ b/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/fieldgenerators/HttpFieldsGenerator.java @@ -7,6 +7,8 @@ import static org.hypertrace.core.span.constants.v1.Http.HTTP_HTTP_RESPONSE_BODY; import static org.hypertrace.core.span.constants.v1.Http.HTTP_PATH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_AUTHORITY_HEADER; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_BODY_TRUNCATED; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_CONTENT_LENGTH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_CONTENT_TYPE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_COOKIE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_HEADER; @@ -20,6 +22,8 @@ import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_SIZE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_URL; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_X_FORWARDED_FOR_HEADER; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_BODY_TRUNCATED; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_CONTENT_LENGTH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_CONTENT_TYPE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_COOKIE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_HEADER; @@ -102,13 +106,15 @@ public class HttpFieldsGenerator extends ProtocolFieldsGenerator { List.of( RawSpanConstants.getValue(ENVOY_REQUEST_SIZE), RawSpanConstants.getValue(HTTP_REQUEST_SIZE), - OTelHttpSemanticConventions.HTTP_REQUEST_SIZE.getValue()); + OTelHttpSemanticConventions.HTTP_REQUEST_SIZE.getValue(), + RawSpanConstants.getValue(HTTP_REQUEST_CONTENT_LENGTH)); private static final List RESPONSE_SIZE_ATTRIBUTES = List.of( RawSpanConstants.getValue(ENVOY_RESPONSE_SIZE), RawSpanConstants.getValue(HTTP_RESPONSE_SIZE), - OTelHttpSemanticConventions.HTTP_RESPONSE_SIZE.getValue()); + OTelHttpSemanticConventions.HTTP_RESPONSE_SIZE.getValue(), + RawSpanConstants.getValue(HTTP_RESPONSE_CONTENT_LENGTH)); private static final List STATUS_CODE_ATTRIBUTES = List.of( @@ -362,14 +368,18 @@ private static Map> initializeFieldGenerato // Request Body fieldGeneratorMap.put( RawSpanConstants.getValue(HTTP_HTTP_REQUEST_BODY), - (key, keyValue, builder, tagsMap) -> - builder.getRequestBuilder().setBody(keyValue.getVStr())); + (key, keyValue, builder, tagsMap) -> { + builder.getRequestBuilder().setBody(keyValue.getVStr()); + setRequestSize(builder, tagsMap); + }); // Response Body fieldGeneratorMap.put( RawSpanConstants.getValue(HTTP_HTTP_RESPONSE_BODY), - (key, keyValue, builder, tagsMap) -> - builder.getResponseBuilder().setBody(keyValue.getVStr())); + (key, keyValue, builder, tagsMap) -> { + builder.getResponseBuilder().setBody(keyValue.getVStr()); + setResponseSize(builder, tagsMap); + }); // Request Size fieldGeneratorMap.put( @@ -381,6 +391,9 @@ private static Map> initializeFieldGenerato fieldGeneratorMap.put( OTelHttpSemanticConventions.HTTP_REQUEST_SIZE.getValue(), (key, keyValue, builder, tagsMap) -> setRequestSize(builder, tagsMap)); + fieldGeneratorMap.put( + RawSpanConstants.getValue(HTTP_REQUEST_CONTENT_LENGTH), + (key, keyValue, builder, tagsMap) -> setRequestSize(builder, tagsMap)); // Response Size fieldGeneratorMap.put( @@ -392,6 +405,9 @@ private static Map> initializeFieldGenerato fieldGeneratorMap.put( OTelHttpSemanticConventions.HTTP_RESPONSE_SIZE.getValue(), (key, keyValue, builder, tagsMap) -> setResponseSize(builder, tagsMap)); + fieldGeneratorMap.put( + RawSpanConstants.getValue(HTTP_RESPONSE_CONTENT_LENGTH), + (key, keyValue, builder, tagsMap) -> setResponseSize(builder, tagsMap)); // Response status and status code fieldGeneratorMap.put( @@ -498,6 +514,23 @@ private static void setRequestSize( FirstMatchingKeyFinder.getIntegerValueByFirstMatchingKey(tagsMap, REQUEST_SIZE_ATTRIBUTES) .ifPresent(size -> httpBuilder.getRequestBuilder().setSize(size)); + + if (!httpBuilder.getRequestBuilder().hasSize() + && !isRequestBodyTruncated(tagsMap) + && tagsMap.containsKey(RawSpanConstants.getValue(HTTP_HTTP_REQUEST_BODY))) { + String requestBody = + ValueConverter.getString(tagsMap.get(RawSpanConstants.getValue(HTTP_HTTP_REQUEST_BODY))); + httpBuilder.getRequestBuilder().setSize(requestBody.length()); + } + } + + private static boolean isRequestBodyTruncated( + Map tagsMap) { + if (tagsMap.containsKey(RawSpanConstants.getValue(HTTP_REQUEST_BODY_TRUNCATED))) { + return ValueConverter.getBoolean( + tagsMap.get(RawSpanConstants.getValue(HTTP_REQUEST_BODY_TRUNCATED))); + } + return false; } private static void setResponseSize( @@ -508,6 +541,23 @@ private static void setResponseSize( FirstMatchingKeyFinder.getIntegerValueByFirstMatchingKey(tagsMap, RESPONSE_SIZE_ATTRIBUTES) .ifPresent(size -> httpBuilder.getResponseBuilder().setSize(size)); + + if (!httpBuilder.getResponseBuilder().hasSize() + && !isResponseBodyTruncated(tagsMap) + && tagsMap.containsKey(RawSpanConstants.getValue(HTTP_HTTP_RESPONSE_BODY))) { + String responseBody = + ValueConverter.getString(tagsMap.get(RawSpanConstants.getValue(HTTP_HTTP_RESPONSE_BODY))); + httpBuilder.getResponseBuilder().setSize(responseBody.length()); + } + } + + private static boolean isResponseBodyTruncated( + Map tagsMap) { + if (tagsMap.containsKey(RawSpanConstants.getValue(HTTP_RESPONSE_BODY_TRUNCATED))) { + return ValueConverter.getBoolean( + tagsMap.get(RawSpanConstants.getValue(HTTP_RESPONSE_BODY_TRUNCATED))); + } + return false; } private static void setResponseStatusCode( diff --git a/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/fieldgenerators/GrpcFieldsGeneratorTest.java b/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/fieldgenerators/GrpcFieldsGeneratorTest.java index 43ac9101f..6d9865610 100644 --- a/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/fieldgenerators/GrpcFieldsGeneratorTest.java +++ b/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/fieldgenerators/GrpcFieldsGeneratorTest.java @@ -11,11 +11,21 @@ import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_HOST_PORT; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_METHOD; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_BODY; +import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_BODY_TRUNCATED; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_CALL_OPTIONS; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_REQUEST_METADATA; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_RESPONSE_BODY; +import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_RESPONSE_BODY_TRUNCATED; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_RESPONSE_METADATA; import static org.hypertrace.core.span.constants.v1.Grpc.GRPC_STATUS_CODE; +import static org.hypertrace.core.span.normalizer.constants.OTelRpcSystem.OTEL_RPC_SYSTEM_GRPC; +import static org.hypertrace.core.span.normalizer.constants.OTelSpanTag.OTEL_SPAN_TAG_RPC_SYSTEM; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_BODY; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_BODY_TRUNCATED; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_REQUEST_METADATA_CONTENT_LENGTH; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_BODY; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_BODY_TRUNCATED; +import static org.hypertrace.core.span.normalizer.constants.RpcSpanTag.RPC_RESPONSE_METADATA_CONTENT_LENGTH; import static org.hypertrace.core.spannormalizer.utils.TestUtils.createKeyValue; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -134,6 +144,329 @@ public void testGrpcFieldsConverterEnvoyRequestAndResponseSizeHigherPriority() { Assertions.assertEquals(400, grpcBuilder.getResponseBuilder().getSize()); } + @Test + public void testGrpcRequestSizeTagKeysPriority() { + GrpcFieldsGenerator grpcFieldsGenerator = new GrpcFieldsGenerator(); + RpcFieldsGenerator rpcFieldsGenerator = new RpcFieldsGenerator(grpcFieldsGenerator); + + // test 1: respect ENVOY_REQUEST_SIZE + Map tagsMap1 = new HashMap<>(); + tagsMap1.put(RawSpanConstants.getValue(ENVOY_REQUEST_SIZE), createKeyValue(100)); + tagsMap1.put( + RawSpanConstants.getValue(GRPC_REQUEST_BODY), createKeyValue("Hey Grpc, you there!!")); + + Map rpcTagsMap1 = new HashMap<>(); + rpcTagsMap1.put( + OTEL_SPAN_TAG_RPC_SYSTEM.getValue(), createKeyValue(OTEL_RPC_SYSTEM_GRPC.getValue())); + rpcTagsMap1.put(RPC_REQUEST_METADATA_CONTENT_LENGTH.getValue(), createKeyValue(200)); + rpcTagsMap1.put(RPC_REQUEST_BODY.getValue(), createKeyValue("Hey rpc, you there!!")); + + Map combinedTags1 = new HashMap<>(); + combinedTags1.putAll(tagsMap1); + combinedTags1.putAll(rpcTagsMap1); + + Event.Builder eventBuilder1 = Event.newBuilder(); + Grpc.Builder grpcBuilder1 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder1); + + tagsMap1.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder1, combinedTags1)); + + rpcTagsMap1.forEach( + (key, keyValue) -> + rpcFieldsGenerator.handleKeyIfNecessary(key, keyValue, eventBuilder1, combinedTags1)); + + assertEquals(100, grpcBuilder1.getRequestBuilder().getSize()); + + // test 2: respect RPC_REQUEST_METADATA_CONTENT_LENGTH + Map tagsMap2 = new HashMap<>(); + tagsMap2.put( + RawSpanConstants.getValue(GRPC_REQUEST_BODY), createKeyValue("Hey Grpc, you there!!")); + + Map rpcTagsMap2 = new HashMap<>(); + rpcTagsMap2.put( + OTEL_SPAN_TAG_RPC_SYSTEM.getValue(), createKeyValue(OTEL_RPC_SYSTEM_GRPC.getValue())); + rpcTagsMap2.put(RPC_REQUEST_METADATA_CONTENT_LENGTH.getValue(), createKeyValue(200)); + rpcTagsMap2.put(RPC_REQUEST_BODY.getValue(), createKeyValue("Hey rpc, you there!!")); + + Map combinedTags2 = new HashMap<>(); + combinedTags2.putAll(tagsMap2); + combinedTags2.putAll(rpcTagsMap2); + + Event.Builder eventBuilder2 = Event.newBuilder(); + Grpc.Builder grpcBuilder2 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder2); + + tagsMap2.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder2, combinedTags2)); + + rpcTagsMap2.forEach( + (key, keyValue) -> + rpcFieldsGenerator.handleKeyIfNecessary(key, keyValue, eventBuilder2, combinedTags2)); + + assertEquals(200, grpcBuilder2.getRequestBuilder().getSize()); + + // test 3: respect GRPC_REQUEST_BODY + Map tagsMap3 = new HashMap<>(); + tagsMap3.put( + RawSpanConstants.getValue(GRPC_REQUEST_BODY), createKeyValue("Hey Grpc, you there!!")); + + Map rpcTagsMap3 = new HashMap<>(); + rpcTagsMap3.put( + OTEL_SPAN_TAG_RPC_SYSTEM.getValue(), createKeyValue(OTEL_RPC_SYSTEM_GRPC.getValue())); + rpcTagsMap3.put(RPC_REQUEST_BODY.getValue(), createKeyValue("Hey rpc, you there!!")); + + Map combinedTags3 = new HashMap<>(); + combinedTags3.putAll(tagsMap3); + combinedTags3.putAll(rpcTagsMap3); + + Event.Builder eventBuilder3 = Event.newBuilder(); + Grpc.Builder grpcBuilder3 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder3); + + tagsMap3.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder3, combinedTags3)); + + rpcTagsMap3.forEach( + (key, keyValue) -> + rpcFieldsGenerator.handleKeyIfNecessary(key, keyValue, eventBuilder3, combinedTags3)); + + assertEquals(21, grpcBuilder3.getRequestBuilder().getSize()); + + // test 3.1: respect GRPC_REQUEST_BODY and tructed set to zero + Map tagsMap31 = new HashMap<>(); + tagsMap31.put( + RawSpanConstants.getValue(GRPC_REQUEST_BODY), createKeyValue("Hey Grpc, you there!!")); + + Map combinedTags31 = new HashMap<>(); + combinedTags31.putAll(tagsMap31); + combinedTags31.put( + RawSpanConstants.getValue(GRPC_REQUEST_BODY_TRUNCATED), createKeyValue("true")); + + Event.Builder eventBuilder31 = Event.newBuilder(); + Grpc.Builder grpcBuilder31 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder31); + + tagsMap31.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder31, combinedTags31)); + + assertEquals(0, grpcBuilder31.getRequestBuilder().getSize()); + + // test 4: respect RPC_REQUEST_BODY + Map tagsMap4 = new HashMap<>(); + Map rpcTagsMap4 = new HashMap<>(); + rpcTagsMap4.put( + OTEL_SPAN_TAG_RPC_SYSTEM.getValue(), createKeyValue(OTEL_RPC_SYSTEM_GRPC.getValue())); + rpcTagsMap4.put(RPC_REQUEST_BODY.getValue(), createKeyValue("Hey rpc, you there!!")); + + Map combinedTags4 = new HashMap<>(); + combinedTags4.putAll(tagsMap4); + combinedTags4.putAll(rpcTagsMap4); + + Event.Builder eventBuilder4 = Event.newBuilder(); + Grpc.Builder grpcBuilder4 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder4); + + tagsMap4.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder4, combinedTags4)); + + rpcTagsMap4.forEach( + (key, keyValue) -> + rpcFieldsGenerator.handleKeyIfNecessary(key, keyValue, eventBuilder4, combinedTags4)); + + assertEquals(20, grpcBuilder4.getRequestBuilder().getSize()); + + // test 4.1: respect RPC_REQUEST_BODY and truncated body + Map tagsMap41 = new HashMap<>(); + Map rpcTagsMap41 = new HashMap<>(); + rpcTagsMap41.put( + OTEL_SPAN_TAG_RPC_SYSTEM.getValue(), createKeyValue(OTEL_RPC_SYSTEM_GRPC.getValue())); + rpcTagsMap4.put(RPC_REQUEST_BODY.getValue(), createKeyValue("Hey rpc, you there!!")); + + Map combinedTags41 = new HashMap<>(); + combinedTags41.putAll(tagsMap41); + combinedTags41.putAll(rpcTagsMap41); + combinedTags41.put(RPC_REQUEST_BODY_TRUNCATED.getValue(), createKeyValue("true")); + + Event.Builder eventBuilder41 = Event.newBuilder(); + Grpc.Builder grpcBuilder41 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder41); + + tagsMap41.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder41, combinedTags41)); + + rpcTagsMap41.forEach( + (key, keyValue) -> + rpcFieldsGenerator.handleKeyIfNecessary(key, keyValue, eventBuilder41, combinedTags41)); + + assertEquals(0, grpcBuilder41.getRequestBuilder().getSize()); + } + + @Test + public void testGrpcResponseSizeTagKeysPriority() { + GrpcFieldsGenerator grpcFieldsGenerator = new GrpcFieldsGenerator(); + RpcFieldsGenerator rpcFieldsGenerator = new RpcFieldsGenerator(grpcFieldsGenerator); + + // test 1: respect ENVOY_RESPONSE_SIZE + Map tagsMap1 = new HashMap<>(); + tagsMap1.put(RawSpanConstants.getValue(ENVOY_RESPONSE_SIZE), createKeyValue(10)); + tagsMap1.put( + RawSpanConstants.getValue(GRPC_RESPONSE_BODY), createKeyValue("Hello from grpc!!")); + + Map rpcTagsMap1 = new HashMap<>(); + rpcTagsMap1.put( + OTEL_SPAN_TAG_RPC_SYSTEM.getValue(), createKeyValue(OTEL_RPC_SYSTEM_GRPC.getValue())); + rpcTagsMap1.put(RPC_RESPONSE_METADATA_CONTENT_LENGTH.getValue(), createKeyValue(20)); + rpcTagsMap1.put(RPC_RESPONSE_BODY.getValue(), createKeyValue("Hello from rpc!!")); + + Map combinedTags1 = new HashMap<>(); + combinedTags1.putAll(tagsMap1); + combinedTags1.putAll(rpcTagsMap1); + + Event.Builder eventBuilder1 = Event.newBuilder(); + Grpc.Builder grpcBuilder1 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder1); + + tagsMap1.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder1, combinedTags1)); + + rpcTagsMap1.forEach( + (key, keyValue) -> + rpcFieldsGenerator.handleKeyIfNecessary(key, keyValue, eventBuilder1, combinedTags1)); + + assertEquals(10, grpcBuilder1.getResponseBuilder().getSize()); + + // test 2: respect RPC_RESPONSE_METADATA_CONTENT_LENGTH + Map tagsMap2 = new HashMap<>(); + tagsMap2.put( + RawSpanConstants.getValue(GRPC_RESPONSE_BODY), createKeyValue("Hello from grpc!!")); + + Map rpcTagsMap2 = new HashMap<>(); + rpcTagsMap2.put( + OTEL_SPAN_TAG_RPC_SYSTEM.getValue(), createKeyValue(OTEL_RPC_SYSTEM_GRPC.getValue())); + rpcTagsMap2.put(RPC_RESPONSE_METADATA_CONTENT_LENGTH.getValue(), createKeyValue(200)); + rpcTagsMap2.put(RPC_RESPONSE_BODY.getValue(), createKeyValue("Hello from rpc!!")); + + Map combinedTags2 = new HashMap<>(); + combinedTags2.putAll(tagsMap2); + combinedTags2.putAll(rpcTagsMap2); + + Event.Builder eventBuilder2 = Event.newBuilder(); + Grpc.Builder grpcBuilder2 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder2); + + tagsMap2.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder2, combinedTags2)); + + rpcTagsMap2.forEach( + (key, keyValue) -> + rpcFieldsGenerator.handleKeyIfNecessary(key, keyValue, eventBuilder2, combinedTags2)); + + assertEquals(200, grpcBuilder2.getResponseBuilder().getSize()); + + // test 3: respect GRPC_RESPONSE_BODY + Map tagsMap3 = new HashMap<>(); + tagsMap3.put( + RawSpanConstants.getValue(GRPC_RESPONSE_BODY), createKeyValue("Hello from grpc!!")); + + Map rpcTagsMap3 = new HashMap<>(); + rpcTagsMap3.put( + OTEL_SPAN_TAG_RPC_SYSTEM.getValue(), createKeyValue(OTEL_RPC_SYSTEM_GRPC.getValue())); + rpcTagsMap3.put(RPC_RESPONSE_BODY.getValue(), createKeyValue("Hello from rpc!!")); + + Map combinedTags3 = new HashMap<>(); + combinedTags3.putAll(tagsMap3); + combinedTags3.putAll(rpcTagsMap3); + + Event.Builder eventBuilder3 = Event.newBuilder(); + Grpc.Builder grpcBuilder3 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder3); + + tagsMap3.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder3, combinedTags3)); + + rpcTagsMap3.forEach( + (key, keyValue) -> + rpcFieldsGenerator.handleKeyIfNecessary(key, keyValue, eventBuilder3, combinedTags3)); + + assertEquals(17, grpcBuilder3.getResponseBuilder().getSize()); + + // test 31: respect GRPC_RESPONSE_BODY and truncated body + Map tagsMap31 = new HashMap<>(); + tagsMap31.put( + RawSpanConstants.getValue(GRPC_RESPONSE_BODY), createKeyValue("Hello from grpc!!")); + + Map rpcTagsMap31 = new HashMap<>(); + + Map combinedTags31 = new HashMap<>(); + combinedTags31.putAll(tagsMap31); + combinedTags31.putAll(rpcTagsMap31); + combinedTags31.put( + RawSpanConstants.getValue(GRPC_RESPONSE_BODY_TRUNCATED), createKeyValue("true")); + + Event.Builder eventBuilder31 = Event.newBuilder(); + Grpc.Builder grpcBuilder31 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder31); + + tagsMap31.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder31, combinedTags31)); + + rpcTagsMap31.forEach( + (key, keyValue) -> + rpcFieldsGenerator.handleKeyIfNecessary(key, keyValue, eventBuilder31, combinedTags31)); + + assertEquals(0, grpcBuilder31.getResponseBuilder().getSize()); + + // test 4: respect RPC_RESPONSE_BODY + Map tagsMap4 = new HashMap<>(); + Map rpcTagsMap4 = new HashMap<>(); + rpcTagsMap4.put( + OTEL_SPAN_TAG_RPC_SYSTEM.getValue(), createKeyValue(OTEL_RPC_SYSTEM_GRPC.getValue())); + rpcTagsMap4.put(RPC_RESPONSE_BODY.getValue(), createKeyValue("Hello from rpc!!")); + + Map combinedTags4 = new HashMap<>(); + combinedTags4.putAll(tagsMap4); + combinedTags4.putAll(rpcTagsMap4); + + Event.Builder eventBuilder4 = Event.newBuilder(); + Grpc.Builder grpcBuilder4 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder4); + + tagsMap4.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder4, combinedTags4)); + + rpcTagsMap4.forEach( + (key, keyValue) -> + rpcFieldsGenerator.handleKeyIfNecessary(key, keyValue, eventBuilder4, combinedTags4)); + + assertEquals(16, grpcBuilder4.getResponseBuilder().getSize()); + + // test 41: respect RPC_RESPONSE_BODY and tructed rpc body + Map tagsMap41 = new HashMap<>(); + Map rpcTagsMap41 = new HashMap<>(); + rpcTagsMap41.put( + OTEL_SPAN_TAG_RPC_SYSTEM.getValue(), createKeyValue(OTEL_RPC_SYSTEM_GRPC.getValue())); + rpcTagsMap41.put(RPC_RESPONSE_BODY.getValue(), createKeyValue("Hello from rpc!!")); + + Map combinedTags41 = new HashMap<>(); + combinedTags41.putAll(tagsMap41); + combinedTags41.putAll(rpcTagsMap41); + combinedTags41.put(RPC_RESPONSE_BODY_TRUNCATED.getValue(), createKeyValue("true")); + + Event.Builder eventBuilder41 = Event.newBuilder(); + Grpc.Builder grpcBuilder41 = grpcFieldsGenerator.getProtocolBuilder(eventBuilder41); + + tagsMap41.forEach( + (key, keyValue) -> + grpcFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder41, combinedTags41)); + + rpcTagsMap41.forEach( + (key, keyValue) -> + rpcFieldsGenerator.handleKeyIfNecessary(key, keyValue, eventBuilder41, combinedTags41)); + + assertEquals(0, grpcBuilder41.getResponseBuilder().getSize()); + } + @Test public void testGrpcFieldsConverterStatusCodePriority() { GrpcFieldsGenerator grpcFieldsGenerator = new GrpcFieldsGenerator(); diff --git a/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/fieldgenerators/HttpFieldsGeneratorTest.java b/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/fieldgenerators/HttpFieldsGeneratorTest.java index 1fbd36c31..b7edaffa9 100644 --- a/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/fieldgenerators/HttpFieldsGeneratorTest.java +++ b/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/fieldgenerators/HttpFieldsGeneratorTest.java @@ -7,6 +7,8 @@ import static org.hypertrace.core.span.constants.v1.Http.HTTP_HTTP_RESPONSE_BODY; import static org.hypertrace.core.span.constants.v1.Http.HTTP_PATH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_AUTHORITY_HEADER; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_BODY_TRUNCATED; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_CONTENT_LENGTH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_CONTENT_TYPE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_COOKIE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_HEADER; @@ -20,6 +22,8 @@ import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_SIZE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_URL; import static org.hypertrace.core.span.constants.v1.Http.HTTP_REQUEST_X_FORWARDED_FOR_HEADER; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_BODY_TRUNCATED; +import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_CONTENT_LENGTH; import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_CONTENT_TYPE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_COOKIE; import static org.hypertrace.core.span.constants.v1.Http.HTTP_RESPONSE_HEADER; @@ -493,6 +497,10 @@ public void testRequestSizeTagKeysPriority() { Map tagsMap1 = new HashMap<>(); tagsMap1.put(RawSpanConstants.getValue(ENVOY_REQUEST_SIZE), createKeyValue(50)); tagsMap1.put(RawSpanConstants.getValue(HTTP_REQUEST_SIZE), createKeyValue(40)); + tagsMap1.put(OTelHttpSemanticConventions.HTTP_REQUEST_SIZE.getValue(), createKeyValue(30)); + tagsMap1.put(RawSpanConstants.getValue(HTTP_REQUEST_CONTENT_LENGTH), createKeyValue(20)); + tagsMap1.put( + RawSpanConstants.getValue(HTTP_HTTP_REQUEST_BODY), createKeyValue("Hello, there!")); Event.Builder eventBuilder1 = Event.newBuilder(); Http.Builder httpBuilder1 = httpFieldsGenerator.getProtocolBuilder(eventBuilder1); @@ -505,6 +513,8 @@ public void testRequestSizeTagKeysPriority() { Map tagsMap2 = new HashMap<>(); tagsMap2.put(RawSpanConstants.getValue(HTTP_REQUEST_SIZE), createKeyValue(35)); + tagsMap2.put(OTelHttpSemanticConventions.HTTP_REQUEST_SIZE.getValue(), createKeyValue(30)); + tagsMap2.put(RawSpanConstants.getValue(HTTP_REQUEST_CONTENT_LENGTH), createKeyValue(20)); Event.Builder eventBuilder2 = Event.newBuilder(); Http.Builder httpBuilder2 = httpFieldsGenerator.getProtocolBuilder(eventBuilder2); @@ -514,6 +524,61 @@ public void testRequestSizeTagKeysPriority() { httpFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder2, tagsMap2)); assertEquals(35, httpBuilder2.getRequestBuilder().getSize()); + + Map tagsMap3 = new HashMap<>(); + tagsMap3.put(OTelHttpSemanticConventions.HTTP_REQUEST_SIZE.getValue(), createKeyValue(30)); + tagsMap3.put(RawSpanConstants.getValue(HTTP_REQUEST_CONTENT_LENGTH), createKeyValue(20)); + + Event.Builder eventBuilder3 = Event.newBuilder(); + Http.Builder httpBuilder3 = httpFieldsGenerator.getProtocolBuilder(eventBuilder3); + + tagsMap3.forEach( + (key, keyValue) -> + httpFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder3, tagsMap3)); + + assertEquals(30, httpBuilder3.getRequestBuilder().getSize()); + + Map tagsMap4 = new HashMap<>(); + tagsMap4.put(RawSpanConstants.getValue(HTTP_REQUEST_CONTENT_LENGTH), createKeyValue(20)); + + Event.Builder eventBuilder4 = Event.newBuilder(); + Http.Builder httpBuilder4 = httpFieldsGenerator.getProtocolBuilder(eventBuilder4); + + tagsMap4.forEach( + (key, keyValue) -> + httpFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder4, tagsMap4)); + + assertEquals(20, httpBuilder4.getRequestBuilder().getSize()); + + Map tagsMap5 = new HashMap<>(); + tagsMap5.put( + RawSpanConstants.getValue(HTTP_HTTP_REQUEST_BODY), createKeyValue("Hello, there!")); + + Event.Builder eventBuilder5 = Event.newBuilder(); + Http.Builder httpBuilder5 = httpFieldsGenerator.getProtocolBuilder(eventBuilder5); + + tagsMap5.forEach( + (key, keyValue) -> + httpFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder5, tagsMap5)); + + assertEquals(13, httpBuilder5.getRequestBuilder().getSize()); + + // test for truncated body + Map tagsMap6 = new HashMap<>(); + tagsMap6.put( + RawSpanConstants.getValue(HTTP_HTTP_REQUEST_BODY), createKeyValue("Hello, there!")); + Map allTags = new HashMap<>(); + allTags.putAll(tagsMap6); + allTags.put(RawSpanConstants.getValue(HTTP_REQUEST_BODY_TRUNCATED), createKeyValue("true")); + + Event.Builder eventBuilder6 = Event.newBuilder(); + Http.Builder httpBuilder6 = httpFieldsGenerator.getProtocolBuilder(eventBuilder6); + + tagsMap6.forEach( + (key, keyValue) -> + httpFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder6, allTags)); + + assertEquals(0, httpBuilder6.getRequestBuilder().getSize()); } @Test @@ -523,6 +588,10 @@ public void testResponseSizeTagKeysPriority() { Map tagsMap1 = new HashMap<>(); tagsMap1.put(RawSpanConstants.getValue(ENVOY_RESPONSE_SIZE), createKeyValue(100)); tagsMap1.put(RawSpanConstants.getValue(HTTP_RESPONSE_SIZE), createKeyValue(90)); + tagsMap1.put(OTelHttpSemanticConventions.HTTP_RESPONSE_SIZE.getValue(), createKeyValue(80)); + tagsMap1.put(RawSpanConstants.getValue(HTTP_RESPONSE_CONTENT_LENGTH), createKeyValue(60)); + tagsMap1.put( + RawSpanConstants.getValue(HTTP_HTTP_RESPONSE_BODY), createKeyValue("Hello World!")); Event.Builder eventBuilder1 = Event.newBuilder(); Http.Builder httpBuilder1 = httpFieldsGenerator.getProtocolBuilder(eventBuilder1); @@ -535,6 +604,8 @@ public void testResponseSizeTagKeysPriority() { Map tagsMap2 = new HashMap<>(); tagsMap2.put(RawSpanConstants.getValue(HTTP_RESPONSE_SIZE), createKeyValue(85)); + tagsMap2.put(OTelHttpSemanticConventions.HTTP_RESPONSE_SIZE.getValue(), createKeyValue(80)); + tagsMap2.put(RawSpanConstants.getValue(HTTP_RESPONSE_CONTENT_LENGTH), createKeyValue(60)); Event.Builder eventBuilder2 = Event.newBuilder(); Http.Builder httpBuilder2 = httpFieldsGenerator.getProtocolBuilder(eventBuilder2); @@ -544,6 +615,61 @@ public void testResponseSizeTagKeysPriority() { httpFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder2, tagsMap2)); assertEquals(85, httpBuilder2.getResponseBuilder().getSize()); + + Map tagsMap3 = new HashMap<>(); + tagsMap3.put(OTelHttpSemanticConventions.HTTP_RESPONSE_SIZE.getValue(), createKeyValue(80)); + tagsMap3.put(RawSpanConstants.getValue(HTTP_RESPONSE_CONTENT_LENGTH), createKeyValue(60)); + + Event.Builder eventBuilder3 = Event.newBuilder(); + Http.Builder httpBuilder3 = httpFieldsGenerator.getProtocolBuilder(eventBuilder3); + + tagsMap3.forEach( + (key, keyValue) -> + httpFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder3, tagsMap3)); + + assertEquals(80, httpBuilder3.getResponseBuilder().getSize()); + + Map tagsMap4 = new HashMap<>(); + tagsMap4.put(RawSpanConstants.getValue(HTTP_RESPONSE_CONTENT_LENGTH), createKeyValue(60)); + + Event.Builder eventBuilder4 = Event.newBuilder(); + Http.Builder httpBuilder4 = httpFieldsGenerator.getProtocolBuilder(eventBuilder4); + + tagsMap4.forEach( + (key, keyValue) -> + httpFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder4, tagsMap4)); + + assertEquals(60, httpBuilder4.getResponseBuilder().getSize()); + + Map tagsMap5 = new HashMap<>(); + tagsMap5.put( + RawSpanConstants.getValue(HTTP_HTTP_RESPONSE_BODY), createKeyValue("Hello World!")); + + Event.Builder eventBuilder5 = Event.newBuilder(); + Http.Builder httpBuilder5 = httpFieldsGenerator.getProtocolBuilder(eventBuilder5); + + tagsMap5.forEach( + (key, keyValue) -> + httpFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder5, tagsMap5)); + + assertEquals(12, httpBuilder5.getResponseBuilder().getSize()); + + // test for truncated reponse body + Map tagsMap6 = new HashMap<>(); + tagsMap6.put( + RawSpanConstants.getValue(HTTP_HTTP_RESPONSE_BODY), createKeyValue("Hello World!")); + Map allTags = new HashMap<>(); + allTags.putAll(tagsMap6); + allTags.put(RawSpanConstants.getValue(HTTP_RESPONSE_BODY_TRUNCATED), createKeyValue("true")); + + Event.Builder eventBuilder6 = Event.newBuilder(); + Http.Builder httpBuilder6 = httpFieldsGenerator.getProtocolBuilder(eventBuilder6); + + tagsMap5.forEach( + (key, keyValue) -> + httpFieldsGenerator.addValueToBuilder(key, keyValue, eventBuilder6, allTags)); + + assertEquals(0, httpBuilder6.getResponseBuilder().getSize()); } @Test