diff --git a/.github/patches/opentelemetry-java-instrumentation.patch b/.github/patches/opentelemetry-java-instrumentation.patch index 6eda0e8374..895b5a7b90 100644 --- a/.github/patches/opentelemetry-java-instrumentation.patch +++ b/.github/patches/opentelemetry-java-instrumentation.patch @@ -1,3 +1,39 @@ +diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-annotations.txt b/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-annotations.txt +index 5c96ee4e2d..9eaed9b327 100644 +--- a/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-annotations.txt ++++ b/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-annotations.txt +@@ -1,2 +1,2 @@ +-Comparing source compatibility of opentelemetry-instrumentation-annotations-2.10.0.jar against opentelemetry-instrumentation-annotations-2.9.0.jar ++Comparing source compatibility of opentelemetry-instrumentation-annotations-2.10.0-adot1.jar against opentelemetry-instrumentation-annotations-2.10.0.jar + No changes. +\ No newline at end of file +diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt b/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt +index 577079fb0a..d00e7dbaff 100644 +--- a/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt ++++ b/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt +@@ -1,2 +1,2 @@ +-Comparing source compatibility of opentelemetry-instrumentation-api-2.10.0.jar against opentelemetry-instrumentation-api-2.9.0.jar ++Comparing source compatibility of opentelemetry-instrumentation-api-2.10.0-adot1.jar against opentelemetry-instrumentation-api-2.10.0.jar + No changes. +\ No newline at end of file +diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-spring-boot-autoconfigure.txt b/docs/apidiffs/current_vs_latest/opentelemetry-spring-boot-autoconfigure.txt +index af4a53135b..e4035e9b69 100644 +--- a/docs/apidiffs/current_vs_latest/opentelemetry-spring-boot-autoconfigure.txt ++++ b/docs/apidiffs/current_vs_latest/opentelemetry-spring-boot-autoconfigure.txt +@@ -1,2 +1,2 @@ +-Comparing source compatibility of opentelemetry-spring-boot-autoconfigure-2.10.0.jar against opentelemetry-spring-boot-autoconfigure-2.9.0.jar ++Comparing source compatibility of opentelemetry-spring-boot-autoconfigure-2.10.0-adot1.jar against opentelemetry-spring-boot-autoconfigure-2.10.0.jar + No changes. +\ No newline at end of file +diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-spring-boot-starter.txt b/docs/apidiffs/current_vs_latest/opentelemetry-spring-boot-starter.txt +index f49204917b..4611341aec 100644 +--- a/docs/apidiffs/current_vs_latest/opentelemetry-spring-boot-starter.txt ++++ b/docs/apidiffs/current_vs_latest/opentelemetry-spring-boot-starter.txt +@@ -1,2 +1,2 @@ +-Comparing source compatibility of opentelemetry-spring-boot-starter-2.10.0.jar against opentelemetry-spring-boot-starter-2.9.0.jar ++Comparing source compatibility of opentelemetry-spring-boot-starter-2.10.0-adot1.jar against opentelemetry-spring-boot-starter-2.10.0.jar + No changes. +\ No newline at end of file diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/build.gradle.kts b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/build.gradle.kts index f357a19f88..fa90530579 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/build.gradle.kts @@ -18,57 +54,57 @@ index f357a19f88..fa90530579 100644 testImplementation(project(":instrumentation:aws-sdk:aws-sdk-1.11:testing")) diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/groovy/S3TracingTest.groovy b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/groovy/S3TracingTest.groovy -index 987a50ed95..889c856a7c 100644 +index 8ba084ba02..a33d4c3bf4 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/groovy/S3TracingTest.groovy +++ b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/groovy/S3TracingTest.groovy -@@ -444,6 +444,7 @@ class S3TracingTest extends AgentInstrumentationSpecification { - "net.peer.port" { it == null || Number } - "$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long } - "$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long } +@@ -417,6 +417,7 @@ class S3TracingTest extends AgentInstrumentationSpecification { + "$ServerAttributes.SERVER_ADDRESS" String + "$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1" + "$ServerAttributes.SERVER_PORT" { it == null || Number } + "aws.sns.topic.arn" "$topicArn" } } } -@@ -467,6 +468,7 @@ class S3TracingTest extends AgentInstrumentationSpecification { - "net.peer.port" { it == null || Number } - "$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long } - "$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long } +@@ -439,6 +440,7 @@ class S3TracingTest extends AgentInstrumentationSpecification { + "$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1" + "$ServerAttributes.SERVER_PORT" { it == null || Number } + "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" topicArn + "aws.sns.topic.arn" "$topicArn" } } } -@@ -514,6 +516,7 @@ class S3TracingTest extends AgentInstrumentationSpecification { - "net.peer.port" { it == null || Number } - "$SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH" { it == null || it instanceof Long } - "$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" { it == null || it instanceof Long } +@@ -483,6 +485,7 @@ class S3TracingTest extends AgentInstrumentationSpecification { + "$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1" + "$ServerAttributes.SERVER_PORT" { it == null || Number } + "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" topicArn + "aws.sns.topic.arn" "$topicArn" } } } diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/groovy/SnsTracingTest.groovy b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/groovy/SnsTracingTest.groovy -index 97749cf085..a0b83ca870 100644 +index 0a22758122..f46ac90610 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/groovy/SnsTracingTest.groovy +++ b/instrumentation/aws-sdk/aws-sdk-1.11/javaagent/src/test/groovy/SnsTracingTest.groovy -@@ -131,6 +131,7 @@ class SnsTracingTest extends AgentInstrumentationSpecification { - "$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1" - "net.peer.port" { it == null || Number } - "$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long +@@ -132,6 +132,7 @@ class SnsTracingTest extends AgentInstrumentationSpecification { + "$ServerAttributes.SERVER_ADDRESS" String + "$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1" + "$ServerAttributes.SERVER_PORT" { it == null || Number } + "aws.sns.topic.arn" "$topicArn" } } } -@@ -154,6 +155,7 @@ class SnsTracingTest extends AgentInstrumentationSpecification { - "$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1" - "net.peer.port" { it == null || Number } - "$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long +@@ -155,6 +156,7 @@ class SnsTracingTest extends AgentInstrumentationSpecification { + "$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1" + "$ServerAttributes.SERVER_PORT" { it == null || Number } + "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" topicArn + "aws.sns.topic.arn" "$topicArn" } } } -@@ -176,6 +178,7 @@ class SnsTracingTest extends AgentInstrumentationSpecification { - "$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1" - "net.peer.port" { it == null || Number } - "$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long +@@ -177,6 +179,7 @@ class SnsTracingTest extends AgentInstrumentationSpecification { + "$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1" + "$ServerAttributes.SERVER_PORT" { it == null || Number } + "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" topicArn + "aws.sns.topic.arn" "$topicArn" } } @@ -250,52 +286,51 @@ index 0000000000..e890cb3c0f + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsExperimentalAttributes.java b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsExperimentalAttributes.java -index 3e8fddec5c..c0c2bb7de5 100644 +index 096c7826a1..a271b16da8 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsExperimentalAttributes.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsExperimentalAttributes.java -@@ -19,5 +19,37 @@ final class AwsExperimentalAttributes { +@@ -17,6 +17,36 @@ final class AwsExperimentalAttributes { + static final AttributeKey AWS_QUEUE_NAME = stringKey("aws.queue.name"); + static final AttributeKey AWS_STREAM_NAME = stringKey("aws.stream.name"); static final AttributeKey AWS_TABLE_NAME = stringKey("aws.table.name"); - static final AttributeKey AWS_REQUEST_ID = stringKey("aws.requestId"); - + static final AttributeKey AWS_AGENT_ID = stringKey("aws.bedrock.agent.id"); -+ + static final AttributeKey AWS_KNOWLEDGE_BASE_ID = + stringKey("aws.bedrock.knowledge_base.id"); -+ + static final AttributeKey AWS_DATA_SOURCE_ID = stringKey("aws.bedrock.data_source.id"); -+ + static final AttributeKey AWS_GUARDRAIL_ID = stringKey("aws.bedrock.guardrail.id"); -+ + static final AttributeKey AWS_GUARDRAIL_ARN = stringKey("aws.bedrock.guardrail.arn"); -+ + // TODO: Merge in gen_ai attributes in opentelemetry-semconv-incubating once upgrade to v1.26.0 + static final AttributeKey AWS_BEDROCK_RUNTIME_MODEL_ID = + stringKey("gen_ai.request.model"); -+ + static final AttributeKey AWS_BEDROCK_SYSTEM = stringKey("gen_ai.system"); -+ ++ static final AttributeKey GEN_AI_REQUEST_MAX_TOKENS = ++ stringKey("gen_ai.request.max_tokens"); ++ static final AttributeKey GEN_AI_REQUEST_TEMPERATURE = ++ stringKey("gen_ai.request.temperature"); ++ static final AttributeKey GEN_AI_REQUEST_TOP_P = stringKey("gen_ai.request.top_p"); ++ static final AttributeKey GEN_AI_RESPONSE_FINISH_REASONS = ++ stringKey("gen_ai.response.finish_reasons"); ++ static final AttributeKey GEN_AI_USAGE_INPUT_TOKENS = ++ stringKey("gen_ai.usage.input_tokens"); ++ static final AttributeKey GEN_AI_USAGE_OUTPUT_TOKENS = ++ stringKey("gen_ai.usage.output_tokens"); + static final AttributeKey AWS_STATE_MACHINE_ARN = + stringKey("aws.stepfunctions.state_machine.arn"); -+ + static final AttributeKey AWS_STEP_FUNCTIONS_ACTIVITY_ARN = + stringKey("aws.stepfunctions.activity.arn"); -+ + static final AttributeKey AWS_SNS_TOPIC_ARN = stringKey("aws.sns.topic.arn"); -+ + static final AttributeKey AWS_SECRET_ARN = stringKey("aws.secretsmanager.secret.arn"); -+ + static final AttributeKey AWS_LAMBDA_NAME = stringKey("aws.lambda.function.name"); -+ + static final AttributeKey AWS_LAMBDA_RESOURCE_ID = + stringKey("aws.lambda.resource_mapping.id"); -+ + private AwsExperimentalAttributes() {} } diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkExperimentalAttributesExtractor.java b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkExperimentalAttributesExtractor.java -index 245f09a5d8..d2bdf1c987 100644 +index 541e67d23b..6627348e73 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkExperimentalAttributesExtractor.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkExperimentalAttributesExtractor.java -@@ -6,11 +6,23 @@ +@@ -6,12 +6,30 @@ package io.opentelemetry.instrumentation.awssdk.v1_11; import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_AGENT; @@ -311,15 +346,22 @@ index 245f09a5d8..d2bdf1c987 100644 +import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_LAMBDA_RESOURCE_ID; import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_QUEUE_NAME; import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_QUEUE_URL; - import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_REQUEST_ID; +import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_SECRET_ARN; +import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_SNS_TOPIC_ARN; +import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_STATE_MACHINE_ARN; +import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_STEP_FUNCTIONS_ACTIVITY_ARN; import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_STREAM_NAME; import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.AWS_TABLE_NAME; ++import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.GEN_AI_REQUEST_MAX_TOKENS; ++import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.GEN_AI_REQUEST_TEMPERATURE; ++import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.GEN_AI_REQUEST_TOP_P; ++import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.GEN_AI_RESPONSE_FINISH_REASONS; ++import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.GEN_AI_USAGE_INPUT_TOKENS; ++import static io.opentelemetry.instrumentation.awssdk.v1_11.AwsExperimentalAttributes.GEN_AI_USAGE_OUTPUT_TOKENS; -@@ -21,12 +33,17 @@ import io.opentelemetry.api.common.AttributeKey; + import com.amazonaws.Request; + import com.amazonaws.Response; +@@ -19,12 +37,17 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; @@ -337,7 +379,7 @@ index 245f09a5d8..d2bdf1c987 100644 @Override public void onStart(AttributesBuilder attributes, Context parentContext, Request request) { -@@ -34,21 +51,29 @@ class AwsSdkExperimentalAttributesExtractor +@@ -32,14 +55,155 @@ class AwsSdkExperimentalAttributesExtractor attributes.put(AWS_ENDPOINT, request.getEndpoint().toString()); Object originalRequest = request.getOriginalRequest(); @@ -346,16 +388,6 @@ index 245f09a5d8..d2bdf1c987 100644 - setRequestAttribute(attributes, AWS_QUEUE_NAME, originalRequest, RequestAccess::getQueueName); - setRequestAttribute(attributes, AWS_STREAM_NAME, originalRequest, RequestAccess::getStreamName); - setRequestAttribute(attributes, AWS_TABLE_NAME, originalRequest, RequestAccess::getTableName); -- } -- -- private static void setRequestAttribute( -- AttributesBuilder attributes, -- AttributeKey key, -- Object request, -- Function getter) { -- String value = getter.apply(request); -- if (value != null) { -- attributes.put(key, value); + String requestClassName = originalRequest.getClass().getSimpleName(); + setAttribute(attributes, AWS_BUCKET_NAME, originalRequest, RequestAccess::getBucketName); + setAttribute(attributes, AWS_QUEUE_URL, originalRequest, RequestAccess::getQueueUrl); @@ -379,18 +411,16 @@ index 245f09a5d8..d2bdf1c987 100644 + // Extract request attributes only for Bedrock services. + if (isBedrockService(serviceName)) { + bedrockOnStart(attributes, originalRequest, requestClassName, serviceName); - } - } - -@@ -59,12 +84,117 @@ class AwsSdkExperimentalAttributesExtractor - Request request, - @Nullable Response response, - @Nullable Throwable error) { -- if (response != null && response.getAwsResponse() instanceof AmazonWebServiceResponse) { -- AmazonWebServiceResponse awsResp = (AmazonWebServiceResponse) response.getAwsResponse(); -- String requestId = awsResp.getRequestId(); -- if (requestId != null) { -- attributes.put(AWS_REQUEST_ID, requestId); ++ } ++ } ++ ++ @Override ++ public void onEnd( ++ AttributesBuilder attributes, ++ Context context, ++ Request request, ++ @Nullable Response response, ++ @Nullable Throwable error) { + if (response != null) { + Object awsResp = response.getAwsResponse(); + setAttribute(attributes, AWS_STATE_MACHINE_ARN, awsResp, RequestAccess::getStateMachineArn); @@ -401,21 +431,14 @@ index 245f09a5d8..d2bdf1c987 100644 + RequestAccess::getStepFunctionsActivityArn); + setAttribute(attributes, AWS_SNS_TOPIC_ARN, awsResp, RequestAccess::getSnsTopicArn); + setAttribute(attributes, AWS_SECRET_ARN, awsResp, RequestAccess::getSecretArn); -+ if (awsResp instanceof AmazonWebServiceResponse) { -+ AmazonWebServiceResponse awsWebServiceResponse = (AmazonWebServiceResponse) awsResp; -+ String requestId = awsWebServiceResponse.getRequestId(); -+ if (requestId != null) { -+ attributes.put(AWS_REQUEST_ID, requestId); -+ } -+ } + // Get serviceName defined in the AWS Java SDK V1 Request class. + String serviceName = request.getServiceName(); + // Extract response attributes for Bedrock services + if (awsResp != null && isBedrockService(serviceName)) { + bedrockOnEnd(attributes, awsResp, serviceName); - } - } - } ++ } ++ } ++ } + + private static void bedrockOnStart( + AttributesBuilder attributes, @@ -450,6 +473,14 @@ index 245f09a5d8..d2bdf1c987 100644 + Function getter = RequestAccess::getModelId; + String modelId = getter.apply(originalRequest); + attributes.put(AWS_BEDROCK_RUNTIME_MODEL_ID, modelId); ++ ++ setAttribute( ++ attributes, GEN_AI_REQUEST_MAX_TOKENS, originalRequest, RequestAccess::getMaxTokens); ++ setAttribute( ++ attributes, GEN_AI_REQUEST_TEMPERATURE, originalRequest, RequestAccess::getTemperature); ++ setAttribute(attributes, GEN_AI_REQUEST_TOP_P, originalRequest, RequestAccess::getTopP); ++ setAttribute( ++ attributes, GEN_AI_USAGE_INPUT_TOKENS, originalRequest, RequestAccess::getInputTokens); + break; + default: + break; @@ -479,6 +510,17 @@ index 245f09a5d8..d2bdf1c987 100644 + setAttribute(attributes, AWS_AGENT_ID, awsResp, RequestAccess::getAgentId); + setAttribute(attributes, AWS_KNOWLEDGE_BASE_ID, awsResp, RequestAccess::getKnowledgeBaseId); + break; ++ case BEDROCK_RUNTIME_SERVICE: ++ if (!Objects.equals(awsResp.getClass().getSimpleName(), "InvokeModelResult")) { ++ break; ++ } ++ ++ setAttribute(attributes, GEN_AI_USAGE_INPUT_TOKENS, awsResp, RequestAccess::getInputTokens); ++ setAttribute( ++ attributes, GEN_AI_USAGE_OUTPUT_TOKENS, awsResp, RequestAccess::getOutputTokens); ++ setAttribute( ++ attributes, GEN_AI_RESPONSE_FINISH_REASONS, awsResp, RequestAccess::getFinishReasons); ++ break; + default: + break; + } @@ -492,35 +534,259 @@ index 245f09a5d8..d2bdf1c987 100644 + || serviceName.equals(BEDROCK_AGENT_SERVICE) + || serviceName.equals(BEDROCK_AGENT_RUNTIME_SERVICE) + || serviceName.equals(BEDROCK_RUNTIME_SERVICE); -+ } -+ + } + +- private static void setRequestAttribute( + private static void setAttribute( -+ AttributesBuilder attributes, -+ AttributeKey key, -+ Object request, -+ Function getter) { -+ String value = getter.apply(request); -+ if (value != null) { -+ attributes.put(key, value); -+ } -+ } + AttributesBuilder attributes, + AttributeKey key, + Object request, +@@ -49,12 +213,4 @@ class AwsSdkExperimentalAttributesExtractor + attributes.put(key, value); + } + } +- +- @Override +- public void onEnd( +- AttributesBuilder attributes, +- Context context, +- Request request, +- @Nullable Response response, +- @Nullable Throwable error) {} } diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/RequestAccess.java b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/RequestAccess.java -index bb2ae9266c..36e216047f 100644 +index c212a69678..6a3db50881 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/RequestAccess.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/RequestAccess.java -@@ -8,6 +8,7 @@ package io.opentelemetry.instrumentation.awssdk.v1_11; +@@ -5,9 +5,17 @@ + + package io.opentelemetry.instrumentation.awssdk.v1_11; + ++import com.fasterxml.jackson.databind.JsonNode; ++import com.fasterxml.jackson.databind.ObjectMapper; ++import java.io.IOException; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.lang.reflect.Method; ++import java.nio.ByteBuffer; ++import java.util.Arrays; ++import java.util.Objects; ++import java.util.stream.Stream; import javax.annotation.Nullable; final class RequestAccess { -@@ -20,36 +21,158 @@ final class RequestAccess { +@@ -20,48 +28,383 @@ final class RequestAccess { } }; ++ private static final ObjectMapper objectMapper = new ObjectMapper(); ++ ++ @Nullable ++ private static JsonNode parseTargetBody(ByteBuffer buffer) { ++ try { ++ byte[] bytes; ++ // Create duplicate to avoid mutating the original buffer position ++ ByteBuffer duplicate = buffer.duplicate(); ++ if (buffer.hasArray()) { ++ bytes = ++ Arrays.copyOfRange( ++ duplicate.array(), ++ duplicate.arrayOffset(), ++ duplicate.arrayOffset() + duplicate.remaining()); ++ } else { ++ bytes = new byte[buffer.remaining()]; ++ buffer.get(bytes); ++ } ++ return objectMapper.readTree(bytes); ++ } catch (IOException e) { ++ return null; ++ } ++ } ++ ++ @Nullable ++ private static JsonNode getJsonBody(Object target) { ++ if (target == null) { ++ return null; ++ } ++ ++ RequestAccess access = REQUEST_ACCESSORS.get(target.getClass()); ++ ByteBuffer bodyBuffer = invokeOrNullGeneric(access.getBody, target, ByteBuffer.class); ++ if (bodyBuffer == null) { ++ return null; ++ } ++ ++ return parseTargetBody(bodyBuffer); ++ } ++ ++ @Nullable ++ private static String findFirstMatchingPath(JsonNode jsonBody, String... paths) { ++ if (jsonBody == null) { ++ return null; ++ } ++ ++ return Stream.of(paths) ++ .map( ++ path -> { ++ JsonNode node = jsonBody.at(path); ++ if (node != null && !node.isMissingNode()) { ++ return node.asText(); ++ } ++ return null; ++ }) ++ .filter(Objects::nonNull) ++ .findFirst() ++ .orElse(null); ++ } ++ ++ @Nullable ++ private static String approximateTokenCount(JsonNode jsonBody, String... textPaths) { ++ if (jsonBody == null) { ++ return null; ++ } ++ ++ return Stream.of(textPaths) ++ .map( ++ path -> { ++ JsonNode node = jsonBody.at(path); ++ if (node != null && !node.isMissingNode()) { ++ int tokenEstimate = (int) Math.ceil(node.asText().length() / 6.0); ++ return Integer.toString(tokenEstimate); ++ } ++ return null; ++ }) ++ .filter(Objects::nonNull) ++ .findFirst() ++ .orElse(null); ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/textGenerationConfig/maxTokenCount" ++ // Anthropic Claude -> "/max_tokens" ++ // Cohere Command -> "/max_tokens" ++ // Cohere Command R -> "/max_tokens" ++ // AI21 Jamba -> "/max_tokens" ++ // Meta Llama -> "/max_gen_len" ++ // Mistral AI -> "/max_tokens" ++ @Nullable ++ static String getMaxTokens(Object target) { ++ return findFirstMatchingPath( ++ getJsonBody(target), "/textGenerationConfig/maxTokenCount", "/max_tokens", "/max_gen_len"); ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/textGenerationConfig/temperature" ++ // Anthropic Claude -> "/temperature" ++ // Cohere Command -> "/temperature" ++ // Cohere Command R -> "/temperature" ++ // AI21 Jamba -> "/temperature" ++ // Meta Llama -> "/temperature" ++ // Mistral AI -> "/temperature" ++ @Nullable ++ static String getTemperature(Object target) { ++ return findFirstMatchingPath( ++ getJsonBody(target), "/textGenerationConfig/temperature", "/temperature"); ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/textGenerationConfig/topP" ++ // Anthropic Claude -> "/top_p" ++ // Cohere Command -> "/p" ++ // Cohere Command R -> "/p" ++ // AI21 Jamba -> "/top_p" ++ // Meta Llama -> "/top_p" ++ // Mistral AI -> "/top_p" ++ @Nullable ++ static String getTopP(Object target) { ++ return findFirstMatchingPath(getJsonBody(target), "/textGenerationConfig/topP", "/top_p", "/p"); ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/inputTextTokenCount" ++ // Anthropic Claude -> "/usage/input_tokens" ++ // Cohere Command -> "/prompt" ++ // Cohere Command R -> "/message" ++ // AI21 Jamba -> "/usage/prompt_tokens" ++ // Meta Llama -> "/prompt_token_count" ++ // Mistral AI -> "/prompt" ++ @Nullable ++ static String getInputTokens(Object target) { ++ JsonNode jsonBody = getJsonBody(target); ++ if (jsonBody == null) { ++ return null; ++ } ++ ++ // Try direct tokens counts first ++ String directCount = ++ findFirstMatchingPath( ++ jsonBody, ++ "/inputTextTokenCount", ++ "/usage/input_tokens", ++ "/usage/prompt_tokens", ++ "/prompt_token_count"); ++ ++ if (directCount != null) { ++ return directCount; ++ } ++ ++ // Fall back to token approximation ++ return approximateTokenCount(jsonBody, "/prompt", "/message"); ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/results/0/tokenCount" ++ // Anthropic Claude -> "/usage/output_tokens" ++ // Cohere Command -> "/generations/0/text" ++ // Cohere Command R -> "/text" ++ // AI21 Jamba -> "/usage/completion_tokens" ++ // Meta Llama -> "/generation_token_count" ++ // Mistral AI -> "/outputs/0/text" ++ @Nullable ++ static String getOutputTokens(Object target) { ++ JsonNode jsonBody = getJsonBody(target); ++ if (jsonBody == null) { ++ return null; ++ } ++ ++ // Try direct token counts first ++ String directCount = ++ findFirstMatchingPath( ++ jsonBody, ++ "/results/0/tokenCount", ++ "/usage/output_tokens", ++ "/usage/completion_tokens", ++ "/generation_token_count"); ++ ++ if (directCount != null) { ++ return directCount; ++ } ++ ++ return approximateTokenCount(jsonBody, "/outputs/0/text", "/text"); ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/results/0/completionReason" ++ // Anthropic Claude -> "/stop_reason" ++ // Cohere Command -> "/generations/0/finish_reason" ++ // Cohere Command R -> "/finish_reason" ++ // AI21 Jamba -> "/choices/0/finish_reason" ++ // Meta Llama -> "/stop_reason" ++ // Mistral AI -> "/outputs/0/stop_reason" ++ @Nullable ++ static String getFinishReasons(Object target) { ++ String finishReason = ++ findFirstMatchingPath( ++ getJsonBody(target), ++ "/results/0/completionReason", ++ "/stop_reason", ++ "/generations/0/finish_reason", ++ "/choices/0/finish_reason", ++ "/outputs/0/stop_reason", ++ "/finish_reason"); ++ ++ return finishReason != null ? "[" + finishReason + "]" : null; ++ } ++ + @Nullable + static String getLambdaName(Object request) { + if (request == null) { @@ -620,6 +886,24 @@ index bb2ae9266c..36e216047f 100644 return invokeOrNull(access.getTableName, request); } + @Nullable + static String getTopicArn(Object request) { ++ if (request == null) { ++ return null; ++ } + RequestAccess access = REQUEST_ACCESSORS.get(request.getClass()); + return invokeOrNull(access.getTopicArn, request); + } + + @Nullable + static String getTargetArn(Object request) { ++ if (request == null) { ++ return null; ++ } + RequestAccess access = REQUEST_ACCESSORS.get(request.getClass()); + return invokeOrNull(access.getTargetArn, request); + } + + @Nullable + static String getAgentId(Object request) { + if (request == null) { @@ -676,15 +960,36 @@ index bb2ae9266c..36e216047f 100644 @Nullable private static String invokeOrNull(@Nullable MethodHandle method, Object obj) { if (method == null) { -@@ -67,6 +190,17 @@ final class RequestAccess { +@@ -74,6 +417,19 @@ final class RequestAccess { + } + } + ++ @Nullable ++ private static T invokeOrNullGeneric( ++ @Nullable MethodHandle method, Object obj, Class returnType) { ++ if (method == null) { ++ return null; ++ } ++ try { ++ return returnType.cast(method.invoke(obj)); ++ } catch (Throwable e) { ++ return null; ++ } ++ } ++ + @Nullable private final MethodHandle getBucketName; + @Nullable private final MethodHandle getQueueUrl; @Nullable private final MethodHandle getQueueName; - @Nullable private final MethodHandle getStreamName; +@@ -81,24 +437,66 @@ final class RequestAccess { @Nullable private final MethodHandle getTableName; + @Nullable private final MethodHandle getTopicArn; + @Nullable private final MethodHandle getTargetArn; + @Nullable private final MethodHandle getAgentId; + @Nullable private final MethodHandle getKnowledgeBaseId; + @Nullable private final MethodHandle getDataSourceId; + @Nullable private final MethodHandle getGuardrailId; + @Nullable private final MethodHandle getModelId; ++ @Nullable private final MethodHandle getBody; + @Nullable private final MethodHandle getStateMachineArn; + @Nullable private final MethodHandle getStepFunctionsActivityArn; + @Nullable private final MethodHandle getSnsTopicArn; @@ -693,26 +998,43 @@ index bb2ae9266c..36e216047f 100644 + @Nullable private final MethodHandle getLambdaResourceId; private RequestAccess(Class clz) { - getBucketName = findAccessorOrNull(clz, "getBucketName"); -@@ -74,6 +208,17 @@ final class RequestAccess { - getQueueName = findAccessorOrNull(clz, "getQueueName"); - getStreamName = findAccessorOrNull(clz, "getStreamName"); - getTableName = findAccessorOrNull(clz, "getTableName"); -+ getAgentId = findAccessorOrNull(clz, "getAgentId"); -+ getKnowledgeBaseId = findAccessorOrNull(clz, "getKnowledgeBaseId"); -+ getDataSourceId = findAccessorOrNull(clz, "getDataSourceId"); -+ getGuardrailId = findAccessorOrNull(clz, "getGuardrailId"); -+ getModelId = findAccessorOrNull(clz, "getModelId"); -+ getStateMachineArn = findAccessorOrNull(clz, "getStateMachineArn"); -+ getStepFunctionsActivityArn = findAccessorOrNull(clz, "getActivityArn"); -+ getSnsTopicArn = findAccessorOrNull(clz, "getTopicArn"); -+ getSecretArn = findAccessorOrNull(clz, "getARN"); -+ getLambdaName = findAccessorOrNull(clz, "getFunctionName"); -+ getLambdaResourceId = findAccessorOrNull(clz, "getUUID"); +- getBucketName = findAccessorOrNull(clz, "getBucketName"); +- getQueueUrl = findAccessorOrNull(clz, "getQueueUrl"); +- getQueueName = findAccessorOrNull(clz, "getQueueName"); +- getStreamName = findAccessorOrNull(clz, "getStreamName"); +- getTableName = findAccessorOrNull(clz, "getTableName"); +- getTopicArn = findAccessorOrNull(clz, "getTopicArn"); +- getTargetArn = findAccessorOrNull(clz, "getTargetArn"); ++ getBucketName = findAccessorOrNull(clz, "getBucketName", String.class); ++ getQueueUrl = findAccessorOrNull(clz, "getQueueUrl", String.class); ++ getQueueName = findAccessorOrNull(clz, "getQueueName", String.class); ++ getStreamName = findAccessorOrNull(clz, "getStreamName", String.class); ++ getTableName = findAccessorOrNull(clz, "getTableName", String.class); ++ getTopicArn = findAccessorOrNull(clz, "getTopicArn", String.class); ++ getTargetArn = findAccessorOrNull(clz, "getTargetArn", String.class); ++ getAgentId = findAccessorOrNull(clz, "getAgentId", String.class); ++ getKnowledgeBaseId = findAccessorOrNull(clz, "getKnowledgeBaseId", String.class); ++ getDataSourceId = findAccessorOrNull(clz, "getDataSourceId", String.class); ++ getGuardrailId = findAccessorOrNull(clz, "getGuardrailId", String.class); ++ getModelId = findAccessorOrNull(clz, "getModelId", String.class); ++ getBody = findAccessorOrNull(clz, "getBody", ByteBuffer.class); ++ getStateMachineArn = findAccessorOrNull(clz, "getStateMachineArn", String.class); ++ getStepFunctionsActivityArn = findAccessorOrNull(clz, "getActivityArn", String.class); ++ getSnsTopicArn = findAccessorOrNull(clz, "getTopicArn", String.class); ++ getSecretArn = findAccessorOrNull(clz, "getARN", String.class); ++ getLambdaName = findAccessorOrNull(clz, "getFunctionName", String.class); ++ getLambdaResourceId = findAccessorOrNull(clz, "getUUID", String.class); } @Nullable -@@ -85,4 +230,21 @@ final class RequestAccess { +- private static MethodHandle findAccessorOrNull(Class clz, String methodName) { ++ private static MethodHandle findAccessorOrNull( ++ Class clz, String methodName, Class returnType) { + try { + return MethodHandles.publicLookup() +- .findVirtual(clz, methodName, MethodType.methodType(String.class)); ++ .findVirtual(clz, methodName, MethodType.methodType(returnType)); + } catch (Throwable t) { return null; } } @@ -735,7 +1057,7 @@ index bb2ae9266c..36e216047f 100644 + } } diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/build.gradle.kts b/instrumentation/aws-sdk/aws-sdk-1.11/testing/build.gradle.kts -index 548631e9f1..51483839a7 100644 +index 545f5dffce..227a205ebd 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/testing/build.gradle.kts +++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/build.gradle.kts @@ -14,6 +14,14 @@ dependencies { @@ -752,135 +1074,624 @@ index 548631e9f1..51483839a7 100644 + compileOnly("com.amazonaws:aws-java-sdk-bedrockruntime:1.12.744") // needed for SQS - using emq directly as localstack references emq v0.15.7 ie WITHOUT AWS trace header propagation - implementation("org.elasticmq:elasticmq-rest-sqs_2.12:1.0.0") -diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractAws1ClientTest.groovy b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractAws1ClientTest.groovy -index 95e6ed8985..48fb10624e 100644 ---- a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractAws1ClientTest.groovy -+++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractAws1ClientTest.groovy -@@ -27,6 +27,24 @@ import com.amazonaws.services.rds.AmazonRDSClientBuilder - import com.amazonaws.services.rds.model.DeleteOptionGroupRequest - import com.amazonaws.services.s3.AmazonS3Client - import com.amazonaws.services.s3.AmazonS3ClientBuilder -+import com.amazonaws.services.bedrockagent.AWSBedrockAgentClientBuilder -+import com.amazonaws.services.bedrockagent.model.GetAgentRequest -+import com.amazonaws.services.bedrockagent.model.GetKnowledgeBaseRequest -+import com.amazonaws.services.bedrockagent.model.GetDataSourceRequest -+import com.amazonaws.services.bedrock.AmazonBedrockClientBuilder -+import com.amazonaws.services.bedrock.model.GetGuardrailRequest -+import com.amazonaws.services.bedrockruntime.AmazonBedrockRuntimeClientBuilder -+import com.amazonaws.services.bedrockruntime.model.InvokeModelRequest -+import com.amazonaws.services.stepfunctions.AWSStepFunctionsClientBuilder -+import com.amazonaws.services.stepfunctions.model.DescribeStateMachineRequest -+import com.amazonaws.services.stepfunctions.model.DescribeActivityRequest -+import com.amazonaws.services.sns.AmazonSNSClientBuilder -+import com.amazonaws.services.sns.model.PublishRequest -+import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder -+import com.amazonaws.services.secretsmanager.model.CreateSecretRequest -+import com.amazonaws.services.lambda.AWSLambdaClientBuilder -+import com.amazonaws.services.lambda.model.GetEventSourceMappingRequest -+import com.amazonaws.services.lambda.model.GetFunctionRequest - import io.opentelemetry.api.trace.Span - import io.opentelemetry.instrumentation.test.InstrumentationSpecification - import io.opentelemetry.semconv.SemanticAttributes -@@ -38,6 +56,7 @@ import spock.lang.Shared - import spock.lang.Unroll + implementation("org.elasticmq:elasticmq-rest-sqs_2.13") +diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractBedrockAgentClientTest.java b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractBedrockAgentClientTest.java +new file mode 100644 +index 0000000000..d107f250bb +--- /dev/null ++++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractBedrockAgentClientTest.java +@@ -0,0 +1,91 @@ ++/* ++ * Copyright The OpenTelemetry Authors ++ * SPDX-License-Identifier: Apache-2.0 ++ */ ++ ++package io.opentelemetry.instrumentation.awssdk.v1_11; ++ ++import com.amazonaws.services.bedrockagent.AWSBedrockAgent; ++import com.amazonaws.services.bedrockagent.AWSBedrockAgentClientBuilder; ++import com.amazonaws.services.bedrockagent.model.GetAgentRequest; ++import com.amazonaws.services.bedrockagent.model.GetDataSourceRequest; ++import com.amazonaws.services.bedrockagent.model.GetKnowledgeBaseRequest; ++import com.google.common.collect.ImmutableMap; ++import io.opentelemetry.testing.internal.armeria.common.HttpResponse; ++import io.opentelemetry.testing.internal.armeria.common.HttpStatus; ++import io.opentelemetry.testing.internal.armeria.common.MediaType; ++import java.util.Map; ++import org.junit.jupiter.api.Test; ++ ++public abstract class AbstractBedrockAgentClientTest extends AbstractBaseAwsClientTest { ++ ++ public abstract AWSBedrockAgentClientBuilder configureClient(AWSBedrockAgentClientBuilder client); ++ ++ @Override ++ protected boolean hasRequestId() { ++ return true; ++ } ++ ++ @Test ++ public void sendGetAgentRequest() throws Exception { ++ AWSBedrockAgent client = createClient(); ++ ++ server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.JSON_UTF_8, "{}")); ++ ++ Object response = client.getAgent(new GetAgentRequest().withAgentId("agentId")); ++ ++ assertRequestWithMockedResponse( ++ response, ++ client, ++ "AWSBedrockAgent", ++ "GetAgent", ++ "GET", ++ ImmutableMap.of("aws.bedrock.agent.id", "agentId")); ++ } ++ ++ @Test ++ public void sendGetKnowledgeBaseRequest() throws Exception { ++ AWSBedrockAgent client = createClient(); ++ ++ server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.JSON_UTF_8, "{}")); ++ ++ Object response = ++ client.getKnowledgeBase( ++ new GetKnowledgeBaseRequest().withKnowledgeBaseId("knowledgeBaseId")); ++ ++ assertRequestWithMockedResponse( ++ response, ++ client, ++ "AWSBedrockAgent", ++ "GetKnowledgeBase", ++ "GET", ++ ImmutableMap.of("aws.bedrock.knowledge_base.id", "knowledgeBaseId")); ++ } ++ ++ @Test ++ public void sendGetDataSourceRequest() throws Exception { ++ AWSBedrockAgent client = createClient(); ++ ++ server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.JSON_UTF_8, "{}")); ++ ++ Object response = ++ client.getDataSource( ++ new GetDataSourceRequest() ++ .withDataSourceId("datasourceId") ++ .withKnowledgeBaseId("knowledgeBaseId")); ++ ++ Map additionalAttributes = ++ ImmutableMap.of("aws.bedrock.data_source.id", "datasourceId"); ++ ++ assertRequestWithMockedResponse( ++ response, client, "AWSBedrockAgent", "GetDataSource", "GET", additionalAttributes); ++ } ++ ++ private AWSBedrockAgent createClient() { ++ AWSBedrockAgentClientBuilder clientBuilder = AWSBedrockAgentClientBuilder.standard(); ++ return configureClient(clientBuilder) ++ .withEndpointConfiguration(endpoint) ++ .withCredentials(credentialsProvider) ++ .build(); ++ } ++} +diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractBedrockClientTest.java b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractBedrockClientTest.java +new file mode 100644 +index 0000000000..498fbc2433 +--- /dev/null ++++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractBedrockClientTest.java +@@ -0,0 +1,76 @@ ++/* ++ * Copyright The OpenTelemetry Authors ++ * SPDX-License-Identifier: Apache-2.0 ++ */ ++ ++package io.opentelemetry.instrumentation.awssdk.v1_11; ++ ++import com.amazonaws.services.bedrock.AmazonBedrock; ++import com.amazonaws.services.bedrock.AmazonBedrockClientBuilder; ++import com.amazonaws.services.bedrock.model.GetGuardrailRequest; ++import com.google.common.collect.ImmutableMap; ++import io.opentelemetry.testing.internal.armeria.common.HttpResponse; ++import io.opentelemetry.testing.internal.armeria.common.HttpStatus; ++import io.opentelemetry.testing.internal.armeria.common.MediaType; ++import org.junit.jupiter.api.Test; ++ ++public abstract class AbstractBedrockClientTest extends AbstractBaseAwsClientTest { ++ ++ public abstract AmazonBedrockClientBuilder configureClient(AmazonBedrockClientBuilder client); ++ ++ @Override ++ protected boolean hasRequestId() { ++ return true; ++ } ++ ++ @Test ++ public void sendRequestWithMockedResponse() throws Exception { ++ AmazonBedrockClientBuilder clientBuilder = AmazonBedrockClientBuilder.standard(); ++ AmazonBedrock client = ++ configureClient(clientBuilder) ++ .withEndpointConfiguration(endpoint) ++ .withCredentials(credentialsProvider) ++ .build(); ++ ++ String body = ++ "{" ++ + " \"blockedInputMessaging\": \"string\"," ++ + " \"blockedOutputsMessaging\": \"string\"," ++ + " \"contentPolicy\": {}," ++ + " \"createdAt\": \"2024-06-12T18:31:45Z\"," ++ + " \"description\": \"string\"," ++ + " \"guardrailArn\": \"guardrailArn\"," ++ + " \"guardrailId\": \"guardrailId\"," ++ + " \"kmsKeyArn\": \"string\"," ++ + " \"name\": \"string\"," ++ + " \"sensitiveInformationPolicy\": {}," ++ + " \"status\": \"READY\"," ++ + " \"topicPolicy\": {" ++ + " \"topics\": [" ++ + " {" ++ + " \"definition\": \"string\"," ++ + " \"examples\": [ \"string\" ]," ++ + " \"name\": \"string\"," ++ + " \"type\": \"string\"" ++ + " }" ++ + " ]" ++ + " }," ++ + " \"updatedAt\": \"2024-06-12T18:31:48Z\"," ++ + " \"version\": \"DRAFT\"," ++ + " \"wordPolicy\": {}" ++ + "}"; ++ ++ server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.JSON_UTF_8, body)); ++ ++ Object response = ++ client.getGuardrail(new GetGuardrailRequest().withGuardrailIdentifier("guardrailId")); ++ ++ assertRequestWithMockedResponse( ++ response, ++ client, ++ "Bedrock", ++ "GetGuardrail", ++ "GET", ++ ImmutableMap.of("aws.bedrock.guardrail.id", "guardrailId")); ++ } ++} +diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractBedrockRuntimeClientTest.java b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractBedrockRuntimeClientTest.java +new file mode 100644 +index 0000000000..e9d2c32262 +--- /dev/null ++++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractBedrockRuntimeClientTest.java +@@ -0,0 +1,125 @@ ++/* ++ * Copyright The OpenTelemetry Authors ++ * SPDX-License-Identifier: Apache-2.0 ++ */ ++ ++package io.opentelemetry.instrumentation.awssdk.v1_11; ++ ++import com.amazonaws.services.bedrockruntime.AmazonBedrockRuntime; ++import com.amazonaws.services.bedrockruntime.AmazonBedrockRuntimeClientBuilder; ++import com.amazonaws.services.bedrockruntime.model.InvokeModelRequest; ++import com.google.common.collect.ImmutableMap; ++import io.opentelemetry.testing.internal.armeria.common.HttpResponse; ++import io.opentelemetry.testing.internal.armeria.common.HttpStatus; ++import io.opentelemetry.testing.internal.armeria.common.MediaType; ++import java.nio.charset.StandardCharsets; ++import java.util.Map; ++import java.util.stream.Stream; ++import org.junit.jupiter.params.ParameterizedTest; ++import org.junit.jupiter.params.provider.MethodSource; ++ ++public abstract class AbstractBedrockRuntimeClientTest extends AbstractBaseAwsClientTest { ++ ++ public abstract AmazonBedrockRuntimeClientBuilder configureClient( ++ AmazonBedrockRuntimeClientBuilder client); ++ ++ @ParameterizedTest ++ @MethodSource("testData") ++ public void sendRequestWithMockedResponse( ++ String modelId, ++ String requestBody, ++ String expectedResponse, ++ Map expectedAttributes) ++ throws Exception { ++ AmazonBedrockRuntimeClientBuilder clientBuilder = AmazonBedrockRuntimeClientBuilder.standard(); ++ AmazonBedrockRuntime client = ++ configureClient(clientBuilder) ++ .withEndpointConfiguration(endpoint) ++ .withCredentials(credentialsProvider) ++ .build(); ++ ++ server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.JSON_UTF_8, expectedResponse)); ++ ++ client.invokeModel( ++ new InvokeModelRequest() ++ .withModelId(modelId) ++ .withBody(StandardCharsets.UTF_8.encode(requestBody))); ++ ++ assertRequestWithMockedResponse( ++ expectedResponse, client, "BedrockRuntime", "InvokeModel", "POST", expectedAttributes); ++ } ++ ++ private static Stream testData() { ++ return Stream.of( ++ new Object[] { ++ "ai21.jamba-1-5-mini-v1:0", ++ "{\"messages\":[{\"role\":\"user\",\"message\":\"Which LLM are you?\"}],\"max_tokens\":1000,\"top_p\":0.8,\"temperature\":0.7}", ++ "{\"choices\":[{\"finish_reason\":\"stop\"}],\"usage\":{\"prompt_tokens\":5,\"completion_tokens\":42}}", ++ ImmutableMap.of( ++ "gen_ai.request.model", "ai21.jamba-1-5-mini-v1:0", ++ "gen_ai.system", "aws_bedrock", ++ "gen_ai.request.max_tokens", "1000", ++ "gen_ai.request.temperature", "0.7", ++ "gen_ai.request.top_p", "0.8", ++ "gen_ai.response.finish_reasons", "[stop]", ++ "gen_ai.usage.input_tokens", "5", ++ "gen_ai.usage.output_tokens", "42") ++ }, ++ new Object[] { ++ "amazon.titan-text-premier-v1:0", ++ "{\"inputText\":\"Hello, world!\",\"textGenerationConfig\":{\"temperature\":0.7,\"topP\":0.9,\"maxTokenCount\":100,\"stopSequences\":[\"END\"]}}", ++ "{\"inputTextTokenCount\":5,\"results\":[{\"tokenCount\":42,\"outputText\":\"Hi! I'm Titan, an AI assistant.\",\"completionReason\":\"stop\"}]}", ++ ImmutableMap.of( ++ "gen_ai.request.model", "amazon.titan-text-premier-v1:0", ++ "gen_ai.system", "aws_bedrock", ++ "gen_ai.request.max_tokens", "100", ++ "gen_ai.request.temperature", "0.7", ++ "gen_ai.request.top_p", "0.9", ++ "gen_ai.response.finish_reasons", "[stop]", ++ "gen_ai.usage.input_tokens", "5", ++ "gen_ai.usage.output_tokens", "42") ++ }, ++ new Object[] { ++ "anthropic.claude-3-5-sonnet-20241022-v2:0", ++ "{\"anthropic_version\":\"bedrock-2023-05-31\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello, world\"}],\"max_tokens\":100,\"temperature\":0.7,\"top_p\":0.9}", ++ "{\"stop_reason\":\"end_turn\",\"usage\":{\"input_tokens\":2095,\"output_tokens\":503}}", ++ ImmutableMap.of( ++ "gen_ai.request.model", "anthropic.claude-3-5-sonnet-20241022-v2:0", ++ "gen_ai.system", "aws_bedrock", ++ "gen_ai.request.max_tokens", "100", ++ "gen_ai.request.temperature", "0.7", ++ "gen_ai.request.top_p", "0.9", ++ "gen_ai.response.finish_reasons", "[end_turn]", ++ "gen_ai.usage.input_tokens", "2095", ++ "gen_ai.usage.output_tokens", "503") ++ }, ++ new Object[] { ++ "meta.llama3-70b-instruct-v1:0", ++ "{\"prompt\":\"<|begin_of_text|><|start_header_id|>user<|end_header_id|>\\\\nDescribe the purpose of a 'hello world' program in one line. <|eot_id|>\\\\n<|start_header_id|>assistant<|end_header_id|>\\\\n\",\"max_gen_len\":128,\"temperature\":0.1,\"top_p\":0.9}", ++ "{\"prompt_token_count\":2095,\"generation_token_count\":503,\"stop_reason\":\"stop\"}", ++ ImmutableMap.of( ++ "gen_ai.request.model", "meta.llama3-70b-instruct-v1:0", ++ "gen_ai.system", "aws_bedrock", ++ "gen_ai.request.max_tokens", "128", ++ "gen_ai.request.temperature", "0.1", ++ "gen_ai.request.top_p", "0.9", ++ "gen_ai.response.finish_reasons", "[stop]", ++ "gen_ai.usage.input_tokens", "2095", ++ "gen_ai.usage.output_tokens", "503") ++ }, ++ new Object[] { ++ "cohere.command-r-v1:0", ++ "{\"message\":\"Convince me to write a LISP interpreter in one line.\",\"temperature\":0.8,\"max_tokens\":4096,\"p\":0.45}", ++ "{\"text\":\"test-output\",\"finish_reason\":\"COMPLETE\"}", ++ ImmutableMap.of( ++ "gen_ai.request.model", "cohere.command-r-v1:0", ++ "gen_ai.system", "aws_bedrock", ++ "gen_ai.request.max_tokens", "4096", ++ "gen_ai.request.temperature", "0.8", ++ "gen_ai.request.top_p", "0.45", ++ "gen_ai.response.finish_reasons", "[COMPLETE]", ++ "gen_ai.usage.input_tokens", "9", ++ "gen_ai.usage.output_tokens", "2") ++ }); ++ } ++} +diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractLambdaClientTest.java b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractLambdaClientTest.java +new file mode 100644 +index 0000000000..f6ab4363bf +--- /dev/null ++++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractLambdaClientTest.java +@@ -0,0 +1,66 @@ ++/* ++ * Copyright The OpenTelemetry Authors ++ * SPDX-License-Identifier: Apache-2.0 ++ */ ++ ++package io.opentelemetry.instrumentation.awssdk.v1_11; ++ ++import com.amazonaws.services.lambda.AWSLambda; ++import com.amazonaws.services.lambda.AWSLambdaClientBuilder; ++import com.amazonaws.services.lambda.model.GetEventSourceMappingRequest; ++import com.amazonaws.services.lambda.model.GetFunctionRequest; ++import com.google.common.collect.ImmutableMap; ++import io.opentelemetry.testing.internal.armeria.common.HttpResponse; ++import io.opentelemetry.testing.internal.armeria.common.HttpStatus; ++import io.opentelemetry.testing.internal.armeria.common.MediaType; ++import java.util.Map; ++import java.util.function.Function; ++import java.util.stream.Stream; ++import org.junit.jupiter.params.ParameterizedTest; ++import org.junit.jupiter.params.provider.Arguments; ++import org.junit.jupiter.params.provider.MethodSource; ++ ++public abstract class AbstractLambdaClientTest extends AbstractBaseAwsClientTest { ++ ++ public abstract AWSLambdaClientBuilder configureClient(AWSLambdaClientBuilder client); ++ ++ @Override ++ protected boolean hasRequestId() { ++ return false; ++ } ++ ++ @ParameterizedTest ++ @MethodSource("provideArguments") ++ public void testSendRequestWithMockedResponse( ++ String operation, Map additionalAttributes, Function call) ++ throws Exception { ++ ++ AWSLambdaClientBuilder clientBuilder = AWSLambdaClientBuilder.standard(); ++ ++ AWSLambda client = ++ configureClient(clientBuilder) ++ .withEndpointConfiguration(endpoint) ++ .withCredentials(credentialsProvider) ++ .build(); ++ ++ server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, "")); ++ ++ Object response = call.apply(client); ++ assertRequestWithMockedResponse( ++ response, client, "AWSLambda", operation, "GET", additionalAttributes); ++ } ++ ++ private static Stream provideArguments() { ++ return Stream.of( ++ Arguments.of( ++ "GetEventSourceMapping", ++ ImmutableMap.of("aws.lambda.resource_mapping.id", "uuid"), ++ (Function) ++ c -> c.getEventSourceMapping(new GetEventSourceMappingRequest().withUUID("uuid"))), ++ Arguments.of( ++ "GetFunction", ++ ImmutableMap.of("aws.lambda.function.name", "functionName"), ++ (Function) ++ c -> c.getFunction(new GetFunctionRequest().withFunctionName("functionName")))); ++ } ++} +diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSecretsManagerClientTest.java b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSecretsManagerClientTest.java +new file mode 100644 +index 0000000000..f3fa5ad08c +--- /dev/null ++++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSecretsManagerClientTest.java +@@ -0,0 +1,58 @@ ++/* ++ * Copyright The OpenTelemetry Authors ++ * SPDX-License-Identifier: Apache-2.0 ++ */ ++ ++package io.opentelemetry.instrumentation.awssdk.v1_11; ++ ++import com.amazonaws.services.secretsmanager.AWSSecretsManager; ++import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder; ++import com.amazonaws.services.secretsmanager.model.CreateSecretRequest; ++import com.google.common.collect.ImmutableMap; ++import io.opentelemetry.testing.internal.armeria.common.HttpResponse; ++import io.opentelemetry.testing.internal.armeria.common.HttpStatus; ++import io.opentelemetry.testing.internal.armeria.common.MediaType; ++import org.junit.jupiter.api.Test; ++ ++public abstract class AbstractSecretsManagerClientTest extends AbstractBaseAwsClientTest { ++ ++ public abstract AWSSecretsManagerClientBuilder configureClient( ++ AWSSecretsManagerClientBuilder client); ++ ++ @Override ++ protected boolean hasRequestId() { ++ return true; ++ } ++ ++ @Test ++ public void sendRequestWithMockedResponse() throws Exception { ++ AWSSecretsManagerClientBuilder clientBuilder = AWSSecretsManagerClientBuilder.standard(); ++ AWSSecretsManager client = ++ configureClient(clientBuilder) ++ .withEndpointConfiguration(endpoint) ++ .withCredentials(credentialsProvider) ++ .build(); ++ ++ String body = ++ "{" ++ + "\"ARN\": \"arn:aws:secretsmanager:us-west-2:123456789012:secret:MyTestDatabaseSecret-a1b2c3\"," ++ + "\"Name\": \"MyTestDatabaseSecret\"," ++ + "\"VersionId\": \"EXAMPLE1-90ab-cdef-fedc-ba987SECRET1\"" ++ + "}"; ++ server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, body)); ++ ++ Object response = ++ client.createSecret( ++ new CreateSecretRequest().withName("secretName").withSecretString("secretValue")); ++ ++ assertRequestWithMockedResponse( ++ response, ++ client, ++ "AWSSecretsManager", ++ "CreateSecret", ++ "POST", ++ ImmutableMap.of( ++ "aws.secretsmanager.secret.arn", ++ "arn:aws:secretsmanager:us-west-2:123456789012:secret:MyTestDatabaseSecret-a1b2c3")); ++ } ++} +diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSnsClientTest.java b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSnsClientTest.java +index 4a728f645c..4499e550e0 100644 +--- a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSnsClientTest.java ++++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSnsClientTest.java +@@ -15,11 +15,7 @@ import io.opentelemetry.testing.internal.armeria.common.HttpResponse; + import io.opentelemetry.testing.internal.armeria.common.HttpStatus; + import io.opentelemetry.testing.internal.armeria.common.MediaType; + import java.util.Map; +-import java.util.function.Function; +-import java.util.stream.Stream; +-import org.junit.jupiter.params.ParameterizedTest; +-import org.junit.jupiter.params.provider.Arguments; +-import org.junit.jupiter.params.provider.MethodSource; ++import org.junit.jupiter.api.Test; - import java.time.Duration -+import java.nio.charset.StandardCharsets + public abstract class AbstractSnsClientTest extends AbstractBaseAwsClientTest { - import static io.opentelemetry.api.trace.SpanKind.CLIENT - import static io.opentelemetry.api.trace.SpanKind.PRODUCER -@@ -156,6 +175,85 @@ abstract class AbstractAws1ClientTest extends InstrumentationSpecification { - - - """ -+ "Bedrock" | "GetGuardrail" | "GET" | "/" | -+ AmazonBedrockClientBuilder.standard() | { c -> c.getGuardrail(new GetGuardrailRequest().withGuardrailIdentifier("guardrailId")) } | ["aws.bedrock.guardrail.id":"guardrailId", "aws.bedrock.guardrail.arn": "guardrailArn"] | """ -+ { -+ "blockedInputMessaging": "string", -+ "blockedOutputsMessaging": "string", -+ "contentPolicy": {}, -+ "createdAt": "2024-06-12T18:31:45Z", -+ "description": "string", -+ "guardrailArn": "guardrailArn", -+ "guardrailId": "guardrailId", -+ "kmsKeyArn": "string", -+ "name": "string", -+ "sensitiveInformationPolicy": {}, -+ "status": "READY", -+ "topicPolicy": { -+ "topics": [ -+ { -+ "definition": "string", -+ "examples": [ "string" ], -+ "name": "string", -+ "type": "string" -+ } -+ ] -+ }, -+ "updatedAt": "2024-06-12T18:31:48Z", -+ "version": "DRAFT", -+ "wordPolicy": {} -+ } -+ """ -+ "AWSBedrockAgent" | "GetAgent" | "GET" | "/" | AWSBedrockAgentClientBuilder.standard() | { c -> c.getAgent(new GetAgentRequest().withAgentId("agentId")) } | ["aws.bedrock.agent.id": "agentId"] | "" -+ "AWSBedrockAgent" | "GetKnowledgeBase" | "GET" | "/" | AWSBedrockAgentClientBuilder.standard() | { c -> c.getKnowledgeBase(new GetKnowledgeBaseRequest().withKnowledgeBaseId("knowledgeBaseId")) } | ["aws.bedrock.knowledge_base.id": "knowledgeBaseId"] | "" -+ "AWSBedrockAgent" | "GetDataSource" | "GET" | "/" | AWSBedrockAgentClientBuilder.standard() | { c -> c.getDataSource(new GetDataSourceRequest().withDataSourceId("datasourceId").withKnowledgeBaseId("knowledgeBaseId")) } | ["aws.bedrock.data_source.id": "datasourceId"] | "" -+ "BedrockRuntime" | "InvokeModel" | "POST" | "/" | AmazonBedrockRuntimeClientBuilder.standard() | -+ { c -> c.invokeModel(new InvokeModelRequest().withModelId("anthropic.claude-v2").withBody(StandardCharsets.UTF_8.encode("{\"prompt\":\"Hello, world!\",\"temperature\":0.7,\"top_p\":0.9,\"max_tokens_to_sample\":100}\n"))) } | ["gen_ai.request.model": "anthropic.claude-v2", "gen_ai.system": "aws_bedrock"] | """ -+ { -+ "completion": " Here is a simple explanation of black ", -+ "stop_reason": "length", -+ "stop": "holes" -+ } -+ """ -+ "AWSStepFunctions" | "DescribeStateMachine" | "POST" | "/" | AWSStepFunctionsClientBuilder.standard() -+ | { c -> c.describeStateMachine(new DescribeStateMachineRequest().withStateMachineArn("stateMachineArn")) } -+ | ["aws.stepfunctions.state_machine.arn": "stateMachineArn"] -+ | "" -+ "AWSStepFunctions" | "DescribeActivity" | "POST" | "/" | AWSStepFunctionsClientBuilder.standard() -+ | { c -> c.describeActivity(new DescribeActivityRequest().withActivityArn("activityArn")) } -+ | ["aws.stepfunctions.activity.arn": "activityArn"] -+ | "" -+ "SNS" | "Publish" | "POST" | "/" | AmazonSNSClientBuilder.standard() -+ | { c -> c.publish(new PublishRequest().withMessage("message").withTopicArn("topicArn")) } -+ | ["aws.sns.topic.arn": "topicArn"] -+ | """ -+ -+ -+ 567910cd-659e-55d4-8ccb-5aaf14679dc0 -+ -+ -+ d74b8436-ae13-5ab4-a9ff-ce54dfea72a0 -+ -+ -+ """ -+ "AWSSecretsManager" | "CreateSecret" | "POST" | "/" | AWSSecretsManagerClientBuilder.standard() -+ | { c -> c.createSecret(new CreateSecretRequest().withName("secretName").withSecretString("secretValue")) } -+ | ["aws.secretsmanager.secret.arn": "arn:aws:secretsmanager:us-west-2:123456789012:secret:MyTestDatabaseSecret-a1b2c3"] -+ | """ -+ { -+ "ARN": "arn:aws:secretsmanager:us-west-2:123456789012:secret:MyTestDatabaseSecret-a1b2c3", -+ "Name":"MyTestDatabaseSecret", -+ "VersionId": "EXAMPLE1-90ab-cdef-fedc-ba987SECRET1" -+ } -+ """ -+ "AWSLambda" | "GetEventSourceMapping" | "GET" | "/" | AWSLambdaClientBuilder.standard() -+ | { c -> c.getEventSourceMapping(new GetEventSourceMappingRequest().withUUID("uuid")) } -+ | ["aws.lambda.resource_mapping.id": "uuid"] -+ | "" -+ "AWSLambda" | "GetFunction" | "GET" | "/" | AWSLambdaClientBuilder.standard() -+ | { c-> c.getFunction(new GetFunctionRequest().withFunctionName("functionName")) } -+ | ["aws.lambda.function.name": "functionName"] -+ | "" +@@ -30,9 +26,8 @@ public abstract class AbstractSnsClientTest extends AbstractBaseAwsClientTest { + return true; + } + +- @ParameterizedTest +- @MethodSource("provideArguments") +- public void testSendRequestWithMockedResponse(Function call) throws Exception { ++ @Test ++ public void testSendRequestWithwithTopicArnMockedResponse() throws Exception { + AmazonSNSClientBuilder clientBuilder = AmazonSNSClientBuilder.standard(); + AmazonSNS client = + configureClient(clientBuilder) +@@ -53,24 +48,43 @@ public abstract class AbstractSnsClientTest extends AbstractBaseAwsClientTest { + server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, body)); + + Map additionalAttributes = +- ImmutableMap.of(MESSAGING_DESTINATION_NAME.toString(), "somearn"); ++ ImmutableMap.of( ++ MESSAGING_DESTINATION_NAME.toString(), "somearn", "aws.sns.topic.arn", "somearn"); ++ ++ Object response = ++ client.publish(new PublishRequest().withMessage("somemessage").withTopicArn("somearn")); + +- Object response = call.apply(client); + assertRequestWithMockedResponse( + response, client, "SNS", "Publish", "POST", additionalAttributes); } - def "send #operation request to closed port"() { +- private static Stream provideArguments() { +- return Stream.of( +- Arguments.of( +- (Function) +- c -> +- c.publish( +- new PublishRequest().withMessage("somemessage").withTopicArn("somearn"))), +- Arguments.of( +- (Function) +- c -> +- c.publish( +- new PublishRequest().withMessage("somemessage").withTargetArn("somearn")))); ++ @Test ++ public void testSendRequestWithwithTargetArnMockedResponse() throws Exception { ++ AmazonSNSClientBuilder clientBuilder = AmazonSNSClientBuilder.standard(); ++ AmazonSNS client = ++ configureClient(clientBuilder) ++ .withEndpointConfiguration(endpoint) ++ .withCredentials(credentialsProvider) ++ .build(); ++ ++ String body = ++ "" ++ + " " ++ + " 567910cd-659e-55d4-8ccb-5aaf14679dc0" ++ + " " ++ + " " ++ + " d74b8436-ae13-5ab4-a9ff-ce54dfea72a0" ++ + " " ++ + ""; ++ ++ server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, body)); ++ ++ Map additionalAttributes = ++ ImmutableMap.of(MESSAGING_DESTINATION_NAME.toString(), "somearn"); ++ ++ Object response = ++ client.publish(new PublishRequest().withMessage("somemessage").withTargetArn("somearn")); ++ assertRequestWithMockedResponse( ++ response, client, "SNS", "Publish", "POST", additionalAttributes); + } + } +diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractStepFunctionsClientTest.java b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractStepFunctionsClientTest.java +new file mode 100644 +index 0000000000..24a1f148ee +--- /dev/null ++++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractStepFunctionsClientTest.java +@@ -0,0 +1,73 @@ ++/* ++ * Copyright The OpenTelemetry Authors ++ * SPDX-License-Identifier: Apache-2.0 ++ */ ++ ++package io.opentelemetry.instrumentation.awssdk.v1_11; ++ ++import com.amazonaws.services.stepfunctions.AWSStepFunctions; ++import com.amazonaws.services.stepfunctions.AWSStepFunctionsClientBuilder; ++import com.amazonaws.services.stepfunctions.model.DescribeActivityRequest; ++import com.amazonaws.services.stepfunctions.model.DescribeStateMachineRequest; ++import com.google.common.collect.ImmutableMap; ++import io.opentelemetry.testing.internal.armeria.common.HttpResponse; ++import io.opentelemetry.testing.internal.armeria.common.HttpStatus; ++import io.opentelemetry.testing.internal.armeria.common.MediaType; ++import java.util.Map; ++import java.util.function.Function; ++import java.util.stream.Stream; ++import org.junit.jupiter.params.ParameterizedTest; ++import org.junit.jupiter.params.provider.Arguments; ++import org.junit.jupiter.params.provider.MethodSource; ++ ++public abstract class AbstractStepFunctionsClientTest extends AbstractBaseAwsClientTest { ++ ++ public abstract AWSStepFunctionsClientBuilder configureClient( ++ AWSStepFunctionsClientBuilder client); ++ ++ @Override ++ protected boolean hasRequestId() { ++ return false; ++ } ++ ++ @ParameterizedTest ++ @MethodSource("provideArguments") ++ public void testSendRequestWithMockedResponse( ++ String operation, ++ Map additionalAttributes, ++ Function call) ++ throws Exception { ++ ++ AWSStepFunctionsClientBuilder clientBuilder = AWSStepFunctionsClientBuilder.standard(); ++ ++ AWSStepFunctions client = ++ configureClient(clientBuilder) ++ .withEndpointConfiguration(endpoint) ++ .withCredentials(credentialsProvider) ++ .build(); ++ ++ server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, "")); ++ ++ Object response = call.apply(client); ++ assertRequestWithMockedResponse( ++ response, client, "AWSStepFunctions", operation, "POST", additionalAttributes); ++ } ++ ++ private static Stream provideArguments() { ++ return Stream.of( ++ Arguments.of( ++ "DescribeStateMachine", ++ ImmutableMap.of("aws.stepfunctions.state_machine.arn", "stateMachineArn"), ++ (Function) ++ c -> ++ c.describeStateMachine( ++ new DescribeStateMachineRequest().withStateMachineArn("stateMachineArn"))), ++ Arguments.of( ++ "DescribeActivity", ++ ImmutableMap.of("aws.stepfunctions.activity.arn", "activityArn"), ++ (Function) ++ c -> ++ c.describeActivity( ++ new DescribeActivityRequest().withActivityArn("activityArn")))); ++ } ++} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/build.gradle.kts b/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/build.gradle.kts -index 3b6efbd696..9f4487d727 100644 +index 7d3fa5d03c..6079232826 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/build.gradle.kts +++ b/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/build.gradle.kts -@@ -84,6 +84,9 @@ dependencies { +@@ -104,6 +104,9 @@ dependencies { testLibrary("software.amazon.awssdk:sqs:2.2.0") testLibrary("software.amazon.awssdk:sns:2.2.0") testLibrary("software.amazon.awssdk:ses:2.2.0") @@ -891,10 +1702,10 @@ index 3b6efbd696..9f4487d727 100644 val latestDepTest = findProperty("testLatestDeps") as Boolean diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure/build.gradle.kts b/instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure/build.gradle.kts -index 6e0ea36a64..68b9c72b7d 100644 +index d493f83a86..0bb91a17c3 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure/build.gradle.kts +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure/build.gradle.kts -@@ -21,6 +21,9 @@ dependencies { +@@ -22,6 +22,9 @@ dependencies { testLibrary("software.amazon.awssdk:s3:2.2.0") testLibrary("software.amazon.awssdk:sqs:2.2.0") testLibrary("software.amazon.awssdk:sns:2.2.0") @@ -905,10 +1716,10 @@ index 6e0ea36a64..68b9c72b7d 100644 tasks { diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/build.gradle.kts b/instrumentation/aws-sdk/aws-sdk-2.2/library/build.gradle.kts -index 862df156ae..2ed33d6f03 100644 +index 3b7381a8ba..6f77951710 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/build.gradle.kts +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/build.gradle.kts -@@ -19,6 +19,9 @@ dependencies { +@@ -22,6 +22,9 @@ dependencies { testLibrary("software.amazon.awssdk:rds:2.2.0") testLibrary("software.amazon.awssdk:s3:2.2.0") testLibrary("software.amazon.awssdk:ses:2.2.0") @@ -918,18 +1729,18 @@ index 862df156ae..2ed33d6f03 100644 } testing { -diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsExperimentalAttributes.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsExperimentalAttributes.java +diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsExperimentalAttributes.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsExperimentalAttributes.java new file mode 100644 -index 0000000000..e1cb180d75 +index 0000000000..4aed4a58c0 --- /dev/null -+++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsExperimentalAttributes.java -@@ -0,0 +1,47 @@ ++++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsExperimentalAttributes.java +@@ -0,0 +1,73 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + -+package io.opentelemetry.instrumentation.awssdk.v2_2; ++package io.opentelemetry.instrumentation.awssdk.v2_2.internal; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; + @@ -952,6 +1763,23 @@ index 0000000000..e1cb180d75 + static final AttributeKey GEN_AI_MODEL = stringKey("gen_ai.request.model"); + static final AttributeKey GEN_AI_SYSTEM = stringKey("gen_ai.system"); + ++ static final AttributeKey GEN_AI_REQUEST_MAX_TOKENS = ++ stringKey("gen_ai.request.max_tokens"); ++ ++ static final AttributeKey GEN_AI_REQUEST_TEMPERATURE = ++ stringKey("gen_ai.request.temperature"); ++ ++ static final AttributeKey GEN_AI_REQUEST_TOP_P = stringKey("gen_ai.request.top_p"); ++ ++ static final AttributeKey GEN_AI_RESPONSE_FINISH_REASONS = ++ stringKey("gen_ai.response.finish_reasons"); ++ ++ static final AttributeKey GEN_AI_USAGE_INPUT_TOKENS = ++ stringKey("gen_ai.usage.input_tokens"); ++ ++ static final AttributeKey GEN_AI_USAGE_OUTPUT_TOKENS = ++ stringKey("gen_ai.usage.output_tokens"); ++ + static final AttributeKey AWS_STATE_MACHINE_ARN = + stringKey("aws.stepfunctions.state_machine.arn"); + @@ -969,35 +1797,44 @@ index 0000000000..e1cb180d75 + static final AttributeKey AWS_LAMBDA_RESOURCE_ID = + stringKey("aws.lambda.resource_mapping.id"); + ++ static boolean isGenAiAttribute(String attributeKey) { ++ return attributeKey.equals(GEN_AI_REQUEST_MAX_TOKENS.getKey()) ++ || attributeKey.equals(GEN_AI_REQUEST_TEMPERATURE.getKey()) ++ || attributeKey.equals(GEN_AI_REQUEST_TOP_P.getKey()) ++ || attributeKey.equals(GEN_AI_RESPONSE_FINISH_REASONS.getKey()) ++ || attributeKey.equals(GEN_AI_USAGE_INPUT_TOKENS.getKey()) ++ || attributeKey.equals(GEN_AI_USAGE_OUTPUT_TOKENS.getKey()); ++ } ++ + private AwsExperimentalAttributes() {} +} -diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkRequest.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkRequest.java -index 54253d0f7b..2374bd4a52 100644 ---- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkRequest.java -+++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkRequest.java -@@ -5,10 +5,20 @@ +diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequest.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequest.java +index 02d92ca070..aa98cd62c7 100644 +--- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequest.java ++++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequest.java +@@ -5,11 +5,20 @@ - package io.opentelemetry.instrumentation.awssdk.v2_2; + package io.opentelemetry.instrumentation.awssdk.v2_2.internal; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCK; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCKAGENTOPERATION; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCKAGENTRUNTIMEOPERATION; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCKDATASOURCEOPERATION; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCKKNOWLEDGEBASEOPERATION; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCKRUNTIME; - import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.DYNAMODB; - import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.KINESIS; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.LAMBDA; - import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.S3; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.SECRETSMANAGER; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.SNS; - import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.SQS; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.STEPFUNCTION; - import static io.opentelemetry.instrumentation.awssdk.v2_2.FieldMapping.request; - import static io.opentelemetry.instrumentation.awssdk.v2_2.FieldMapping.response; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.BEDROCK; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.BEDROCKAGENTOPERATION; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.BEDROCKAGENTRUNTIMEOPERATION; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.BEDROCKDATASOURCEOPERATION; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.BEDROCKKNOWLEDGEBASEOPERATION; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.BEDROCKRUNTIME; + import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.DYNAMODB; + import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.KINESIS; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.LAMBDA; + import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.S3; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.SECRETSMANAGER; + import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.SNS; + import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.SQS; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.STEPFUNCTION; + import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.request; + import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.response; -@@ -32,6 +42,54 @@ enum AwsSdkRequest { - S3Request(S3, "S3Request"), +@@ -34,6 +43,52 @@ enum AwsSdkRequest { + SnsRequest(SNS, "SnsRequest"), SqsRequest(SQS, "SqsRequest"), KinesisRequest(KINESIS, "KinesisRequest"), + @@ -1043,52 +1880,57 @@ index 54253d0f7b..2374bd4a52 100644 + + SfnRequest(STEPFUNCTION, "SfnRequest"), + -+ SnsRequest(SNS, "SnsRequest"), -+ + SecretsManagerRequest(SECRETSMANAGER, "SecretsManagerRequest"), + + LambdaRequest(LAMBDA, "LambdaRequest"), // specific requests BatchGetItem( DYNAMODB, -diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkRequestType.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkRequestType.java -index 9062f2aa17..1c34035588 100644 ---- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkRequestType.java -+++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkRequestType.java -@@ -5,17 +5,69 @@ +diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequestType.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequestType.java +index 274ec27194..83d9353c3b 100644 +--- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequestType.java ++++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequestType.java +@@ -5,7 +5,32 @@ - package io.opentelemetry.instrumentation.awssdk.v2_2; + package io.opentelemetry.instrumentation.awssdk.v2_2.internal; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_AGENT_ID; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_BUCKET_NAME; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_DATA_SOURCE_ID; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_GUARDRAIL_ARN; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_GUARDRAIL_ID; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_KNOWLEDGE_BASE_ID; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_LAMBDA_ARN; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_LAMBDA_NAME; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_LAMBDA_RESOURCE_ID; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_QUEUE_NAME; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_QUEUE_URL; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_SECRET_ARN; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_SNS_TOPIC_ARN; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_STATE_MACHINE_ARN; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_STEP_FUNCTIONS_ACTIVITY_ARN; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_STREAM_NAME; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_TABLE_NAME; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_MODEL; - import static io.opentelemetry.instrumentation.awssdk.v2_2.FieldMapping.request; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.FieldMapping.response; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_AGENT_ID; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_BUCKET_NAME; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_DATA_SOURCE_ID; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_GUARDRAIL_ARN; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_GUARDRAIL_ID; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_KNOWLEDGE_BASE_ID; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_LAMBDA_ARN; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_LAMBDA_NAME; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_LAMBDA_RESOURCE_ID; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_QUEUE_NAME; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_QUEUE_URL; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_SECRET_ARN; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_SNS_TOPIC_ARN; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_STATE_MACHINE_ARN; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_STEP_FUNCTIONS_ACTIVITY_ARN; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_STREAM_NAME; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_TABLE_NAME; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.GEN_AI_MODEL; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.GEN_AI_REQUEST_MAX_TOKENS; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.GEN_AI_REQUEST_TEMPERATURE; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.GEN_AI_REQUEST_TOP_P; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.GEN_AI_RESPONSE_FINISH_REASONS; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.GEN_AI_USAGE_INPUT_TOKENS; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.GEN_AI_USAGE_OUTPUT_TOKENS; + import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.request; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.response; + import io.opentelemetry.api.common.AttributeKey; import java.util.Collections; - import java.util.List; +@@ -13,16 +38,60 @@ import java.util.List; import java.util.Map; enum AwsSdkRequestType { - S3(request("aws.bucket.name", "Bucket")), - SQS(request("aws.queue.url", "QueueUrl"), request("aws.queue.name", "QueueName")), - KINESIS(request("aws.stream.name", "StreamName")), -- DYNAMODB(request("aws.table.name", "TableName")); +- DYNAMODB(request("aws.table.name", "TableName")), + S3(request(AWS_BUCKET_NAME.getKey(), "Bucket")), + + SQS(request(AWS_QUEUE_URL.getKey(), "QueueUrl"), request(AWS_QUEUE_NAME.getKey(), "QueueName")), @@ -1096,6 +1938,15 @@ index 9062f2aa17..1c34035588 100644 + KINESIS(request(AWS_STREAM_NAME.getKey(), "StreamName")), + + DYNAMODB(request(AWS_TABLE_NAME.getKey(), "TableName")), ++ + SNS( + /* + * Only one of TopicArn and TargetArn are permitted on an SNS request. + */ + request(AttributeKeys.MESSAGING_DESTINATION_NAME.getKey(), "TargetArn"), +- request(AttributeKeys.MESSAGING_DESTINATION_NAME.getKey(), "TopicArn")); ++ request(AttributeKeys.MESSAGING_DESTINATION_NAME.getKey(), "TopicArn"), ++ request(AWS_SNS_TOPIC_ARN.getKey(), "TopicArn")), + + BEDROCK( + request(AWS_GUARDRAIL_ID.getKey(), "guardrailIdentifier"), @@ -1113,12 +1964,21 @@ index 9062f2aa17..1c34035588 100644 + BEDROCKKNOWLEDGEBASEOPERATION( + request(AWS_KNOWLEDGE_BASE_ID.getKey(), "knowledgeBaseId"), + response(AWS_KNOWLEDGE_BASE_ID.getKey(), "knowledgeBaseId")), -+ BEDROCKRUNTIME(request(GEN_AI_MODEL.getKey(), "modelId")), ++ BEDROCKRUNTIME( ++ request(GEN_AI_MODEL.getKey(), "modelId"), ++ request(GEN_AI_REQUEST_MAX_TOKENS.getKey(), "body"), ++ request(GEN_AI_REQUEST_TEMPERATURE.getKey(), "body"), ++ request(GEN_AI_REQUEST_TOP_P.getKey(), "body"), ++ request(GEN_AI_USAGE_INPUT_TOKENS.getKey(), "body"), ++ response(GEN_AI_RESPONSE_FINISH_REASONS.getKey(), "body"), ++ response(GEN_AI_USAGE_INPUT_TOKENS.getKey(), "body"), ++ response(GEN_AI_USAGE_OUTPUT_TOKENS.getKey(), "body")), ++ + STEPFUNCTION( + request(AWS_STATE_MACHINE_ARN.getKey(), "stateMachineArn"), + request(AWS_STEP_FUNCTIONS_ACTIVITY_ARN.getKey(), "activityArn")), + -+ SNS(request(AWS_SNS_TOPIC_ARN.getKey(), "TopicArn")), ++ // SNS(request(AWS_SNS_TOPIC_ARN.getKey(), "TopicArn")), + + SECRETSMANAGER(response(AWS_SECRET_ARN.getKey(), "ARN")), + @@ -1129,29 +1989,286 @@ index 9062f2aa17..1c34035588 100644 // Wrapping in unmodifiableMap @SuppressWarnings("ImmutableEnumChecker") -diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java -index f717b1efc4..352b02093e 100644 ---- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java -+++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java +diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/FieldMapper.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/FieldMapper.java +index 9e7aeacbce..9a38a753ca 100644 +--- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/FieldMapper.java ++++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/FieldMapper.java +@@ -65,8 +65,13 @@ class FieldMapper { + for (int i = 1; i < path.size() && target != null; i++) { + target = next(target, path.get(i)); + } ++ String value; + if (target != null) { +- String value = serializer.serialize(target); ++ if (AwsExperimentalAttributes.isGenAiAttribute(fieldMapping.getAttribute())) { ++ value = serializer.serialize(fieldMapping.getAttribute(), target); ++ } else { ++ value = serializer.serialize(target); ++ } + if (!StringUtils.isEmpty(value)) { + span.setAttribute(fieldMapping.getAttribute(), value); + } +diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/Serializer.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/Serializer.java +index 7ae1590152..18f9dd41ee 100644 +--- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/Serializer.java ++++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/Serializer.java +@@ -5,13 +5,19 @@ + + package io.opentelemetry.instrumentation.awssdk.v2_2.internal; + ++import com.fasterxml.jackson.core.JsonProcessingException; ++import com.fasterxml.jackson.databind.JsonNode; ++import com.fasterxml.jackson.databind.ObjectMapper; + import java.io.IOException; + import java.io.InputStream; + import java.util.Collection; + import java.util.Map; ++import java.util.Objects; + import java.util.Optional; + import java.util.stream.Collectors; ++import java.util.stream.Stream; + import javax.annotation.Nullable; ++import software.amazon.awssdk.core.SdkBytes; + import software.amazon.awssdk.core.SdkPojo; + import software.amazon.awssdk.http.ContentStreamProvider; + import software.amazon.awssdk.http.SdkHttpFullRequest; +@@ -21,6 +27,8 @@ import software.amazon.awssdk.utils.StringUtils; + + class Serializer { + ++ private static final ObjectMapper objectMapper = new ObjectMapper(); ++ + @Nullable + String serialize(Object target) { + +@@ -41,6 +49,41 @@ class Serializer { + return target.toString(); + } + ++ @Nullable ++ String serialize(String attributeName, Object target) { ++ try { ++ JsonNode jsonBody; ++ if (target instanceof SdkBytes) { ++ String jsonString = ((SdkBytes) target).asUtf8String(); ++ jsonBody = objectMapper.readTree(jsonString); ++ } else { ++ if (target != null) { ++ return target.toString(); ++ } ++ return null; ++ } ++ ++ switch (attributeName) { ++ case "gen_ai.request.max_tokens": ++ return getMaxTokens(jsonBody); ++ case "gen_ai.request.temperature": ++ return getTemperature(jsonBody); ++ case "gen_ai.request.top_p": ++ return getTopP(jsonBody); ++ case "gen_ai.response.finish_reasons": ++ return getFinishReasons(jsonBody); ++ case "gen_ai.usage.input_tokens": ++ return getInputTokens(jsonBody); ++ case "gen_ai.usage.output_tokens": ++ return getOutputTokens(jsonBody); ++ default: ++ return null; ++ } ++ } catch (JsonProcessingException e) { ++ return null; ++ } ++ } ++ + @Nullable + private static String serialize(SdkPojo sdkPojo) { + ProtocolMarshaller marshaller = +@@ -65,4 +108,162 @@ class Serializer { + String serialized = collection.stream().map(this::serialize).collect(Collectors.joining(",")); + return (StringUtils.isEmpty(serialized) ? null : "[" + serialized + "]"); + } ++ ++ @Nullable ++ private static String findFirstMatchingPath(JsonNode jsonBody, String... paths) { ++ if (jsonBody == null) { ++ return null; ++ } ++ ++ return Stream.of(paths) ++ .map( ++ path -> { ++ JsonNode node = jsonBody.at(path); ++ if (node != null && !node.isMissingNode()) { ++ return node.asText(); ++ } ++ return null; ++ }) ++ .filter(Objects::nonNull) ++ .findFirst() ++ .orElse(null); ++ } ++ ++ @Nullable ++ private static String approximateTokenCount(JsonNode jsonBody, String... textPaths) { ++ if (jsonBody == null) { ++ return null; ++ } ++ ++ return Stream.of(textPaths) ++ .map( ++ path -> { ++ JsonNode node = jsonBody.at(path); ++ if (node != null && !node.isMissingNode()) { ++ int tokenEstimate = (int) Math.ceil(node.asText().length() / 6.0); ++ return Integer.toString(tokenEstimate); ++ } ++ return null; ++ }) ++ .filter(Objects::nonNull) ++ .findFirst() ++ .orElse(null); ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/textGenerationConfig/maxTokenCount" ++ // Anthropic Claude -> "/max_tokens" ++ // Cohere Command -> "/max_tokens" ++ // Cohere Command R -> "/max_tokens" ++ // AI21 Jamba -> "/max_tokens" ++ // Meta Llama -> "/max_gen_len" ++ // Mistral AI -> "/max_tokens" ++ @Nullable ++ private static String getMaxTokens(JsonNode jsonBody) { ++ return findFirstMatchingPath( ++ jsonBody, "/textGenerationConfig/maxTokenCount", "/max_tokens", "/max_gen_len"); ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/textGenerationConfig/temperature" ++ // Anthropic Claude -> "/temperature" ++ // Cohere Command -> "/temperature" ++ // Cohere Command R -> "/temperature" ++ // AI21 Jamba -> "/temperature" ++ // Meta Llama -> "/temperature" ++ // Mistral AI -> "/temperature" ++ @Nullable ++ private static String getTemperature(JsonNode jsonBody) { ++ return findFirstMatchingPath(jsonBody, "/textGenerationConfig/temperature", "/temperature"); ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/textGenerationConfig/topP" ++ // Anthropic Claude -> "/top_p" ++ // Cohere Command -> "/p" ++ // Cohere Command R -> "/p" ++ // AI21 Jamba -> "/top_p" ++ // Meta Llama -> "/top_p" ++ // Mistral AI -> "/top_p" ++ @Nullable ++ private static String getTopP(JsonNode jsonBody) { ++ return findFirstMatchingPath(jsonBody, "/textGenerationConfig/topP", "/top_p", "/p"); ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/results/0/completionReason" ++ // Anthropic Claude -> "/stop_reason" ++ // Cohere Command -> "/generations/0/finish_reason" ++ // Cohere Command R -> "/finish_reason" ++ // AI21 Jamba -> "/choices/0/finish_reason" ++ // Meta Llama -> "/stop_reason" ++ // Mistral AI -> "/outputs/0/stop_reason" ++ @Nullable ++ private static String getFinishReasons(JsonNode jsonBody) { ++ String finishReason = ++ findFirstMatchingPath( ++ jsonBody, ++ "/results/0/completionReason", ++ "/stop_reason", ++ "/generations/0/finish_reason", ++ "/choices/0/finish_reason", ++ "/outputs/0/stop_reason", ++ "/finish_reason"); ++ ++ return finishReason != null ? "[" + finishReason + "]" : null; ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/inputTextTokenCount" ++ // Anthropic Claude -> "/usage/input_tokens" ++ // Cohere Command -> "/prompt" ++ // Cohere Command R -> "/message" ++ // AI21 Jamba -> "/usage/prompt_tokens" ++ // Meta Llama -> "/prompt_token_count" ++ // Mistral AI -> "/prompt" ++ @Nullable ++ private static String getInputTokens(JsonNode jsonBody) { ++ // Try direct tokens counts first ++ String directCount = ++ findFirstMatchingPath( ++ jsonBody, ++ "/inputTextTokenCount", ++ "/usage/input_tokens", ++ "/usage/prompt_tokens", ++ "/prompt_token_count"); ++ ++ if (directCount != null) { ++ return directCount; ++ } ++ ++ // Fall back to token approximation ++ return approximateTokenCount(jsonBody, "/prompt", "/message"); ++ } ++ ++ // Model -> Path Mapping: ++ // Amazon Titan -> "/results/0/tokenCount" ++ // Anthropic Claude -> "/usage/output_tokens" ++ // Cohere Command -> "/generations/0/text" ++ // Cohere Command R -> "/text" ++ // AI21 Jamba -> "/usage/completion_tokens" ++ // Meta Llama -> "/generation_token_count" ++ // Mistral AI -> "/outputs/0/text" ++ @Nullable ++ private static String getOutputTokens(JsonNode jsonBody) { ++ // Try direct token counts first ++ String directCount = ++ findFirstMatchingPath( ++ jsonBody, ++ "/results/0/tokenCount", ++ "/usage/output_tokens", ++ "/usage/completion_tokens", ++ "/generation_token_count"); ++ ++ if (directCount != null) { ++ return directCount; ++ } ++ ++ // Fall back to token approximation ++ return approximateTokenCount(jsonBody, "/outputs/0/text", "/text"); ++ } + } +diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/TracingExecutionInterceptor.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/TracingExecutionInterceptor.java +index 94243d0b11..747620b108 100644 +--- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/TracingExecutionInterceptor.java ++++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/TracingExecutionInterceptor.java @@ -5,6 +5,8 @@ - package io.opentelemetry.instrumentation.awssdk.v2_2; + package io.opentelemetry.instrumentation.awssdk.v2_2.internal; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_SYSTEM; -+import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCKRUNTIME; - import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.DYNAMODB; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.GEN_AI_SYSTEM; ++import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.BEDROCKRUNTIME; + import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.DYNAMODB; import io.opentelemetry.api.common.AttributeKey; -@@ -42,6 +44,7 @@ import software.amazon.awssdk.http.SdkHttpResponse; - - /** AWS request execution interceptor. */ - final class TracingExecutionInterceptor implements ExecutionInterceptor { +@@ -48,6 +50,7 @@ import software.amazon.awssdk.http.SdkHttpResponse; + * at any time. + */ + public final class TracingExecutionInterceptor implements ExecutionInterceptor { + private static final String GEN_AI_SYSTEM_BEDROCK = "aws_bedrock"; - // the class name is part of the attribute name, so that it will be shaded when used in javaagent - // instrumentation, and won't conflict with usage outside javaagent instrumentation -@@ -317,6 +320,10 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor { - span.setAttribute(SemanticAttributes.DB_OPERATION, operation); + // copied from DbIncubatingAttributes + private static final AttributeKey DB_OPERATION = AttributeKey.stringKey("db.operation"); +@@ -342,6 +345,10 @@ public final class TracingExecutionInterceptor implements ExecutionInterceptor { + } } } + @@ -1162,10 +2279,10 @@ index f717b1efc4..352b02093e 100644 @Override diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/testing/build.gradle.kts b/instrumentation/aws-sdk/aws-sdk-2.2/testing/build.gradle.kts -index 9981aa9a19..1caed55e62 100644 +index 08b000a05c..de0fe82638 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/testing/build.gradle.kts +++ b/instrumentation/aws-sdk/aws-sdk-2.2/testing/build.gradle.kts -@@ -19,6 +19,9 @@ dependencies { +@@ -20,6 +20,9 @@ dependencies { compileOnly("software.amazon.awssdk:sqs:2.2.0") compileOnly("software.amazon.awssdk:sns:2.2.0") compileOnly("software.amazon.awssdk:ses:2.2.0") @@ -1174,12 +2291,17 @@ index 9981aa9a19..1caed55e62 100644 + compileOnly("software.amazon.awssdk:secretsmanager:2.2.0") // needed for SQS - using emq directly as localstack references emq v0.15.7 ie WITHOUT AWS trace header propagation - implementation("org.elasticmq:elasticmq-rest-sqs_2.13:1.5.1") + implementation("org.elasticmq:elasticmq-rest-sqs_2.13") diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.groovy b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.groovy -index 7c152bb91b..b30b8fa2c7 100644 +index 2533a0202d..c6350d0749 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.groovy +++ b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.groovy -@@ -35,6 +35,16 @@ import software.amazon.awssdk.services.sqs.SqsAsyncClient +@@ -37,10 +37,19 @@ import software.amazon.awssdk.services.s3.model.GetObjectRequest + import software.amazon.awssdk.services.sns.SnsAsyncClient + import software.amazon.awssdk.services.sns.SnsClient + import software.amazon.awssdk.services.sns.model.PublishRequest ++import software.amazon.awssdk.services.sns.model.SubscribeRequest + import software.amazon.awssdk.services.sqs.SqsAsyncClient import software.amazon.awssdk.services.sqs.SqsClient import software.amazon.awssdk.services.sqs.model.CreateQueueRequest import software.amazon.awssdk.services.sqs.model.SendMessageRequest @@ -1189,17 +2311,22 @@ index 7c152bb91b..b30b8fa2c7 100644 +import software.amazon.awssdk.services.lambda.LambdaClient +import software.amazon.awssdk.services.lambda.model.GetFunctionRequest +import software.amazon.awssdk.services.lambda.model.GetEventSourceMappingRequest -+import software.amazon.awssdk.services.sns.SnsClient -+import software.amazon.awssdk.services.sns.model.PublishRequest +import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient +import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest import spock.lang.Unroll import java.nio.charset.StandardCharsets -@@ -144,6 +154,29 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest { - "$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS" +@@ -148,8 +157,32 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest { + "$MessagingIncubatingAttributes.MESSAGING_SYSTEM" MessagingIncubatingAttributes.MessagingSystemIncubatingValues.AWS_SQS } else if (service == "Kinesis") { "aws.stream.name" "somestream" +- } else if (service == "Sns") { +- "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "somearn" ++ } else if (service == "Sns" && operation == "Publish") { ++ "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "sometargetarn" ++ } else if (service == "Sns" && operation == "Subscribe") { ++ "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "sometopicarn" ++ "aws.sns.topic.arn" "sometopicarn" + } else if (service == "Bedrock" && operation == "GetGuardrail") { + "aws.bedrock.guardrail.id" "guardrailId" + } else if (service == "BedrockAgent" && operation == "GetAgent") { @@ -1219,17 +2346,173 @@ index 7c152bb91b..b30b8fa2c7 100644 + "aws.lambda.function.name" "functionName" + } else if (service == "Lambda" && operation == "GetEventSourceMapping") { + "aws.lambda.resource_mapping.id" "sourceEventId" -+ } else if (service == "Sns") { -+ "aws.sns.topic.arn" "topicArn" + } else if (service == "SecretsManager") { + "aws.secretsmanager.secret.arn" "someSecretArn" } } } -@@ -218,6 +251,41 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest { +@@ -164,7 +197,7 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest { + "S3" | "CreateBucket" | "PUT" | "UNKNOWN" | s3ClientBuilder() | { c -> c.createBucket(CreateBucketRequest.builder().bucket("somebucket").build()) } | "" + "S3" | "GetObject" | "GET" | "UNKNOWN" | s3ClientBuilder() | { c -> c.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build()) } | "" + "Kinesis" | "DeleteStream" | "POST" | "UNKNOWN" | KinesisClient.builder() | { c -> c.deleteStream(DeleteStreamRequest.builder().streamName("somestream").build()) } | "" +- "Sns" | "Publish" | "POST" | "d74b8436-ae13-5ab4-a9ff-ce54dfea72a0" | SnsClient.builder() | { c -> c.publish(PublishRequest.builder().message("somemessage").topicArn("somearn").build()) } | """ ++ "Sns" | "Publish" | "POST" | "d74b8436-ae13-5ab4-a9ff-ce54dfea72a0" | SnsClient.builder() | { c -> c.publish(PublishRequest.builder().message("somemessage").targetArn("sometargetarn").build()) } | """ + + + 567910cd-659e-55d4-8ccb-5aaf14679dc0 +@@ -174,15 +207,15 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest { + + + """ +- "Sns" | "Publish" | "POST" | "d74b8436-ae13-5ab4-a9ff-ce54dfea72a0" | SnsClient.builder() | { c -> c.publish(PublishRequest.builder().message("somemessage").targetArn("somearn").build()) } | """ +- +- +- 567910cd-659e-55d4-8ccb-5aaf14679dc0 +- ++ "Sns" | "Subscribe" | "POST" | "1234-5678-9101-1121" | SnsClient.builder() | { c -> c.subscribe(SubscribeRequest.builder().topicArn("sometopicarn").protocol("email").endpoint("test@example.com").build())} | """ ++ ++ ++ arn:aws:sns:us-west-2:123456789012:MyTopic:abc123 ++ + +- d74b8436-ae13-5ab4-a9ff-ce54dfea72a0 ++ 1234-5678-9101-1121 + +- ++ + """ + "Sqs" | "CreateQueue" | "POST" | "7a62c49f-347e-4fc4-9331-6e8e7a96aa73" | SqsClient.builder() | { c -> c.createQueue(CreateQueueRequest.builder().queueName("somequeue").build()) } | { + if (!Boolean.getBoolean("testLatestDeps")) { +@@ -244,170 +277,193 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest { 0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99 """ +- } +- +- def "send #operation async request with builder #builder.class.getName() mocked response"() { +- assumeSupportedConfig(service, operation) +- setup: +- configureSdkClient(builder) +- def client = builder +- .endpointOverride(clientUri) +- .region(Region.AP_NORTHEAST_1) +- .credentialsProvider(CREDENTIALS_PROVIDER) +- .build() +- +- if (body instanceof Closure) { +- server.enqueue(body.call()) +- } else { +- server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, body)) +- } +- +- def response = call.call(client) +- if (response instanceof Future) { +- response = response.get() +- } +- +- expect: +- response != null +- +- assertTraces(1) { +- trace(0, 1) { +- span(0) { +- name operation != "SendMessage" ? "$service.$operation" : "somequeue publish" +- kind operation != "SendMessage" ? CLIENT : PRODUCER +- hasNoParent() +- attributes { +- if (service == "S3") { +- // Starting with AWS SDK V2 2.18.0, the s3 sdk will prefix the hostname with the bucket name in case +- // the bucket name is a valid DNS label, even in the case that we are using an endpoint override. +- // Previously the sdk was only doing that if endpoint had "s3" as label in the FQDN. +- // Our test assert both cases so that we don't need to know what version is being tested. +- "$ServerAttributes.SERVER_ADDRESS" { it == "somebucket.localhost" || it == "localhost" } +- "$UrlAttributes.URL_FULL" { it.startsWith("http://somebucket.localhost:${server.httpPort()}") || it.startsWith("http://localhost:${server.httpPort()}") } +- } else { +- "$ServerAttributes.SERVER_ADDRESS" "localhost" +- "$UrlAttributes.URL_FULL" { it == "http://localhost:${server.httpPort()}" || it == "http://localhost:${server.httpPort()}/" } +- } +- "$ServerAttributes.SERVER_PORT" server.httpPort() +- "$HttpAttributes.HTTP_REQUEST_METHOD" "$method" +- "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200 +- "$RpcIncubatingAttributes.RPC_SYSTEM" "aws-api" +- "$RpcIncubatingAttributes.RPC_SERVICE" "$service" +- "$RpcIncubatingAttributes.RPC_METHOD" "${operation}" +- "aws.agent" "java-aws-sdk" +- "$AwsIncubatingAttributes.AWS_REQUEST_ID" "$requestId" +- if (service == "S3") { +- "aws.bucket.name" "somebucket" +- } else if (service == "Sqs" && operation == "CreateQueue") { +- "aws.queue.name" "somequeue" +- } else if (service == "Sqs" && operation == "SendMessage") { +- "aws.queue.url" QUEUE_URL +- "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "somequeue" +- "$MessagingIncubatingAttributes.MESSAGING_OPERATION" "publish" +- "$MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID" String +- "$MessagingIncubatingAttributes.MESSAGING_SYSTEM" MessagingIncubatingAttributes.MessagingSystemIncubatingValues.AWS_SQS +- } else if (service == "Kinesis") { +- "aws.stream.name" "somestream" +- } else if (service == "Sns") { +- "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "somearn" +- } +- } +- } +- } +- } +- def request = server.takeRequest() +- request.request().headers().get("X-Amzn-Trace-Id") != null +- request.request().headers().get("traceparent") == null +- +- if (service == "Sns" && operation == "Publish") { +- def content = request.request().content().toStringUtf8() +- def containsId = content.contains("${traces[0][0].traceId}-${traces[0][0].spanId}") +- def containsTp = content.contains("=traceparent") +- if (isSqsAttributeInjectionEnabled()) { +- assert containsId && containsTp +- } else { +- assert !containsId && !containsTp +- } +- } +- +- where: +- service | operation | method | requestId | builder | call | body +- "S3" | "CreateBucket" | "PUT" | "UNKNOWN" | s3AsyncClientBuilder() | { c -> c.createBucket(CreateBucketRequest.builder().bucket("somebucket").build()) } | "" +- "S3" | "GetObject" | "GET" | "UNKNOWN" | s3AsyncClientBuilder() | { c -> c.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build(), AsyncResponseTransformer.toBytes()) } | "1234567890" +- // Kinesis seems to expect an http2 response which is incompatible with our test server. +- // "Kinesis" | "DeleteStream" | "POST" | "/" | "UNKNOWN" | KinesisAsyncClient.builder() | { c -> c.deleteStream(DeleteStreamRequest.builder().streamName("somestream").build()) } | "" +- "Sqs" | "CreateQueue" | "POST" | "7a62c49f-347e-4fc4-9331-6e8e7a96aa73" | SqsAsyncClient.builder() | { c -> c.createQueue(CreateQueueRequest.builder().queueName("somequeue").build()) } | { +- if (!Boolean.getBoolean("testLatestDeps")) { +- def content = """ +- +- https://queue.amazonaws.com/123456789012/MyQueue +- 7a62c49f-347e-4fc4-9331-6e8e7a96aa73 +- +- """ +- return HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, content) +- } +- def content = """ +- { +- "QueueUrl":"https://queue.amazonaws.com/123456789012/MyQueue" +- } +- """ +- ResponseHeaders headers = ResponseHeaders.builder(HttpStatus.OK) +- .contentType(MediaType.PLAIN_TEXT_UTF_8) +- .add("x-amzn-RequestId", "7a62c49f-347e-4fc4-9331-6e8e7a96aa73") +- .build() +- return HttpResponse.of(headers, HttpData.of(StandardCharsets.UTF_8, content)) +- } +- "Sqs" | "SendMessage" | "POST" | "27daac76-34dd-47df-bd01-1f6e873584a0" | SqsAsyncClient.builder() | { c -> c.sendMessage(SendMessageRequest.builder().queueUrl(QUEUE_URL).messageBody("").build()) } | { +- if (!Boolean.getBoolean("testLatestDeps")) { +- def content = """ +- +- +- d41d8cd98f00b204e9800998ecf8427e +- 3ae8f24a165a8cedc005670c81a27295 +- 5fea7756-0ea4-451a-a703-a558b933e274 +- +- 27daac76-34dd-47df-bd01-1f6e873584a0 +- +- """ +- return HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, content) + "Sfn" | "DescribeStateMachine" | "POST" | "UNKNOWN" | SfnClient.builder() + | { c -> c.describeStateMachine(DescribeStateMachineRequest.builder().stateMachineArn("stateMachineArn").build()) } + | "" @@ -1242,18 +2525,6 @@ index 7c152bb91b..b30b8fa2c7 100644 + "Lambda" | "GetEventSourceMapping" | "GET" |"UNKNOWN" | LambdaClient.builder() + | { c -> c.getEventSourceMapping(GetEventSourceMappingRequest.builder().uuid("sourceEventId").build()) } + | "" -+ "Sns" | "Publish" | "POST" | "d74b8436-ae13-5ab4-a9ff-ce54dfea72a0" | SnsClient.builder() -+ | { c -> c.publish(PublishRequest.builder().topicArn("topicArn").message("message").build()) } -+ | """ -+ -+ -+ 567910cd-659e-55d4-8ccb-5aaf14679dc0 -+ -+ -+ d74b8436-ae13-5ab4-a9ff-ce54dfea72a0 -+ -+ -+ """ + "SecretsManager" | "GetSecretValue" | "POST" | "UNKNOWN" | SecretsManagerClient.builder() + | { c -> c.getSecretValue(GetSecretValueRequest.builder().secretId("someSecret1").build()) } + | """ @@ -1263,104 +2534,219 @@ index 7c152bb91b..b30b8fa2c7 100644 + "Name":"MyTestDatabaseSecret", + "SecretString":"{\\n \\"username\\":\\"david\\",\\n \\"password\\":\\"EXAMPLE-PASSWORD\\"\\n}\\n", + "VersionId":"EXAMPLE1-90ab-cdef-fedc-ba987SECRET1" -+ } + } +- def content = """ +- { +- "MD5OfMessageBody":"d41d8cd98f00b204e9800998ecf8427e", +- "MD5OfMessageAttributes":"3ae8f24a165a8cedc005670c81a27295", +- "MessageId":"5fea7756-0ea4-451a-a703-a558b933e274" +- } +- """ +- ResponseHeaders headers = ResponseHeaders.builder(HttpStatus.OK) +- .contentType(MediaType.PLAIN_TEXT_UTF_8) +- .add("x-amzn-RequestId", "27daac76-34dd-47df-bd01-1f6e873584a0") +- .build() +- return HttpResponse.of(headers, HttpData.of(StandardCharsets.UTF_8, content)) +- } +- "Ec2" | "AllocateAddress" | "POST" | "59dbff89-35bd-4eac-99ed-be587EXAMPLE" | Ec2AsyncClient.builder() | { c -> c.allocateAddress() } | """ +- +- 59dbff89-35bd-4eac-99ed-be587EXAMPLE +- 192.0.2.1 +- standard +- +- """ +- "Rds" | "DeleteOptionGroup" | "POST" | "0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99" | RdsAsyncClient.builder() | { c -> c.deleteOptionGroup(DeleteOptionGroupRequest.builder().build()) } | """ +- +- 0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99 +- +- """ +- "Sns" | "Publish" | "POST" | "f187a3c1-376f-11df-8963-01868b7c937a" | SnsAsyncClient.builder() | { SnsAsyncClient c -> c.publish(r -> r.message("hello").topicArn("somearn")) } | """ +- +- +- 94f20ce6-13c5-43a0-9a9e-ca52d816e90b +- +- +- f187a3c1-376f-11df-8963-01868b7c937a +- +- +- """ + """ } - def "send #operation async request with builder #builder.class.getName() mocked response"() { -diff --git a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java -index 69b3c09c90..74a6f75ffb 100644 ---- a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java -+++ b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java -@@ -20,6 +20,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; - import java.io.InputStream; - import java.nio.file.Files; - import java.nio.file.Paths; -+import java.time.Duration; - import java.util.List; - - /** An {@link AgentListener} that enables JMX metrics during agent startup. */ -@@ -32,22 +33,22 @@ public class JmxMetricInsightInstaller implements AgentListener { - - if (config.getBoolean("otel.jmx.enabled", true)) { - JmxMetricInsight service = -- JmxMetricInsight.createService(GlobalOpenTelemetry.get(), beanDiscoveryDelay(config)); -+ JmxMetricInsight.createService( -+ GlobalOpenTelemetry.get(), beanDiscoveryDelay(config).toMillis()); - MetricConfiguration conf = buildMetricConfiguration(config); - service.start(conf); - } - } - -- private static long beanDiscoveryDelay(ConfigProperties configProperties) { -- Long discoveryDelay = configProperties.getLong("otel.jmx.discovery.delay"); -+ private static Duration beanDiscoveryDelay(ConfigProperties configProperties) { -+ Duration discoveryDelay = configProperties.getDuration("otel.jmx.discovery.delay"); - if (discoveryDelay != null) { - return discoveryDelay; - } - - // If discovery delay has not been configured, have a peek at the metric export interval. - // It makes sense for both of these values to be similar. -- long exportInterval = configProperties.getLong("otel.metric.export.interval", 60000); -- return exportInterval; -+ return configProperties.getDuration("otel.metric.export.interval", Duration.ofMinutes(1)); - } - - private static String resourceFor(String platform) { -diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java -index 8b0fd636be..b9856f1dc9 100644 ---- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java -+++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java -@@ -25,7 +25,13 @@ class BeanFinder { - - private final MetricRegistrar registrar; - private MetricConfiguration conf; -- private final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); -+ private final ScheduledExecutorService exec = -+ Executors.newSingleThreadScheduledExecutor( -+ runnable -> { -+ Thread result = new Thread(runnable, "jmx_bean_finder"); -+ result.setDaemon(true); -+ return result; -+ }); - private final long discoveryDelay; - private final long maxDelay; - private long delay = 1000; // number of milliseconds until first attempt to discover MBeans -@@ -39,12 +45,18 @@ class BeanFinder { - void discoverBeans(MetricConfiguration conf) { - this.conf = conf; - -- if (!conf.isEmpty()) { -- // Issue 9336: Corner case: PlatformMBeanServer will remain unitialized until a direct -- // reference to it is made. This call makes sure that the PlatformMBeanServer will be in -- // the set of MBeanServers reported by MBeanServerFactory. -- ManagementFactory.getPlatformMBeanServer(); -- } -+ exec.schedule( -+ () -> { -+ // Issue 9336: Corner case: PlatformMBeanServer will remain unitialized until a direct -+ // reference to it is made. This call makes sure that the PlatformMBeanServer will be in -+ // the set of MBeanServers reported by MBeanServerFactory. -+ // Issue 11143: This call initializes java.util.logging.LogManager. We should not call it -+ // before application has had a chance to configure custom log manager. This is needed for -+ // wildfly. -+ ManagementFactory.getPlatformMBeanServer(); -+ }, -+ discoveryDelay, -+ TimeUnit.MILLISECONDS); - - exec.schedule( - new Runnable() { ++// def "send #operation async request with builder #builder.class.getName() mocked response"() { ++// assumeSupportedConfig(service, operation) ++// setup: ++// configureSdkClient(builder) ++// def client = builder ++// .endpointOverride(clientUri) ++// .region(Region.AP_NORTHEAST_1) ++// .credentialsProvider(CREDENTIALS_PROVIDER) ++// .build() ++// ++// if (body instanceof Closure) { ++// server.enqueue(body.call()) ++// } else { ++// server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, body)) ++// } ++// ++// def response = call.call(client) ++// if (response instanceof Future) { ++// response = response.get() ++// } ++// ++// expect: ++// response != null ++// ++// assertTraces(1) { ++// trace(0, 1) { ++// span(0) { ++// name operation != "SendMessage" ? "$service.$operation" : "somequeue publish" ++// kind operation != "SendMessage" ? CLIENT : PRODUCER ++// hasNoParent() ++// attributes { ++// if (service == "S3") { ++// // Starting with AWS SDK V2 2.18.0, the s3 sdk will prefix the hostname with the bucket name in case ++// // the bucket name is a valid DNS label, even in the case that we are using an endpoint override. ++// // Previously the sdk was only doing that if endpoint had "s3" as label in the FQDN. ++// // Our test assert both cases so that we don't need to know what version is being tested. ++// "$ServerAttributes.SERVER_ADDRESS" { it == "somebucket.localhost" || it == "localhost" } ++// "$UrlAttributes.URL_FULL" { it.startsWith("http://somebucket.localhost:${server.httpPort()}") || it.startsWith("http://localhost:${server.httpPort()}") } ++// } else { ++// "$ServerAttributes.SERVER_ADDRESS" "localhost" ++// "$UrlAttributes.URL_FULL" { it == "http://localhost:${server.httpPort()}" || it == "http://localhost:${server.httpPort()}/" } ++// } ++// "$ServerAttributes.SERVER_PORT" server.httpPort() ++// "$HttpAttributes.HTTP_REQUEST_METHOD" "$method" ++// "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200 ++// "$RpcIncubatingAttributes.RPC_SYSTEM" "aws-api" ++// "$RpcIncubatingAttributes.RPC_SERVICE" "$service" ++// "$RpcIncubatingAttributes.RPC_METHOD" "${operation}" ++// "aws.agent" "java-aws-sdk" ++// "$AwsIncubatingAttributes.AWS_REQUEST_ID" "$requestId" ++// if (service == "S3") { ++// "aws.bucket.name" "somebucket" ++// } else if (service == "Sqs" && operation == "CreateQueue") { ++// "aws.queue.name" "somequeue" ++// } else if (service == "Sqs" && operation == "SendMessage") { ++// "aws.queue.url" QUEUE_URL ++// "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "somequeue" ++// "$MessagingIncubatingAttributes.MESSAGING_OPERATION" "publish" ++// "$MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID" String ++// "$MessagingIncubatingAttributes.MESSAGING_SYSTEM" MessagingIncubatingAttributes.MessagingSystemIncubatingValues.AWS_SQS ++// } else if (service == "Kinesis") { ++// "aws.stream.name" "somestream" ++// } else if (service == "Sns") { ++// "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "somearn" ++// } ++// } ++// } ++// } ++// } ++// def request = server.takeRequest() ++// request.request().headers().get("X-Amzn-Trace-Id") != null ++// request.request().headers().get("traceparent") == null ++// ++// if (service == "Sns" && operation == "Publish") { ++// def content = request.request().content().toStringUtf8() ++// def containsId = content.contains("${traces[0][0].traceId}-${traces[0][0].spanId}") ++// def containsTp = content.contains("=traceparent") ++// if (isSqsAttributeInjectionEnabled()) { ++// assert containsId && containsTp ++// } else { ++// assert !containsId && !containsTp ++// } ++// } ++// ++// where: ++// service | operation | method | requestId | builder | call | body ++// "S3" | "CreateBucket" | "PUT" | "UNKNOWN" | s3AsyncClientBuilder() | { c -> c.createBucket(CreateBucketRequest.builder().bucket("somebucket").build()) } | "" ++// "S3" | "GetObject" | "GET" | "UNKNOWN" | s3AsyncClientBuilder() | { c -> c.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build(), AsyncResponseTransformer.toBytes()) } | "1234567890" ++// // Kinesis seems to expect an http2 response which is incompatible with our test server. ++// // "Kinesis" | "DeleteStream" | "POST" | "/" | "UNKNOWN" | KinesisAsyncClient.builder() | { c -> c.deleteStream(DeleteStreamRequest.builder().streamName("somestream").build()) } | "" ++// "Sqs" | "CreateQueue" | "POST" | "7a62c49f-347e-4fc4-9331-6e8e7a96aa73" | SqsAsyncClient.builder() | { c -> c.createQueue(CreateQueueRequest.builder().queueName("somequeue").build()) } | { ++// if (!Boolean.getBoolean("testLatestDeps")) { ++// def content = """ ++// ++// https://queue.amazonaws.com/123456789012/MyQueue ++// 7a62c49f-347e-4fc4-9331-6e8e7a96aa73 ++// ++// """ ++// return HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, content) ++// } ++// def content = """ ++// { ++// "QueueUrl":"https://queue.amazonaws.com/123456789012/MyQueue" ++// } ++// """ ++// ResponseHeaders headers = ResponseHeaders.builder(HttpStatus.OK) ++// .contentType(MediaType.PLAIN_TEXT_UTF_8) ++// .add("x-amzn-RequestId", "7a62c49f-347e-4fc4-9331-6e8e7a96aa73") ++// .build() ++// return HttpResponse.of(headers, HttpData.of(StandardCharsets.UTF_8, content)) ++// } ++// "Sqs" | "SendMessage" | "POST" | "27daac76-34dd-47df-bd01-1f6e873584a0" | SqsAsyncClient.builder() | { c -> c.sendMessage(SendMessageRequest.builder().queueUrl(QUEUE_URL).messageBody("").build()) } | { ++// if (!Boolean.getBoolean("testLatestDeps")) { ++// def content = """ ++// ++// ++// d41d8cd98f00b204e9800998ecf8427e ++// 3ae8f24a165a8cedc005670c81a27295 ++// 5fea7756-0ea4-451a-a703-a558b933e274 ++// ++// 27daac76-34dd-47df-bd01-1f6e873584a0 ++// ++// """ ++// return HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, content) ++// } ++// def content = """ ++// { ++// "MD5OfMessageBody":"d41d8cd98f00b204e9800998ecf8427e", ++// "MD5OfMessageAttributes":"3ae8f24a165a8cedc005670c81a27295", ++// "MessageId":"5fea7756-0ea4-451a-a703-a558b933e274" ++// } ++// """ ++// ResponseHeaders headers = ResponseHeaders.builder(HttpStatus.OK) ++// .contentType(MediaType.PLAIN_TEXT_UTF_8) ++// .add("x-amzn-RequestId", "27daac76-34dd-47df-bd01-1f6e873584a0") ++// .build() ++// return HttpResponse.of(headers, HttpData.of(StandardCharsets.UTF_8, content)) ++// } ++// "Ec2" | "AllocateAddress" | "POST" | "59dbff89-35bd-4eac-99ed-be587EXAMPLE" | Ec2AsyncClient.builder() | { c -> c.allocateAddress() } | """ ++// ++// 59dbff89-35bd-4eac-99ed-be587EXAMPLE ++// 192.0.2.1 ++// standard ++// ++// """ ++// "Rds" | "DeleteOptionGroup" | "POST" | "0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99" | RdsAsyncClient.builder() | { c -> c.deleteOptionGroup(DeleteOptionGroupRequest.builder().build()) } | """ ++// ++// 0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99 ++// ++// """ ++// "Sns" | "Publish" | "POST" | "f187a3c1-376f-11df-8963-01868b7c937a" | SnsAsyncClient.builder() | { SnsAsyncClient c -> c.publish(r -> r.message("hello").topicArn("somearn")) } | """ ++// ++// ++// 94f20ce6-13c5-43a0-9a9e-ca52d816e90b ++// ++// ++// f187a3c1-376f-11df-8963-01868b7c937a ++// ++// ++// """ ++// } ++ + // TODO(anuraaga): Without AOP instrumentation of the HTTP client, we cannot model retries as + // spans because of https://github.com/aws/aws-sdk-java-v2/issues/1741. We should at least tweak + // the instrumentation to add Events for retries instead. diff --git a/version.gradle.kts b/version.gradle.kts -index 5217d396e2..66cc8ecb2a 100644 +index 7900c9a4d9..57b4d36c0a 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -1,5 +1,5 @@ --val stableVersion = "1.33.6" --val alphaVersion = "1.33.6-alpha" -+val stableVersion = "1.33.6-adot1" -+val alphaVersion = "1.33.6-adot1-alpha" +-val stableVersion = "2.10.0" +-val alphaVersion = "2.10.0-alpha" ++val stableVersion = "2.10.0-adot1" ++val alphaVersion = "2.10.0-adot1-alpha" allprojects { if (findProperty("otel.stable") != "true") { diff --git a/.github/patches/versions b/.github/patches/versions index 46fc43aaa1..2266e4202f 100644 --- a/.github/patches/versions +++ b/.github/patches/versions @@ -1 +1 @@ -OTEL_JAVA_INSTRUMENTATION_VERSION=v1.33.6 \ No newline at end of file +OTEL_JAVA_INSTRUMENTATION_VERSION=v2.10.0 \ No newline at end of file diff --git a/.github/workflows/docker-build-smoke-tests-fake-backend.yml b/.github/workflows/docker-build-smoke-tests-fake-backend.yml index 5cd5f2956c..7bcb06a6fe 100644 --- a/.github/workflows/docker-build-smoke-tests-fake-backend.yml +++ b/.github/workflows/docker-build-smoke-tests-fake-backend.yml @@ -25,6 +25,19 @@ jobs: with: java-version: 17 distribution: 'temurin' + # cache local patch outputs + - name: Cache local Maven repository + uses: actions/cache@v3 + with: + path: | + ~/.m2/repository/io/opentelemetry/ + key: ${{ runner.os }}-maven-local-${{ hashFiles('.github/patches/opentelemetry-java*.patch') }} + + - name: Publish patched dependencies to maven local + uses: ./.github/actions/patch-dependencies + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg_password: ${{ secrets.GPG_PASSPHRASE }} - uses: gradle/wrapper-validation-action@v1 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 diff --git a/.github/workflows/main-build.yml b/.github/workflows/main-build.yml index 07f8b29fa2..89870e82be 100644 --- a/.github/workflows/main-build.yml +++ b/.github/workflows/main-build.yml @@ -194,7 +194,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-java@v4 with: - java-version: 21 + java-version: 23 distribution: 'temurin' - uses: gradle/wrapper-validation-action@v1 @@ -219,7 +219,7 @@ jobs: key: ${{ runner.os }}-maven-local-${{ hashFiles('.github/patches/opentelemetry-java*.patch') }} - name: Pull base image of Contract Tests Sample Apps - run: docker pull public.ecr.aws/docker/library/amazoncorretto:21-alpine + run: docker pull public.ecr.aws/docker/library/amazoncorretto:23-alpine - name: Build snapshot with Gradle uses: gradle/gradle-build-action@v3 diff --git a/.github/workflows/nightly-upstream-snapshot-build.yml b/.github/workflows/nightly-upstream-snapshot-build.yml index a364358265..dde8608042 100644 --- a/.github/workflows/nightly-upstream-snapshot-build.yml +++ b/.github/workflows/nightly-upstream-snapshot-build.yml @@ -32,6 +32,20 @@ jobs: java-version: 17 distribution: 'temurin' + # cache local patch outputs + - name: Cache local Maven repository + uses: actions/cache@v3 + with: + path: | + ~/.m2/repository/io/opentelemetry/ + key: ${{ runner.os }}-maven-local-${{ hashFiles('.github/patches/opentelemetry-java*.patch') }} + + - name: Publish patched dependencies to maven local + uses: ./.github/actions/patch-dependencies + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg_password: ${{ secrets.GPG_PASSPHRASE }} + - uses: gradle/wrapper-validation-action@v1 - name: Configure AWS Credentials @@ -120,7 +134,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-java@v4 with: - java-version: 21 + java-version: 23 distribution: 'temurin' - uses: gradle/wrapper-validation-action@v1 @@ -136,7 +150,7 @@ jobs: registry: public.ecr.aws - name: Pull base image of Contract Tests Sample Apps - run: docker pull public.ecr.aws/docker/library/amazoncorretto:21-alpine + run: docker pull public.ecr.aws/docker/library/amazoncorretto:23-alpine - name: Build snapshot with Gradle uses: gradle/gradle-build-action@v3 diff --git a/.github/workflows/patch-release-build.yml b/.github/workflows/patch-release-build.yml index c56255204e..4cbc3965fa 100644 --- a/.github/workflows/patch-release-build.yml +++ b/.github/workflows/patch-release-build.yml @@ -12,7 +12,7 @@ on: env: AWS_DEFAULT_REGION: us-east-1 - TEST_TAG: public.ecr.aws/aws-observability/adot-autoinstrumentation-java:test + TEST_TAG: public.ecr.aws/aws-observability/adot-autoinstrumentation-java:test-v2 permissions: id-token: write diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 9e47a15bce..57fc2422d2 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -5,7 +5,7 @@ on: - main - "release/v*" env: - TEST_TAG: public.ecr.aws/aws-observability/adot-autoinstrumentation-java:test + TEST_TAG: public.ecr.aws/aws-observability/adot-autoinstrumentation-java:test-v2 jobs: testpatch: @@ -63,6 +63,13 @@ jobs: - uses: gradle/wrapper-validation-action@v1 + # Cleanup directories before proceeding with setup + - name: Clean up old installations + if: ${{ matrix.os != 'windows-latest' }} + run: | + sudo rm -rf /usr/local/lib/android + sudo rm -rf /usr/share/dotnet + # cache local patch outputs - name: Cache local Maven repository uses: actions/cache@v3 @@ -84,12 +91,12 @@ jobs: - name: Set up Java version for tests uses: actions/setup-java@v4 with: - java-version: 21 + java-version: 23 distribution: temurin - name: Pull base image of Contract Tests Sample Apps if: ${{ matrix.os == 'ubuntu-latest' }} - run: docker pull public.ecr.aws/docker/library/amazoncorretto:21-alpine + run: docker pull public.ecr.aws/docker/library/amazoncorretto:23-alpine - name: Run contract tests uses: gradle/gradle-build-action@v3 diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 5ddb016af7..41ca87fbc4 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -9,7 +9,7 @@ on: env: AWS_PUBLIC_ECR_REGION: us-east-1 AWS_PRIVATE_ECR_REGION: us-west-2 - TEST_TAG: public.ecr.aws/aws-observability/adot-autoinstrumentation-java:test + TEST_TAG: public.ecr.aws/aws-observability/adot-autoinstrumentation-java:test-v2 PUBLIC_REPOSITORY: public.ecr.aws/aws-observability/adot-autoinstrumentation-java PRIVATE_REPOSITORY: 020628701572.dkr.ecr.us-west-2.amazonaws.com/adot-autoinstrumentation-java PRIVATE_REGISTRY: 020628701572.dkr.ecr.us-west-2.amazonaws.com diff --git a/README.md b/README.md index 4af75998eb..c450790dcc 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,11 @@ can be exported in a variety of formats. In addition, the agent and exporter can command line arguments or environment variables. The net result is the ability to gather telemetry data from a Java application without any code changes. +Note: There are 2.x releases and 1.x releases. The 2.0 release included significant breaking changes from [OpenTelemetry Agent for Java](https://github.com/open-telemetry/opentelemetry-java-instrumentation), +the details of which can be found in the [release notes](https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases). +It is recommended to use the latest 2.x release which will have the latest features and improvements. +1.x will receive security patches for a limited time and will not include other bug fixes and enhancements. + ## Getting Started Check out the [getting started documentation](https://aws-otel.github.io/docs/getting-started/java-sdk/auto-instr). @@ -45,4 +50,4 @@ In addition to the sample apps in this repository, there are also a set of [stan Please note that as per policy, we're providing support via GitHub on a best effort basis. However, if you have AWS Enterprise Support you can create a ticket and we will provide direct support within the respective SLAs. ## Security issue notifications -If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. +If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. \ No newline at end of file diff --git a/appsignals-tests/contract-tests/build.gradle.kts b/appsignals-tests/contract-tests/build.gradle.kts index 70780d767c..ac15939a62 100644 --- a/appsignals-tests/contract-tests/build.gradle.kts +++ b/appsignals-tests/contract-tests/build.gradle.kts @@ -33,7 +33,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { java - kotlin("jvm") version "1.8.22" + kotlin("jvm") version "2.1.0-RC2" } java { diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/awssdk/base/AwsSdkBaseTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/awssdk/base/AwsSdkBaseTest.java index 278aa4011d..fc0381d7d9 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/awssdk/base/AwsSdkBaseTest.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/awssdk/base/AwsSdkBaseTest.java @@ -263,19 +263,19 @@ private void assertSemanticConventionsAttributes( List attributesList, String service, String method, - String peerName, - int peerPort, + String address, + int port, String url, int statusCode) { assertThat(attributesList) .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.RPC_METHOD, method)) .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.RPC_SERVICE, service)) .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.RPC_SYSTEM, "aws-api")) - .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.NET_PEER_NAME, peerName)) - .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.NET_PEER_PORT, peerPort)) + .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.SERVER_ADDRESS, address)) + .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.SERVER_PORT, port)) .satisfiesOnlyOnce( - assertAttribute(SemanticConventionsConstants.HTTP_STATUS_CODE, statusCode)) - .satisfiesOnlyOnce(assertAttributeStartsWith(SemanticConventionsConstants.HTTP_URL, url)) + assertAttribute(SemanticConventionsConstants.HTTP_RESPONSE_STATUS_CODE, statusCode)) + .satisfiesOnlyOnce(assertAttributeStartsWith(SemanticConventionsConstants.URL_FULL, url)) .satisfiesOnlyOnce(assertKeyIsPresent(SemanticConventionsConstants.THREAD_ID)); } @@ -284,16 +284,16 @@ private void assertSemanticConventionsSqsConsumerAttributes( List attributesList, String service, String method, - String peerName, - int peerPort, + String address, + int port, String url) { assertThat(attributesList) .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.RPC_METHOD, method)) .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.RPC_SERVICE, service)) .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.RPC_SYSTEM, "aws-api")) - .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.NET_PEER_NAME, peerName)) - .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.NET_PEER_PORT, peerPort)) - .satisfiesOnlyOnce(assertAttributeStartsWith(SemanticConventionsConstants.HTTP_URL, url)) + .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.SERVER_ADDRESS, address)) + .satisfiesOnlyOnce(assertAttribute(SemanticConventionsConstants.SERVER_PORT, port)) + .satisfiesOnlyOnce(assertAttributeStartsWith(SemanticConventionsConstants.URL_FULL, url)) .satisfiesOnlyOnce(assertKeyIsPresent(SemanticConventionsConstants.THREAD_ID)); } @@ -308,8 +308,8 @@ private void assertSpanClientAttributes( String type, String identifier, String cloudformationIdentifier, - String peerName, - int peerPort, + String address, + int port, String url, int statusCode, List> extraAssertions) { @@ -327,8 +327,8 @@ private void assertSpanClientAttributes( type, identifier, cloudformationIdentifier, - peerName, - peerPort, + address, + port, url, statusCode, extraAssertions); @@ -345,8 +345,8 @@ private void assertSpanProducerAttributes( String type, String identifier, String cloudformationIdentifier, - String peerName, - int peerPort, + String address, + int port, String url, int statusCode, List> extraAssertions) { @@ -363,8 +363,8 @@ private void assertSpanProducerAttributes( type, identifier, cloudformationIdentifier, - peerName, - peerPort, + address, + port, url, statusCode, extraAssertions); @@ -377,8 +377,8 @@ private void assertSpanConsumerAttributes( String operation, String localService, String method, - String peerName, - int peerPort, + String address, + int port, String url, int statusCode, List> extraAssertions) { @@ -391,7 +391,7 @@ private void assertSpanConsumerAttributes( assertThat(span.getKind()).isEqualTo(SpanKind.SPAN_KIND_CONSUMER); assertThat(span.getName()).isEqualTo(spanName); assertSemanticConventionsSqsConsumerAttributes( - spanAttributes, rpcService, method, peerName, peerPort, url); + spanAttributes, rpcService, method, address, port, url); assertSqsConsumerAwsAttributes(span.getAttributesList(), operation); for (var assertion : extraAssertions) { assertThat(spanAttributes).satisfiesOnlyOnce(assertion); @@ -412,8 +412,8 @@ private void assertSpanAttributes( String type, String identifier, String cloudformationIdentifier, - String peerName, - int peerPort, + String address, + int port, String url, int statusCode, List> extraAssertions) { @@ -425,9 +425,8 @@ private void assertSpanAttributes( var spanAttributes = span.getAttributesList(); assertThat(span.getKind()).isEqualTo(spanKind); assertThat(span.getName()).isEqualTo(spanName); - assertSemanticConventionsAttributes( - spanAttributes, rpcService, method, peerName, peerPort, url, statusCode); + spanAttributes, rpcService, method, address, port, url, statusCode); assertAwsAttributes( spanAttributes, localService, diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/base/ContractTestBase.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/base/ContractTestBase.java index bb8a2255f3..456dd7e1cb 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/base/ContractTestBase.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/base/ContractTestBase.java @@ -152,7 +152,9 @@ protected Map getApplicationEnvironmentVariables() { "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", COLLECTOR_HTTP_ENDPOINT, "OTEL_RESOURCE_ATTRIBUTES", - getApplicationOtelResourceAttributes()); + getApplicationOtelResourceAttributes(), + "OTEL_EXPORTER_OTLP_PROTOCOL", + "grpc"); } protected Map getApplicationExtraEnvironmentVariables() { diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/base/JMXMetricsContractTestBase.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/base/JMXMetricsContractTestBase.java index e6d9d76b06..0b0fd6e7cd 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/base/JMXMetricsContractTestBase.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/base/JMXMetricsContractTestBase.java @@ -62,6 +62,11 @@ protected long getThreshold(String metricName) { switch (metricName) { // If maximum memory size is undefined, then value is -1 // https://docs.oracle.com/en/java/javase/17/docs/api/java.management/java/lang/management/MemoryUsage.html#getMax() + // Thread count can be negative when excutor is null + // https://github.com/apache/tomcat/blob/1afe41491f0e56ec0a776db5ff84607f87ce6640/java/org/apache/tomcat/util/net/AbstractEndpoint.java#L1204 + case JMXMetricsConstants.TOMCAT_THREADS: + threshold = -2; + break; case JMXMetricsConstants.JVM_HEAP_MAX: case JMXMetricsConstants.JVM_NON_HEAP_MAX: case JMXMetricsConstants.JVM_POOL_MAX: diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/grpc/client/GrpcClientTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/grpc/client/GrpcClientTest.java index 2970bef65b..edd6c7404d 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/grpc/client/GrpcClientTest.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/grpc/client/GrpcClientTest.java @@ -229,12 +229,12 @@ protected void assertSemanticConventionsAttributes( assertThat(attributesList) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.NET_PEER_NAME); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_ADDRESS); assertThat(attribute.getValue().getStringValue()).isEqualTo("server"); }) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.NET_PEER_PORT); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_PORT); assertThat(attribute.getValue().getIntValue()).isEqualTo(50051L); }) .satisfiesOnlyOnce( @@ -266,15 +266,10 @@ protected void assertSemanticConventionsAttributes( assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.RPC_SERVICE); assertThat(attribute.getValue().getStringValue()).isEqualTo(GRPC_SERVICE_NAME); }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.NET_PEER_NAME); - assertThat(attribute.getValue().getStringValue()).isEqualTo("server"); - }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_SOCK_PEER_ADDR); + .isEqualTo(SemanticConventionsConstants.NETWORK_PEER_ADDRESS); }); } diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/grpc/server/GrpcServerTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/grpc/server/GrpcServerTest.java index 66fd3cf01e..310ab06778 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/grpc/server/GrpcServerTest.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/grpc/server/GrpcServerTest.java @@ -271,20 +271,20 @@ protected void assertSemanticConventionsAttributes( .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_SOCK_PEER_ADDR); + .isEqualTo(SemanticConventionsConstants.NETWORK_PEER_ADDRESS); }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_SOCK_PEER_PORT); + .isEqualTo(SemanticConventionsConstants.NETWORK_PEER_PORT); }) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.NET_HOST_PORT); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_PORT); }) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.NET_HOST_NAME); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_ADDRESS); assertThat(attribute.getValue().getStringValue()).isEqualTo("localhost"); }); } diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpclients/base/BaseHttpClientTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpclients/base/BaseHttpClientTest.java index aa9ff6b97c..33f5119bb8 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpclients/base/BaseHttpClientTest.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpclients/base/BaseHttpClientTest.java @@ -119,46 +119,36 @@ protected void assertSemanticConventionsAttributes( assertThat(attributesList) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.NET_PEER_NAME); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_ADDRESS); assertThat(attribute.getValue().getStringValue()).isEqualTo("backend"); }) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.NET_PEER_PORT); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_PORT); assertThat(attribute.getValue().getIntValue()).isEqualTo(8080L); }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.HTTP_STATUS_CODE); + .isEqualTo(SemanticConventionsConstants.HTTP_RESPONSE_STATUS_CODE); assertThat(attribute.getValue().getIntValue()).isEqualTo(status_code); }) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.HTTP_URL); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.URL_FULL); assertThat(attribute.getValue().getStringValue()) .isEqualTo(String.format("%s/%s", "http://backend:8080/backend", endpoint)); }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.HTTP_METHOD); - assertThat(attribute.getValue().getStringValue()).isEqualTo(method); - }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_PROTOCOL_NAME); - assertThat(attribute.getValue().getStringValue()).isEqualTo("http"); + .isEqualTo(SemanticConventionsConstants.HTTP_REQUEST_METHOD); + assertThat(attribute.getValue().getStringValue()).isEqualTo(method); }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_PROTOCOL_VERSION); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.PEER_SERVICE); - assertThat(attribute.getValue().getStringValue()).isEqualTo("backend:8080"); + .isEqualTo(SemanticConventionsConstants.NETWORK_PROTOCOL_VERSION); }) .satisfiesOnlyOnce( attribute -> { @@ -168,6 +158,15 @@ protected void assertSemanticConventionsAttributes( attribute -> { assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_NAME); }); + + if (!getApplicationImageName().equals("aws-appsignals-tests-netty-http-client-app")) { + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.PEER_SERVICE); + assertThat(attribute.getValue().getStringValue()).isEqualTo("backend:8080"); + }); + } } protected void assertMetricAttributes( diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/base/BaseHttpServerTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/base/BaseHttpServerTest.java index 5af6972842..ce55c23fe5 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/base/BaseHttpServerTest.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/base/BaseHttpServerTest.java @@ -89,45 +89,29 @@ protected void assertSemanticConventionsAttributes( assertThat(attributesList) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.NET_HOST_NAME); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_ADDRESS); assertThat(attribute.getValue().getStringValue()).isEqualTo("localhost"); }) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.NET_HOST_PORT); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_PORT); }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_SOCK_HOST_ADDR); + .isEqualTo(SemanticConventionsConstants.NETWORK_PEER_ADDRESS); }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_SOCK_HOST_PORT); - assertThat(attribute.getValue().getIntValue()).isEqualTo(8080L); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_SOCK_PEER_ADDR); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_SOCK_PEER_PORT); + .isEqualTo(SemanticConventionsConstants.NETWORK_PEER_PORT); assertThat(attribute.getValue().getIntValue()).isBetween(1023L, 65536L); }) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.HTTP_SCHEME); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.URL_SCHEME); assertThat(attribute.getValue().getStringValue()).isEqualTo("http"); }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.HTTP_RESPONSE_CONTENT_LENGTH); - }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.HTTP_ROUTE); @@ -135,30 +119,25 @@ protected void assertSemanticConventionsAttributes( }) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.HTTP_TARGET); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.URL_PATH); assertThat(attribute.getValue().getStringValue()).isEqualTo(target); }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.HTTP_STATUS_CODE); + .isEqualTo(SemanticConventionsConstants.HTTP_RESPONSE_STATUS_CODE); assertThat(attribute.getValue().getIntValue()).isEqualTo(status_code); }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.HTTP_METHOD); - assertThat(attribute.getValue().getStringValue()).isEqualTo(method); - }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_PROTOCOL_NAME); - assertThat(attribute.getValue().getStringValue()).isEqualTo("http"); + .isEqualTo(SemanticConventionsConstants.HTTP_REQUEST_METHOD); + assertThat(attribute.getValue().getStringValue()).isEqualTo(method); }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_PROTOCOL_VERSION); + .isEqualTo(SemanticConventionsConstants.NETWORK_PROTOCOL_VERSION); }) .satisfiesOnlyOnce( attribute -> { diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/nettyserver/NettyServer.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/nettyserver/NettyServer.java index 974ab2ce98..b2afedd237 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/nettyserver/NettyServer.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/nettyserver/NettyServer.java @@ -91,70 +91,49 @@ protected void assertSemanticConventionsAttributes( assertThat(attributesList) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.NET_HOST_NAME); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_ADDRESS); assertThat(attribute.getValue().getStringValue()).isEqualTo("localhost"); }) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.NET_HOST_PORT); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_PORT); }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_SOCK_HOST_ADDR); + .isEqualTo(SemanticConventionsConstants.NETWORK_PEER_ADDRESS); }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_SOCK_HOST_PORT); - assertThat(attribute.getValue().getIntValue()).isEqualTo(8080L); + .isEqualTo(SemanticConventionsConstants.NETWORK_PEER_PORT); }) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_SOCK_PEER_ADDR); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_SOCK_PEER_PORT); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.HTTP_SCHEME); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.URL_SCHEME); assertThat(attribute.getValue().getStringValue()).isEqualTo("http"); }) .satisfiesOnlyOnce( attribute -> { - assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.HTTP_RESPONSE_CONTENT_LENGTH); - }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.HTTP_TARGET); + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.URL_PATH); assertThat(attribute.getValue().getStringValue()).isEqualTo(target); }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.HTTP_STATUS_CODE); + .isEqualTo(SemanticConventionsConstants.HTTP_RESPONSE_STATUS_CODE); assertThat(attribute.getValue().getIntValue()).isEqualTo(status_code); }) - .satisfiesOnlyOnce( - attribute -> { - assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.HTTP_METHOD); - assertThat(attribute.getValue().getStringValue()).isEqualTo(method); - }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_PROTOCOL_NAME); - assertThat(attribute.getValue().getStringValue()).isEqualTo("http"); + .isEqualTo(SemanticConventionsConstants.HTTP_REQUEST_METHOD); + assertThat(attribute.getValue().getStringValue()).isEqualTo(method); }) .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.NET_PROTOCOL_VERSION); + .isEqualTo(SemanticConventionsConstants.NETWORK_PROTOCOL_VERSION); }) .satisfiesOnlyOnce( attribute -> { diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/springmvc/SpringMvc.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/springmvc/SpringMvc.java index 832c468c37..7dc6b73e60 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/springmvc/SpringMvc.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/springmvc/SpringMvc.java @@ -30,10 +30,15 @@ * permissions and limitations under the License. */ +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.proto.common.v1.KeyValue; +import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.testcontainers.junit.jupiter.Testcontainers; import software.amazon.opentelemetry.appsignals.test.httpservers.base.BaseHttpServerTest; +import software.amazon.opentelemetry.appsignals.test.utils.SemanticConventionsConstants; @Testcontainers(disabledWithoutDocker = true) @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -48,6 +53,72 @@ protected String getApplicationWaitPattern() { return ".*Started Application.*"; } + @Override + protected void assertSemanticConventionsAttributes( + List attributesList, String method, String route, String target, long status_code) { + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_ADDRESS); + assertThat(attribute.getValue().getStringValue()).isEqualTo("localhost"); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_PORT); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.NETWORK_PEER_ADDRESS); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.NETWORK_PEER_PORT); + assertThat(attribute.getValue().getIntValue()).isBetween(1023L, 65536L); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.URL_SCHEME); + assertThat(attribute.getValue().getStringValue()).isEqualTo("http"); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.HTTP_ROUTE); + assertThat(attribute.getValue().getStringValue()).isEqualTo(route); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.HTTP_RESPONSE_STATUS_CODE); + assertThat(attribute.getValue().getIntValue()).isEqualTo(status_code); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.HTTP_REQUEST_METHOD); + assertThat(attribute.getValue().getStringValue()).isEqualTo(method); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.NETWORK_PROTOCOL_VERSION); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_ID); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_NAME); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.USER_AGENT_ORIGINAL); + }); + } + @Test void testRoutes() { doTestRoutes("/users/{userId}/orders/{orderId}"); diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/tomcat/Tomcat.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/tomcat/Tomcat.java index 2b8abfafb4..27c8e9f873 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/tomcat/Tomcat.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/httpservers/tomcat/Tomcat.java @@ -30,10 +30,15 @@ * permissions and limitations under the License. */ +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.proto.common.v1.KeyValue; +import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.testcontainers.junit.jupiter.Testcontainers; import software.amazon.opentelemetry.appsignals.test.httpservers.base.BaseHttpServerTest; +import software.amazon.opentelemetry.appsignals.test.utils.SemanticConventionsConstants; @Testcontainers(disabledWithoutDocker = true) @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -49,6 +54,72 @@ protected String getApplicationImageName() { return "aws-appsignals-tests-http-server-tomcat"; } + @Override + protected void assertSemanticConventionsAttributes( + List attributesList, String method, String route, String target, long status_code) { + assertThat(attributesList) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_ADDRESS); + assertThat(attribute.getValue().getStringValue()).isEqualTo("localhost"); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.SERVER_PORT); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.NETWORK_PEER_ADDRESS); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.NETWORK_PEER_PORT); + assertThat(attribute.getValue().getIntValue()).isBetween(1023L, 65536L); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.URL_SCHEME); + assertThat(attribute.getValue().getStringValue()).isEqualTo("http"); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.HTTP_ROUTE); + assertThat(attribute.getValue().getStringValue()).isEqualTo(route); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.HTTP_RESPONSE_STATUS_CODE); + assertThat(attribute.getValue().getIntValue()).isEqualTo(status_code); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.HTTP_REQUEST_METHOD); + assertThat(attribute.getValue().getStringValue()).isEqualTo(method); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.NETWORK_PROTOCOL_VERSION); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_ID); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()).isEqualTo(SemanticConventionsConstants.THREAD_NAME); + }) + .satisfiesOnlyOnce( + attribute -> { + assertThat(attribute.getKey()) + .isEqualTo(SemanticConventionsConstants.USER_AGENT_ORIGINAL); + }); + } + @Test void testRoutes() { // Tomcat ServLets have a primitive support to url templates (It only has support to wildcards). diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java index 706b314979..8b8e953985 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/jdbc/JdbcContractTestBase.java @@ -34,7 +34,7 @@ public class JdbcContractTestBase extends ContractTestBase { protected static final String DB_USER = "root"; protected static final String DB_PASSWORD = "password"; protected static final String DB_SELECT_OPERATION = "SELECT"; - protected static final String DB_CREATE_DATABASE_OPERATION = "CREATE DATABASE"; + protected static final String DB_CREATE_DATABASE_OPERATION = "CREATE database"; protected static final String DB_RESOURCE_TYPE = "DB::Connection"; @Override @@ -159,7 +159,7 @@ protected void assertSemanticConventionsSpanAttributes( private void assertSemanticConventionForOperation( ResourceScopeSpan rss, String dbOperation, String dbName, String dbSqlTable) { if (dbOperation.equals(DB_CREATE_DATABASE_OPERATION)) { - assertThat(rss.getSpan().getName()).isEqualTo(String.format("%s", dbName)); + assertThat(rss.getSpan().getName()).isEqualTo(String.format("%s %s", dbOperation, dbName)); } else if (dbOperation.equals(DB_SELECT_OPERATION)) { assertThat(rss.getSpan().getName()) .isEqualTo(String.format("%s %s.%s", dbOperation, dbName, dbSqlTable)); diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/kafka/consumers/KafkaConsumersTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/kafka/consumers/KafkaConsumersTest.java index fb2cad6fe9..48f5c249f3 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/kafka/consumers/KafkaConsumersTest.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/kafka/consumers/KafkaConsumersTest.java @@ -178,7 +178,7 @@ protected void assertSemanticConventionsAttributes( .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.MESSAGING_KAFKA_DESTINATION_PARTITION); + .isEqualTo(SemanticConventionsConstants.MESSAGING_DESTINATION_PARTITION_ID); }) .satisfiesOnlyOnce( attribute -> { @@ -199,7 +199,7 @@ protected void assertSemanticConventionsAttributes( .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES); + .isEqualTo(SemanticConventionsConstants.MESSAGING_MESSAGE_BODY_SIZE); }) .satisfiesOnlyOnce( attribute -> { diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/kafka/producers/KafkaProducersTest.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/kafka/producers/KafkaProducersTest.java index 26e248a296..4fcc33e968 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/kafka/producers/KafkaProducersTest.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/kafka/producers/KafkaProducersTest.java @@ -214,7 +214,7 @@ protected void assertSemanticConventionsAttributes( .satisfiesOnlyOnce( attribute -> { assertThat(attribute.getKey()) - .isEqualTo(SemanticConventionsConstants.MESSAGING_KAFKA_DESTINATION_PARTITION); + .isEqualTo(SemanticConventionsConstants.MESSAGING_DESTINATION_PARTITION_ID); }) .satisfiesOnlyOnce( attribute -> { diff --git a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/utils/SemanticConventionsConstants.java b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/utils/SemanticConventionsConstants.java index 51077ea6a1..a2421a8a3a 100644 --- a/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/utils/SemanticConventionsConstants.java +++ b/appsignals-tests/contract-tests/src/test/java/software/amazon/opentelemetry/appsignals/test/utils/SemanticConventionsConstants.java @@ -21,23 +21,22 @@ public class SemanticConventionsConstants { // Semantic Conventions Attribute names - public static final String NET_PEER_NAME = "net.peer.name"; - public static final String NET_PEER_PORT = "net.peer.port"; - public static final String NET_PROTOCOL_NAME = "net.protocol.name"; - public static final String NET_PROTOCOL_VERSION = "net.protocol.version"; - public static final String NET_HOST_NAME = "net.host.name"; - public static final String NET_HOST_PORT = "net.host.port"; - public static final String NET_SOCK_HOST_ADDR = "net.sock.host.addr"; - public static final String NET_SOCK_HOST_PORT = "net.sock.host.port"; - public static final String NET_SOCK_PEER_ADDR = "net.sock.peer.addr"; - public static final String NET_SOCK_PEER_PORT = "net.sock.peer.port"; + public static final String SERVER_ADDRESS = "server.address"; + public static final String SERVER_PORT = "server.port"; + public static final String NETWORK_PROTOCOL_NAME = "network.protocol.name"; + public static final String NETWORK_PROTOCOL_VERSION = "network.protocol.version"; + public static final String NETWORK_LOCAL_ADDRESS = "network.local.address"; + public static final String NETWORK_LOCAL_PORT = "network.local.port"; + public static final String NETWORK_PEER_ADDRESS = "network.peer.address"; + public static final String NETWORK_PEER_PORT = "network.peer.port"; public static final String NET_SOCK_PEER_NAME = "net.sock.peer.name"; - public static final String HTTP_STATUS_CODE = "http.status_code"; - public static final String HTTP_SCHEME = "http.scheme"; - public static final String HTTP_TARGET = "http.target"; - public static final String HTTP_RESPONSE_CONTENT_LENGTH = "http.response_content_length"; - public static final String HTTP_URL = "http.url"; - public static final String HTTP_METHOD = "http.method"; + public static final String HTTP_RESPONSE_STATUS_CODE = "http.response.status_code"; + public static final String URL_SCHEME = "url.scheme"; + public static final String URL_PATH = "url.path"; + public static final String HTTP_RESPONSE_HEADER_CONTENT_LENGTH = + "http.response.header.content-length"; + public static final String URL_FULL = "url.full"; + public static final String HTTP_REQUEST_METHOD = "http.request.method"; public static final String HTTP_ROUTE = "http.route"; public static final String PEER_SERVICE = "peer.service"; @@ -78,13 +77,12 @@ public class SemanticConventionsConstants { // kafka public static final String MESSAGING_CLIENT_ID = "messaging.client_id"; public static final String MESSAGING_DESTINATION_NAME = "messaging.destination.name"; - public static final String MESSAGING_KAFKA_DESTINATION_PARTITION = - "messaging.kafka.destination.partition"; + public static final String MESSAGING_DESTINATION_PARTITION_ID = + "messaging.destination.partition.id"; public static final String MESSAGING_KAFKA_MESSAGE_OFFSET = "messaging.kafka.message.offset"; public static final String MESSAGING_SYSTEM = "messaging.system"; public static final String MESSAGING_KAFKA_CONSUMER_GROUP = "messaging.kafka.consumer.group"; - public static final String MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES = - "messaging.message.payload_size_bytes"; + public static final String MESSAGING_MESSAGE_BODY_SIZE = "messaging.message.body.size"; public static final String MESSAGING_OPERATION = "messaging.operation"; // GRPC specific semantic attributes diff --git a/appsignals-tests/images/aws-sdk/aws-sdk-v1/build.gradle.kts b/appsignals-tests/images/aws-sdk/aws-sdk-v1/build.gradle.kts index 4aa5ea57a0..c6a28a04f2 100644 --- a/appsignals-tests/images/aws-sdk/aws-sdk-v1/build.gradle.kts +++ b/appsignals-tests/images/aws-sdk/aws-sdk-v1/build.gradle.kts @@ -57,7 +57,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-aws-sdk-v1", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/aws-sdk/aws-sdk-v2/build.gradle.kts b/appsignals-tests/images/aws-sdk/aws-sdk-v2/build.gradle.kts index ee5e4b9105..5407b94eed 100644 --- a/appsignals-tests/images/aws-sdk/aws-sdk-v2/build.gradle.kts +++ b/appsignals-tests/images/aws-sdk/aws-sdk-v2/build.gradle.kts @@ -57,7 +57,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-aws-sdk-v2", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/grpc/grpc-client/build.gradle.kts b/appsignals-tests/images/grpc/grpc-client/build.gradle.kts index c113cb447c..a3daa595bd 100644 --- a/appsignals-tests/images/grpc/grpc-client/build.gradle.kts +++ b/appsignals-tests/images/grpc/grpc-client/build.gradle.kts @@ -41,7 +41,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "grpc-client", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/grpc/grpc-server/build.gradle.kts b/appsignals-tests/images/grpc/grpc-server/build.gradle.kts index a7e0728029..ea34b3a750 100644 --- a/appsignals-tests/images/grpc/grpc-server/build.gradle.kts +++ b/appsignals-tests/images/grpc/grpc-server/build.gradle.kts @@ -46,7 +46,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "grpc-server", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/http-clients/apache-http-client/build.gradle.kts b/appsignals-tests/images/http-clients/apache-http-client/build.gradle.kts index 5ba716f7c1..323ee1505c 100644 --- a/appsignals-tests/images/http-clients/apache-http-client/build.gradle.kts +++ b/appsignals-tests/images/http-clients/apache-http-client/build.gradle.kts @@ -43,7 +43,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-apache-http-client-app", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/http-clients/native-http-client/build.gradle.kts b/appsignals-tests/images/http-clients/native-http-client/build.gradle.kts index 2827da3637..13526bac71 100644 --- a/appsignals-tests/images/http-clients/native-http-client/build.gradle.kts +++ b/appsignals-tests/images/http-clients/native-http-client/build.gradle.kts @@ -42,7 +42,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-native-http-client-app", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/http-clients/netty-http-client/build.gradle.kts b/appsignals-tests/images/http-clients/netty-http-client/build.gradle.kts index ac481d4769..4c8305493d 100644 --- a/appsignals-tests/images/http-clients/netty-http-client/build.gradle.kts +++ b/appsignals-tests/images/http-clients/netty-http-client/build.gradle.kts @@ -43,7 +43,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-netty-http-client-app", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/http-clients/spring-mvc-client/build.gradle.kts b/appsignals-tests/images/http-clients/spring-mvc-client/build.gradle.kts index 4235fa0d54..b28bfce1c3 100644 --- a/appsignals-tests/images/http-clients/spring-mvc-client/build.gradle.kts +++ b/appsignals-tests/images/http-clients/spring-mvc-client/build.gradle.kts @@ -39,7 +39,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-spring-mvc-client-app", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/http-servers/netty-server/build.gradle.kts b/appsignals-tests/images/http-servers/netty-server/build.gradle.kts index 307ab89146..465329fa6f 100644 --- a/appsignals-tests/images/http-servers/netty-server/build.gradle.kts +++ b/appsignals-tests/images/http-servers/netty-server/build.gradle.kts @@ -42,7 +42,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-http-server-netty-server", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/http-servers/spring-mvc/build.gradle.kts b/appsignals-tests/images/http-servers/spring-mvc/build.gradle.kts index 5ed341d6f6..513624682d 100644 --- a/appsignals-tests/images/http-servers/spring-mvc/build.gradle.kts +++ b/appsignals-tests/images/http-servers/spring-mvc/build.gradle.kts @@ -28,7 +28,7 @@ java { dependencies { // Spring-boot-starter uses Spring-webmvc 6 - implementation("org.springframework.boot:spring-boot-starter-web:3.1.1") + implementation("org.springframework.boot:spring-boot-starter-web:3.4.0") implementation("io.opentelemetry:opentelemetry-api") } @@ -41,7 +41,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-http-server-spring-mvc", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/http-servers/tomcat/build.gradle.kts b/appsignals-tests/images/http-servers/tomcat/build.gradle.kts index 1ff2464e5b..a9456b57ce 100644 --- a/appsignals-tests/images/http-servers/tomcat/build.gradle.kts +++ b/appsignals-tests/images/http-servers/tomcat/build.gradle.kts @@ -44,7 +44,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-http-server-tomcat", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/jdbc/build.gradle.kts b/appsignals-tests/images/jdbc/build.gradle.kts index 073f6d4c40..2a95236c1f 100644 --- a/appsignals-tests/images/jdbc/build.gradle.kts +++ b/appsignals-tests/images/jdbc/build.gradle.kts @@ -45,7 +45,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-jdbc-app", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java b/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java index 81b1ff32ec..4f1cb17139 100644 --- a/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java +++ b/appsignals-tests/images/jdbc/src/main/java/software/amazon/opentelemetry/AppController.java @@ -46,7 +46,7 @@ public void prepareDB() { logger.info("Application Ready"); } - @GetMapping("/success/CREATE DATABASE") + @GetMapping("/success/CREATE database") @ResponseBody public ResponseEntity successCreateDatabase() { jdbcTemplate.execute("create database testdb2"); diff --git a/appsignals-tests/images/kafka/kafka-consumers/build.gradle.kts b/appsignals-tests/images/kafka/kafka-consumers/build.gradle.kts index 91ef8a7528..3b0a88eee4 100644 --- a/appsignals-tests/images/kafka/kafka-consumers/build.gradle.kts +++ b/appsignals-tests/images/kafka/kafka-consumers/build.gradle.kts @@ -47,7 +47,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-kafka-kafka-consumers", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/kafka/kafka-producers/build.gradle.kts b/appsignals-tests/images/kafka/kafka-producers/build.gradle.kts index a7e0b98f08..57154c981b 100644 --- a/appsignals-tests/images/kafka/kafka-producers/build.gradle.kts +++ b/appsignals-tests/images/kafka/kafka-producers/build.gradle.kts @@ -47,7 +47,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-tests-kafka-kafka-producers", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/appsignals-tests/images/mock-collector/build.gradle.kts b/appsignals-tests/images/mock-collector/build.gradle.kts index 16c1715b81..c0617de3d4 100644 --- a/appsignals-tests/images/mock-collector/build.gradle.kts +++ b/appsignals-tests/images/mock-collector/build.gradle.kts @@ -42,7 +42,7 @@ tasks { } jib { configureImages( - "public.ecr.aws/docker/library/amazoncorretto:21-alpine", + "public.ecr.aws/docker/library/amazoncorretto:23-alpine", "aws-appsignals-mock-collector", localDocker = rootProject.property("localDocker")!! == "true", multiPlatform = false, diff --git a/awsagentprovider/build.gradle.kts b/awsagentprovider/build.gradle.kts index 44488d3cfa..7e9211052e 100644 --- a/awsagentprovider/build.gradle.kts +++ b/awsagentprovider/build.gradle.kts @@ -13,9 +13,11 @@ * permissions and limitations under the License. */ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + plugins { java - id("com.github.johnrengelman.shadow") + id("com.gradleup.shadow") } base { @@ -56,7 +58,7 @@ dependencies { } tasks { - shadowJar { + val shadowJar by existing(ShadowJar::class) { archiveClassifier.set("") } } diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java index c1ffc13884..b3d04a7a8c 100644 --- a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java +++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java @@ -80,6 +80,9 @@ public class AwsApplicationSignalsCustomizerProvider "otel.aws.app.signals.enabled"; private static final String APPLICATION_SIGNALS_ENABLED_CONFIG = "otel.aws.application.signals.enabled"; + + private static final String OTEL_RESOURCE_PROVIDERS_AWS_ENABLED = + "otel.resource.providers.aws.enabled"; private static final String APPLICATION_SIGNALS_RUNTIME_ENABLED_CONFIG = "otel.aws.application.signals.runtime.enabled"; private static final String DEPRECATED_SMP_EXPORTER_ENDPOINT_CONFIG = @@ -132,19 +135,23 @@ private boolean isApplicationSignalsRuntimeEnabled(ConfigProperties configProps) } private Map customizeProperties(ConfigProperties configProps) { - if (isApplicationSignalsRuntimeEnabled(configProps)) { - List list = configProps.getList(OTEL_JMX_TARGET_SYSTEM_CONFIG); - if (list.contains("jvm")) { - logger.log(Level.INFO, "Found jmx in {0}", OTEL_JMX_TARGET_SYSTEM_CONFIG); - return Collections.emptyMap(); - } else { - logger.log(Level.INFO, "Configure jmx in {0}", OTEL_JMX_TARGET_SYSTEM_CONFIG); - List jmxTargets = new ArrayList<>(list); - jmxTargets.add("jvm"); - Map propsOverride = new HashMap<>(1); - propsOverride.put(OTEL_JMX_TARGET_SYSTEM_CONFIG, String.join(",", jmxTargets)); - return propsOverride; + if (isApplicationSignalsEnabled(configProps)) { + Map propsOverride = new HashMap<>(); + // Enable AWS Resource Providers + propsOverride.put(OTEL_RESOURCE_PROVIDERS_AWS_ENABLED, "true"); + + if (isApplicationSignalsRuntimeEnabled(configProps)) { + List list = configProps.getList(OTEL_JMX_TARGET_SYSTEM_CONFIG); + if (list.contains("jvm")) { + logger.log(Level.INFO, "Found jmx in {0}", OTEL_JMX_TARGET_SYSTEM_CONFIG); + } else { + logger.log(Level.INFO, "Configure jmx in {0}", OTEL_JMX_TARGET_SYSTEM_CONFIG); + List jmxTargets = new ArrayList<>(list); + jmxTargets.add("jvm"); + propsOverride.put(OTEL_JMX_TARGET_SYSTEM_CONFIG, String.join(",", jmxTargets)); + } } + return propsOverride; } return Collections.emptyMap(); } diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributeGenerator.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributeGenerator.java index 3b27816cc0..564d0e890d 100644 --- a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributeGenerator.java +++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributeGenerator.java @@ -86,8 +86,8 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.data.EventData; +import io.opentelemetry.sdk.trace.data.ExceptionEventData; import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.internal.data.ExceptionEventData; import io.opentelemetry.semconv.ResourceAttributes; import io.opentelemetry.semconv.SemanticAttributes; import java.lang.reflect.Method; @@ -655,7 +655,13 @@ private static void setSpanKindForDependency(SpanData span, AttributesBuilder bu * allow for desired metric creation. */ private static void setHttpStatus(SpanData span, AttributesBuilder builder) { + if (isKeyPresent(span, HTTP_RESPONSE_STATUS_CODE)) { + return; + } + if (isKeyPresent(span, HTTP_STATUS_CODE)) { + Long statusCode = span.getAttributes().get(HTTP_STATUS_CODE); + builder.put(HTTP_RESPONSE_STATUS_CODE, statusCode); return; } @@ -667,7 +673,7 @@ private static void setHttpStatus(SpanData span, AttributesBuilder builder) { Long statusCode = getAwsStatusCode(span); if (statusCode != null) { - builder.put(HTTP_STATUS_CODE, statusCode); + builder.put(HTTP_RESPONSE_STATUS_CODE, statusCode); } } diff --git a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanMetricsProcessor.java b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanMetricsProcessor.java index af987908e1..b8479dbedd 100644 --- a/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanMetricsProcessor.java +++ b/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanMetricsProcessor.java @@ -140,7 +140,7 @@ private void recordErrorOrFault(SpanData spanData, Attributes attributes) { StatusCode statusCode = spanData.getStatus().getStatusCode(); if (httpStatusCode == null) { - httpStatusCode = attributes.get(HTTP_STATUS_CODE); + httpStatusCode = attributes.get(HTTP_RESPONSE_STATUS_CODE); } if (httpStatusCode == null diff --git a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributeGeneratorTest.java b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributeGeneratorTest.java index 8309ac31f1..bceb8e3111 100644 --- a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributeGeneratorTest.java +++ b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributeGeneratorTest.java @@ -54,8 +54,8 @@ import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.data.EventData; +import io.opentelemetry.sdk.trace.data.ExceptionEventData; import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.internal.data.ExceptionEventData; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -393,7 +393,6 @@ public void testServerSpanWithSpanNameAsHttpMethod() { public void testServerSpanWithSpanNameWithHttpTarget() { updateResourceWithServiceName(); when(spanDataMock.getName()).thenReturn("POST"); - Attributes expectedAttributes = Attributes.of( AWS_SPAN_KIND, @@ -402,12 +401,14 @@ 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"); @@ -1045,7 +1046,7 @@ public void testHttpStatusAttributeNotAwsSdk() { @Test public void testHttpStatusAttributeStatusAlreadyPresent() { when(instrumentationScopeInfoMock.getName()).thenReturn("aws-sdk"); - mockAttribute(HTTP_STATUS_CODE, 200L); + mockAttribute(HTTP_RESPONSE_STATUS_CODE, 200L); validateHttpStatusWithThrowable(new ThrowableWithMethodGetStatusCode(500), null); } @@ -1202,9 +1203,9 @@ private void validateHttpStatusForNonLocalRootWithThrowableForClient( actualAttributes = attributeMap.get(SERVICE_METRIC); } } - assertThat(actualAttributes.get(HTTP_STATUS_CODE)).isEqualTo(expectedStatusCode); + assertThat(actualAttributes.get(HTTP_RESPONSE_STATUS_CODE)).isEqualTo(expectedStatusCode); if (expectedStatusCode == null) { - assertThat(actualAttributes.asMap().containsKey(HTTP_STATUS_CODE)).isFalse(); + assertThat(actualAttributes.asMap().containsKey(HTTP_RESPONSE_STATUS_CODE)).isFalse(); } } diff --git a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanMetricsProcessorTest.java b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanMetricsProcessorTest.java index 214c43ec95..16fc889cec 100644 --- a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanMetricsProcessorTest.java +++ b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanMetricsProcessorTest.java @@ -15,7 +15,7 @@ package software.amazon.opentelemetry.javaagent.providers; -import static io.opentelemetry.semconv.SemanticAttributes.HTTP_STATUS_CODE; +import static io.opentelemetry.semconv.SemanticAttributes.HTTP_RESPONSE_STATUS_CODE; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -41,9 +41,9 @@ import io.opentelemetry.sdk.trace.ReadWriteSpan; import io.opentelemetry.sdk.trace.ReadableSpan; import io.opentelemetry.sdk.trace.data.EventData; +import io.opentelemetry.sdk.trace.data.ExceptionEventData; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.data.StatusData; -import io.opentelemetry.sdk.trace.internal.data.ExceptionEventData; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -141,7 +141,7 @@ public void testOnEndMetricsGenerationWithoutSpanAttributes() { @Test public void testOnEndMetricsGenerationWithoutMetricAttributes() { - Attributes spanAttributes = Attributes.of(HTTP_STATUS_CODE, 500L); + Attributes spanAttributes = Attributes.of(HTTP_RESPONSE_STATUS_CODE, 500L); ReadableSpan readableSpanMock = buildReadableSpanMock(spanAttributes); Map metricAttributesMap = buildMetricAttributes(CONTAINS_NO_ATTRIBUTES, readableSpanMock.toSpanData()); @@ -273,7 +273,7 @@ public void testsOnEndMetricsGenerationProducerSpan() { @Test public void testOnEndMetricsGenerationWithoutEndRequired() { - Attributes spanAttributes = Attributes.of(HTTP_STATUS_CODE, 500L); + Attributes spanAttributes = Attributes.of(HTTP_RESPONSE_STATUS_CODE, 500L); ReadableSpan readableSpanMock = buildReadableSpanMock(spanAttributes); Map metricAttributesMap = buildMetricAttributes(CONTAINS_ATTRIBUTES, readableSpanMock.toSpanData()); @@ -296,7 +296,7 @@ public void testOnEndMetricsGenerationWithoutEndRequired() { @Test public void testOnEndMetricsGenerationWithLatency() { - Attributes spanAttributes = Attributes.of(HTTP_STATUS_CODE, 200L); + Attributes spanAttributes = Attributes.of(HTTP_RESPONSE_STATUS_CODE, 200L); ReadableSpan readableSpanMock = buildReadableSpanMock(spanAttributes); Map metricAttributesMap = buildMetricAttributes(CONTAINS_ATTRIBUTES, readableSpanMock.toSpanData()); @@ -440,7 +440,7 @@ private static ReadableSpan buildReadableSpanMock( private static ReadableSpan buildReadableSpanWithThrowableMock(Throwable throwable) { // config http status code as null - Attributes spanAttributes = Attributes.of(HTTP_STATUS_CODE, null); + Attributes spanAttributes = Attributes.of(HTTP_RESPONSE_STATUS_CODE, null); ReadableSpan readableSpanMock = mock(ReadableSpan.class); SpanData mockSpanData = mock(SpanData.class); InstrumentationScopeInfo awsSdkScopeInfo = @@ -476,7 +476,7 @@ private void configureMocksForOnEnd( private void validateMetricsGeneratedForHttpStatusCode( Long httpStatusCode, ExpectedStatusMetric expectedStatusMetric) { - Attributes spanAttributes = Attributes.of(HTTP_STATUS_CODE, httpStatusCode); + Attributes spanAttributes = Attributes.of(HTTP_RESPONSE_STATUS_CODE, httpStatusCode); ReadableSpan readableSpanMock = buildReadableSpanMock(spanAttributes, SpanKind.PRODUCER, null, StatusData.unset()); Map metricAttributesMap = @@ -501,14 +501,14 @@ private void validateMetricsGeneratedForAttributeStatusCode( Attributes.of( AttributeKey.stringKey("new service key"), "new service value", - HTTP_STATUS_CODE, + HTTP_RESPONSE_STATUS_CODE, awsStatusCode)); metricAttributesMap.put( DEPENDENCY_METRIC, Attributes.of( AttributeKey.stringKey("new dependency key"), "new dependency value", - HTTP_STATUS_CODE, + HTTP_RESPONSE_STATUS_CODE, awsStatusCode)); } configureMocksForOnEnd(readableSpanMock, metricAttributesMap); @@ -518,7 +518,7 @@ private void validateMetricsGeneratedForAttributeStatusCode( private void validateMetricsGeneratedForStatusDataError( Long httpStatusCode, ExpectedStatusMetric expectedStatusMetric) { - Attributes spanAttributes = Attributes.of(HTTP_STATUS_CODE, httpStatusCode); + Attributes spanAttributes = Attributes.of(HTTP_RESPONSE_STATUS_CODE, httpStatusCode); ReadableSpan readableSpanMock = buildReadableSpanMock(spanAttributes, SpanKind.PRODUCER, null, StatusData.error()); Map metricAttributesMap = @@ -531,7 +531,7 @@ private void validateMetricsGeneratedForStatusDataError( private void validateMetricsGeneratedForStatusDataOk( Long httpStatusCode, ExpectedStatusMetric expectedStatusMetric) { - Attributes spanAttributes = Attributes.of(HTTP_STATUS_CODE, httpStatusCode); + Attributes spanAttributes = Attributes.of(HTTP_RESPONSE_STATUS_CODE, httpStatusCode); ReadableSpan readableSpanMock = buildReadableSpanMock(spanAttributes, SpanKind.PRODUCER, null, StatusData.ok()); diff --git a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtilTest.java b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtilTest.java index 90f53ed513..0ed7b2d326 100644 --- a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtilTest.java +++ b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanProcessingUtilTest.java @@ -73,7 +73,7 @@ public void testGetIngressOperationHttpMethodNameAndNoFallback() { String invalidName = "GET"; when(spanDataMock.getName()).thenReturn(invalidName); when(spanDataMock.getKind()).thenReturn(SpanKind.SERVER); - when(attributesMock.get(HTTP_METHOD)).thenReturn(invalidName); + when(attributesMock.get(HTTP_REQUEST_METHOD)).thenReturn(invalidName); String actualOperation = AwsSpanProcessingUtil.getIngressOperation(spanDataMock); assertThat(actualOperation).isEqualTo(UNKNOWN_OPERATION); } @@ -102,7 +102,7 @@ public void testGetIngressOperationInvalidNameAndValidTarget() { String validTarget = "/"; when(spanDataMock.getName()).thenReturn(invalidName); when(spanDataMock.getKind()).thenReturn(SpanKind.SERVER); - when(attributesMock.get(HTTP_TARGET)).thenReturn(validTarget); + when(attributesMock.get(URL_PATH)).thenReturn(validTarget); String actualOperation = AwsSpanProcessingUtil.getIngressOperation(spanDataMock); assertThat(actualOperation).isEqualTo(validTarget); } @@ -114,8 +114,8 @@ public void testGetIngressOperationInvalidNameAndValidTargetAndMethod() { String validMethod = "GET"; when(spanDataMock.getName()).thenReturn(invalidName); when(spanDataMock.getKind()).thenReturn(SpanKind.SERVER); - when(attributesMock.get(HTTP_TARGET)).thenReturn(validTarget); - when(attributesMock.get(HTTP_METHOD)).thenReturn(validMethod); + when(attributesMock.get(URL_PATH)).thenReturn(validTarget); + when(attributesMock.get(HTTP_REQUEST_METHOD)).thenReturn(validMethod); String actualOperation = AwsSpanProcessingUtil.getIngressOperation(spanDataMock); assertThat(actualOperation).isEqualTo(validMethod + " " + validTarget); } @@ -183,13 +183,13 @@ public void testExtractAPIPathValidPath() { @Test public void testIsKeyPresentKeyPresent() { - when(attributesMock.get(HTTP_TARGET)).thenReturn("target"); - assertThat(AwsSpanProcessingUtil.isKeyPresent(spanDataMock, HTTP_TARGET)).isTrue(); + when(attributesMock.get(URL_PATH)).thenReturn("target"); + assertThat(AwsSpanProcessingUtil.isKeyPresent(spanDataMock, URL_PATH)).isTrue(); } @Test public void testIsKeyPresentKeyAbsent() { - assertThat(AwsSpanProcessingUtil.isKeyPresent(spanDataMock, HTTP_TARGET)).isFalse(); + assertThat(AwsSpanProcessingUtil.isKeyPresent(spanDataMock, URL_PATH)).isFalse(); } @Test diff --git a/build.gradle.kts b/build.gradle.kts index ed2ff0c9d3..973d7d73ba 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,13 +20,13 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { java - + kotlin("jvm") version "2.1.0-RC2" id("com.diffplug.spotless") id("com.github.jk1.dependency-license-report") id("io.github.gradle-nexus.publish-plugin") id("nebula.release") - id("com.github.johnrengelman.shadow") apply false + id("com.gradleup.shadow") apply false } release { @@ -68,7 +68,7 @@ allprojects { spotless { kotlinGradle { - ktlint("0.48.0").userData(mapOf("indent_size" to "2", "continuation_indent_size" to "2")) + ktlint("1.4.0").editorConfigOverride(mapOf("indent_size" to "2", "continuation_indent_size" to "2")) // Doesn't support pluginManagement block targetExclude("settings.gradle.kts") @@ -155,7 +155,7 @@ allprojects { } } - plugins.withId("com.github.johnrengelman.shadow") { + plugins.withId("com.gradleup.shadow") { tasks { withType().configureEach { exclude("**/module-info.class") diff --git a/dependencyManagement/build.gradle.kts b/dependencyManagement/build.gradle.kts index 6394ab93c8..92bdf381e1 100644 --- a/dependencyManagement/build.gradle.kts +++ b/dependencyManagement/build.gradle.kts @@ -24,16 +24,16 @@ plugins { data class DependencySet(val group: String, val version: String, val modules: List) -val TEST_SNAPSHOTS = rootProject.findProperty("testUpstreamSnapshots") == "true" +val testSnapshots = rootProject.findProperty("testUpstreamSnapshots") == "true" // This is the version of the upstream instrumentation BOM -val otelVersion = "1.33.6-adot1" -val otelSnapshotVersion = "1.33.6" -val otelAlphaVersion = if (!TEST_SNAPSHOTS) "$otelVersion-alpha" else "$otelSnapshotVersion-alpha-SNAPSHOT" -val otelJavaAgentVersion = if (!TEST_SNAPSHOTS) otelVersion else "$otelSnapshotVersion-SNAPSHOT" +val otelVersion = "2.10.0-adot1" +val otelSnapshotVersion = "2.11.0" +val otelAlphaVersion = if (!testSnapshots) "$otelVersion-alpha" else "$otelSnapshotVersion-alpha-SNAPSHOT" +val otelJavaAgentVersion = if (!testSnapshots) otelVersion else "$otelSnapshotVersion-SNAPSHOT" // All versions below are only used in testing and do not affect the released artifact. -val DEPENDENCY_BOMS = listOf( +val dependencyBoms = listOf( "com.amazonaws:aws-java-sdk-bom:1.12.599", "com.fasterxml.jackson:jackson-bom:2.16.0", "com.google.guava:guava-bom:33.0.0-jre", @@ -48,7 +48,7 @@ val DEPENDENCY_BOMS = listOf( "software.amazon.awssdk:bom:2.21.33", ) -val DEPENDENCY_SETS = listOf( +val dependencySets = listOf( DependencySet( "org.assertj", "3.24.2", @@ -69,7 +69,7 @@ val DEPENDENCY_SETS = listOf( ), ) -val DEPENDENCIES = listOf( +val dependencyLists = listOf( "commons-logging:commons-logging:1.2", "com.sparkjava:spark-core:2.9.4", "com.squareup.okhttp3:okhttp:4.12.0", @@ -86,17 +86,17 @@ javaPlatform { } dependencies { - for (bom in DEPENDENCY_BOMS) { + for (bom in dependencyBoms) { api(platform(bom)) } constraints { - for (set in DEPENDENCY_SETS) { + for (set in dependencySets) { for (module in set.modules) { api("${set.group}:$module:${set.version}") } } - for (dependency in DEPENDENCIES) { + for (dependency in dependencyLists) { api(dependency) } } @@ -105,7 +105,7 @@ dependencies { rootProject.allprojects { plugins.withId("com.github.jk1.dependency-license-report") { configure { - val bomExcludes = DEPENDENCY_BOMS.stream() + val bomExcludes = dependencyBoms.stream() .map { it.substring(0, it.lastIndexOf(':')) } .toArray { length -> arrayOfNulls(length) } excludes = bomExcludes diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138c9..9355b41557 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/instrumentation/jmx-metrics/build.gradle.kts b/instrumentation/jmx-metrics/build.gradle.kts index 6456230040..c2124f2716 100644 --- a/instrumentation/jmx-metrics/build.gradle.kts +++ b/instrumentation/jmx-metrics/build.gradle.kts @@ -15,7 +15,7 @@ plugins { java - id("com.github.johnrengelman.shadow") + id("com.gradleup.shadow") } base.archivesBaseName = "aws-instrumentation-jmx-metrics" diff --git a/instrumentation/log4j-2.13.2/build.gradle.kts b/instrumentation/log4j-2.13.2/build.gradle.kts index a6c273ac66..529f9953c3 100644 --- a/instrumentation/log4j-2.13.2/build.gradle.kts +++ b/instrumentation/log4j-2.13.2/build.gradle.kts @@ -15,7 +15,7 @@ plugins { java - id("com.github.johnrengelman.shadow") + id("com.gradleup.shadow") } base.archivesBaseName = "aws-instrumentation-log4j-2.13.2" diff --git a/instrumentation/logback-1.0/build.gradle.kts b/instrumentation/logback-1.0/build.gradle.kts index dc0d0f1f82..398cf54539 100644 --- a/instrumentation/logback-1.0/build.gradle.kts +++ b/instrumentation/logback-1.0/build.gradle.kts @@ -15,7 +15,7 @@ plugins { java - id("com.github.johnrengelman.shadow") + id("com.gradleup.shadow") } base.archivesBaseName = "aws-instrumentation-logback-1.0" diff --git a/lambda-layer/settings.gradle.kts b/lambda-layer/settings.gradle.kts index b37d925e37..97d2e853eb 100644 --- a/lambda-layer/settings.gradle.kts +++ b/lambda-layer/settings.gradle.kts @@ -2,7 +2,7 @@ pluginManagement { plugins { id("com.diffplug.spotless") version "6.13.0" id("com.github.ben-manes.versions") version "0.50.0" - id("com.github.johnrengelman.shadow") version "8.1.1" + id("com.gradleup.shadow") version "8.3.5" } } diff --git a/otelagent/build.gradle.kts b/otelagent/build.gradle.kts index 2027a56bbf..db76dc6c7f 100644 --- a/otelagent/build.gradle.kts +++ b/otelagent/build.gradle.kts @@ -20,7 +20,7 @@ plugins { `maven-publish` id("com.google.cloud.tools.jib") - id("com.github.johnrengelman.shadow") + id("com.gradleup.shadow") id("org.owasp.dependencycheck") } @@ -40,9 +40,7 @@ val javaagentLibs by configurations.creating { exclude("io.opentelemetry", "opentelemetry-api") exclude("io.opentelemetry", "opentelemetry-sdk") exclude("io.opentelemetry", "opentelemetry-sdk-common") - // Once io.opentelemetry.contrib:opentelemetry-aws-resources starts using - // the new semantic convention packages we will need to exclude it here. - // io.opentelemetry.semconv:opentelemetry-semconv + exclude("io.opentelemetry.semconv", "opentelemetry-semconv") } val shadowClasspath by configurations.creating { @@ -74,7 +72,7 @@ tasks { archiveFileName.set("javaagentLibs-relocated.jar") } - shadowJar { + val shadowJar by existing(ShadowJar::class) { dependsOn(relocateJavaagentLibs) archiveClassifier.set("") @@ -112,7 +110,7 @@ tasks { } } -val shadowJar = tasks.named("shadowJar") +val shadowJar by tasks.existing(ShadowJar::class) tasks { named("jar") { enabled = false @@ -137,7 +135,7 @@ tasks { jib { configureImages( "gcr.io/distroless/java17-debian11:debug", - "public.ecr.aws/aws-otel-test/aws-opentelemetry-java-base:alpha", + "public.ecr.aws/aws-otel-test/aws-opentelemetry-java-base:alpha-v2", localDocker = false, multiPlatform = !rootProject.property("localDocker")!!.equals("true"), ) diff --git a/sample-apps/spark-awssdkv1/build.gradle.kts b/sample-apps/spark-awssdkv1/build.gradle.kts index 5139528a60..ce69dcb18d 100644 --- a/sample-apps/spark-awssdkv1/build.gradle.kts +++ b/sample-apps/spark-awssdkv1/build.gradle.kts @@ -22,8 +22,8 @@ application { jib { configureImages( - "public.ecr.aws/aws-otel-test/aws-opentelemetry-java-base:alpha", - "public.ecr.aws/aws-otel-test/aws-otel-java-spark-awssdkv1", + "public.ecr.aws/aws-otel-test/aws-opentelemetry-java-base:alpha-v2", + "public.ecr.aws/aws-otel-test/aws-otel-java-spark-awssdkv1:v2", localDocker = rootProject.property("localDocker")!!.equals("true"), multiPlatform = !rootProject.property("localDocker")!!.equals("true"), tags = setOf("latest", "${System.getenv("COMMIT_HASH")}"), diff --git a/sample-apps/spark/build.gradle.kts b/sample-apps/spark/build.gradle.kts index 47ee944a4f..1dc88e3192 100644 --- a/sample-apps/spark/build.gradle.kts +++ b/sample-apps/spark/build.gradle.kts @@ -28,8 +28,8 @@ application { jib { configureImages( - "public.ecr.aws/aws-otel-test/aws-opentelemetry-java-base:alpha", - "public.ecr.aws/aws-otel-test/aws-otel-java-spark", + "public.ecr.aws/aws-otel-test/aws-opentelemetry-java-base:alpha-v2", + "public.ecr.aws/aws-otel-test/aws-otel-java-spark:v2", localDocker = rootProject.property("localDocker")!!.equals("true"), multiPlatform = !rootProject.property("localDocker")!!.equals("true"), tags = setOf("latest", "${System.getenv("COMMIT_HASH")}"), diff --git a/sample-apps/springboot/build.gradle.kts b/sample-apps/springboot/build.gradle.kts index d06f816ce2..2d4844fcc4 100644 --- a/sample-apps/springboot/build.gradle.kts +++ b/sample-apps/springboot/build.gradle.kts @@ -17,8 +17,8 @@ dependencies { jib { configureImages( - "public.ecr.aws/aws-otel-test/aws-opentelemetry-java-base:alpha", - "public.ecr.aws/aws-otel-test/aws-otel-java-springboot", + "public.ecr.aws/aws-otel-test/aws-opentelemetry-java-base:alpha-v2", + "public.ecr.aws/aws-otel-test/aws-otel-java-springboot:v2", rootProject.property("localDocker")!!.equals("true"), !rootProject.property("localDocker")!!.equals("true"), tags = setOf("latest", "${System.getenv("COMMIT_HASH")}"), diff --git a/scripts/docker/corretto-slim/Dockerfile b/scripts/docker/corretto-slim/Dockerfile index 5303d4d2c0..1d3de1cd63 100644 --- a/scripts/docker/corretto-slim/Dockerfile +++ b/scripts/docker/corretto-slim/Dockerfile @@ -1,4 +1,4 @@ -FROM public.ecr.aws/docker/library/amazoncorretto:21-alpine-jdk +FROM public.ecr.aws/docker/library/amazoncorretto:23-alpine-jdk # Copied from https://github.com/corretto/corretto-docker/blob/master/11/jre/alpine/Dockerfile RUN apk update && apk add binutils && jlink --endian little --release-info $JAVA_HOME/release \ diff --git a/settings.gradle.kts b/settings.gradle.kts index decf81d145..7edda895ac 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,11 +15,11 @@ pluginManagement { plugins { - id("com.diffplug.spotless") version "6.22.0" + id("com.diffplug.spotless") version "6.25.0" id("com.github.ben-manes.versions") version "0.50.0" id("com.github.jk1.dependency-license-report") version "2.5" - id("com.github.johnrengelman.shadow") version "8.1.1" - id("com.google.cloud.tools.jib") version "3.4.3" + id("com.gradleup.shadow") version "8.3.5" + id("com.google.cloud.tools.jib") version "3.4.4" id("io.github.gradle-nexus.publish-plugin") version "2.0.0" id("nebula.release") version "18.0.6" id("org.springframework.boot") version "2.7.17" diff --git a/smoke-tests/fakebackend/build.gradle.kts b/smoke-tests/fakebackend/build.gradle.kts index 7f1365027b..937b864f48 100644 --- a/smoke-tests/fakebackend/build.gradle.kts +++ b/smoke-tests/fakebackend/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { jib { to { - image = "public.ecr.aws/u0d6r4y4/aws-otel-java-test-fakebackend:alpha" + image = "public.ecr.aws/aws-otel-test/aws-otel-java-test-fakebackend:alpha-v2" } from { image = "gcr.io/distroless/java17-debian11:debug" diff --git a/smoke-tests/runner/src/test/java/io/awsobservability/instrumentation/smoketests/runner/SpringBootSmokeTest.java b/smoke-tests/runner/src/test/java/io/awsobservability/instrumentation/smoketests/runner/SpringBootSmokeTest.java index b4740eb8d3..f22b29cf03 100644 --- a/smoke-tests/runner/src/test/java/io/awsobservability/instrumentation/smoketests/runner/SpringBootSmokeTest.java +++ b/smoke-tests/runner/src/test/java/io/awsobservability/instrumentation/smoketests/runner/SpringBootSmokeTest.java @@ -98,7 +98,7 @@ public ExportTraceServiceRequest deserialize( @Container private static final GenericContainer backend = - new GenericContainer<>("public.ecr.aws/aws-otel-test/aws-otel-java-test-fakebackend:alpha") + new GenericContainer<>("public.ecr.aws/aws-otel-test/aws-otel-java-test-fakebackend:alpha-v2") .withExposedPorts(8080) .waitingFor(Wait.forHttp("/health").forPort(8080)) .withLogConsumer(new Slf4jLogConsumer(backendLogger)) @@ -107,8 +107,7 @@ public ExportTraceServiceRequest deserialize( @Container private static final GenericContainer application = - new GenericContainer<>( - "public.ecr.aws/aws-otel-test/aws-otel-java-smoketests-springboot:latest") + new GenericContainer<>("public.ecr.aws/aws-otel-test/aws-otel-java-smoketests-springboot:v2") .dependsOn(backend) .withExposedPorts(8080) .withNetwork(network) @@ -119,12 +118,13 @@ public ExportTraceServiceRequest deserialize( .withEnv("JAVA_TOOL_OPTIONS", "-javaagent:/opentelemetry-javaagent-all.jar") .withEnv("OTEL_BSP_MAX_EXPORT_BATCH", "1") .withEnv("OTEL_BSP_SCHEDULE_DELAY", "10") + .withEnv("OTEL_EXPORTER_OTLP_PROTOCOL", "grpc") + .withEnv("OTEL_INSTRUMENTATION_COMMON_EXPERIMENTAL_CONTROLLER_TELEMETRY_ENABLED", "true") .withEnv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://backend:8080"); @Container private static final GenericContainer applicationXraySampler = - new GenericContainer<>( - "public.ecr.aws/aws-otel-test/aws-otel-java-smoketests-springboot:latest") + new GenericContainer<>("public.ecr.aws/aws-otel-test/aws-otel-java-smoketests-springboot:v2") .dependsOn(backend) .withExposedPorts(8080) .withNetwork(network) @@ -137,6 +137,8 @@ public ExportTraceServiceRequest deserialize( .withEnv("OTEL_BSP_MAX_EXPORT_BATCH", "1") .withEnv("OTEL_BSP_SCHEDULE_DELAY", "10") .withEnv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://backend:8080") + .withEnv("OTEL_EXPORTER_OTLP_PROTOCOL", "grpc") + .withEnv("OTEL_INSTRUMENTATION_COMMON_EXPERIMENTAL_CONTROLLER_TELEMETRY_ENABLED", "true") .withEnv("OTEL_TRACES_SAMPLER", "xray"); private static final TypeReference> diff --git a/smoke-tests/spring-boot/build.gradle.kts b/smoke-tests/spring-boot/build.gradle.kts index d58e020b4b..05aa848a2d 100644 --- a/smoke-tests/spring-boot/build.gradle.kts +++ b/smoke-tests/spring-boot/build.gradle.kts @@ -47,8 +47,8 @@ dependencies { jib { configureImages( - "public.ecr.aws/aws-otel-test/aws-opentelemetry-java-base:alpha", - "public.ecr.aws/aws-otel-test/aws-otel-java-smoketests-springboot", + "public.ecr.aws/aws-otel-test/aws-opentelemetry-java-base:alpha-v2", + "public.ecr.aws/aws-otel-test/aws-otel-java-smoketests-springboot:v2", localDocker = rootProject.property("localDocker")!!.equals("true"), multiPlatform = false, )