From d9030c2dde03c0405fa382a198c3c6a28a10930a Mon Sep 17 00:00:00 2001 From: Min Xia Date: Wed, 19 Jun 2024 14:19:56 -0700 Subject: [PATCH 01/13] support bedrock and bedrock runtime resources --- .../aws-sdk-2.2/library/build.gradle.kts | 1 + .../v2_2/AwsExperimentalAttributes.java | 52 ++++++++ .../awssdk/v2_2/AwsSdkRequest.java | 6 + .../awssdk/v2_2/AwsSdkRequestType.java | 38 +++++- .../awssdk/v2_2/FieldMapper.java | 9 +- .../awssdk/v2_2/Serializer.java | 121 ++++++++++++++++++ 6 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 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/build.gradle.kts b/instrumentation/aws-sdk/aws-sdk-2.2/library/build.gradle.kts index 081d542e76ab..e121354f3a56 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 @@ -9,6 +9,7 @@ dependencies { library("software.amazon.awssdk:sqs:2.2.0") library("software.amazon.awssdk:sns:2.2.0") library("software.amazon.awssdk:aws-json-protocol:2.2.0") + implementation("org.json:json:20210307") compileOnly(project(":muzzle")) // For @NoMuzzle testImplementation(project(":instrumentation:aws-sdk:aws-sdk-2.2: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 new file mode 100644 index 000000000000..9e5a5834d580 --- /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,52 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.awssdk.v2_2; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; + +import io.opentelemetry.api.common.AttributeKey; + +final class AwsExperimentalAttributes { + static final AttributeKey AWS_BUCKET_NAME = stringKey("aws.bucket.name"); + static final AttributeKey AWS_QUEUE_URL = stringKey("aws.queue.url"); + 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_BEDROCK_GUARDRAIL_ID = + stringKey("aws.bedrock.guardrail_id"); + static final AttributeKey AWS_BEDROCK_AGENT_ID = stringKey("aws.bedrock.agent_id"); + static final AttributeKey AWS_BEDROCK_DATASOURCE_ID = + stringKey("aws.bedrock.datasource_id"); + static final AttributeKey AWS_BEDROCK_KNOWLEDGEBASE_ID = + stringKey("aws.bedrock.knowledgebase_id"); + static final AttributeKey GEN_AI_FINISH_REASON = + stringKey("gen_ai.response.finish_reason"); + static final AttributeKey GEN_AI_PROMPT_TOKENS = stringKey("gen_ai.usage.prompt_tokens"); + static final AttributeKey GEN_AI_COMPLETION_TOKENS = + stringKey("gen_ai.usage.completion_tokens"); + + // OTel GenAI/LLM group has defined gen_ai attributes but not yet add it in + // semantic-conventions-java package + // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-spans.md#genai-attributes + static final AttributeKey GEN_AI_MODEL = stringKey("gen_ai.request.model"); + static final AttributeKey GEN_AI_TEMPERATURE = stringKey("gen_ai.request.temperature"); + static final AttributeKey GEN_AI_TOP_P = stringKey("gen_ai.request.top_p"); + static final AttributeKey GEN_AI_MAX_TOKENS = stringKey("gen_ai.request.max_tokens"); + static final AttributeKey GEN_AI_SYSTEM = stringKey("gen_ai.system"); + + private AwsExperimentalAttributes() {} + + static boolean isGenAiAttribute(String attributeKey) { + return attributeKey.equals(GEN_AI_MODEL.getKey()) + || attributeKey.equals(GEN_AI_FINISH_REASON.getKey()) + || attributeKey.equals(GEN_AI_PROMPT_TOKENS.getKey()) + || attributeKey.equals(GEN_AI_COMPLETION_TOKENS.getKey()) + || attributeKey.equals(GEN_AI_TEMPERATURE.getKey()) + || attributeKey.equals(GEN_AI_TOP_P.getKey()) + || attributeKey.equals(GEN_AI_MAX_TOKENS.getKey()) + || attributeKey.equals(GEN_AI_SYSTEM.getKey()); + } +} 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 54253d0f7bcb..18ff560b802a 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,6 +5,9 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCK; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCKAGENT; +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.S3; @@ -32,6 +35,9 @@ enum AwsSdkRequest { S3Request(S3, "S3Request"), SqsRequest(SQS, "SqsRequest"), KinesisRequest(KINESIS, "KinesisRequest"), + BedrockRequest(BEDROCK, "BedrockRequest"), + BedrockAgentRequest(BEDROCKAGENT, "BedrockAgentRequest"), + BedrockRuntimeRequest(BEDROCKRUNTIME, "BedrockRuntimeRequest"), // 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 9062f2aa1738..238a6ab746af 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,47 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_BEDROCK_AGENT_ID; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_BEDROCK_DATASOURCE_ID; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_BEDROCK_GUARDRAIL_ID; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_BEDROCK_KNOWLEDGEBASE_ID; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_BUCKET_NAME; +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_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_COMPLETION_TOKENS; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_FINISH_REASON; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_MAX_TOKENS; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_MODEL; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_PROMPT_TOKENS; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_TEMPERATURE; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_TOP_P; import static io.opentelemetry.instrumentation.awssdk.v2_2.FieldMapping.request; +import static io.opentelemetry.instrumentation.awssdk.v2_2.FieldMapping.response; import java.util.Collections; 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")); + S3(request(AWS_BUCKET_NAME.getKey(), "Bucket")), + SQS(request(AWS_QUEUE_URL.getKey(), "QueueUrl"), request(AWS_QUEUE_NAME.getKey(), "QueueName")), + KINESIS(request(AWS_STREAM_NAME.getKey(), "StreamName")), + DYNAMODB(request(AWS_TABLE_NAME.getKey(), "TableName")), + BEDROCK(request(AWS_BEDROCK_GUARDRAIL_ID.getKey(), "guardrailIdentifier")), + BEDROCKAGENT( + request(AWS_BEDROCK_AGENT_ID.getKey(), "agentId"), + request(AWS_BEDROCK_DATASOURCE_ID.getKey(), "dataSourceId"), + request(AWS_BEDROCK_KNOWLEDGEBASE_ID.getKey(), "knowledgeBaseId")), + BEDROCKRUNTIME( + request(GEN_AI_MODEL.getKey(), "modelId"), + request(GEN_AI_TEMPERATURE.getKey(), "body"), + request(GEN_AI_TOP_P.getKey(), "body"), + request(GEN_AI_MAX_TOKENS.getKey(), "body"), + response(GEN_AI_FINISH_REASON.getKey(), "body"), + response(GEN_AI_PROMPT_TOKENS.getKey(), "body"), + response(GEN_AI_COMPLETION_TOKENS.getKey(), "body")); // 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/FieldMapper.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/FieldMapper.java index 569d0eb5ae18..93e3f9508049 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/FieldMapper.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/FieldMapper.java @@ -65,8 +65,15 @@ private void mapToAttributes( 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); + span.setAttribute("gen_ai.system", "AWS Bedrock"); + } 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/Serializer.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/Serializer.java index 979ecb08e87d..14e01024ca06 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/Serializer.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/Serializer.java @@ -12,6 +12,8 @@ import java.util.Optional; import java.util.stream.Collectors; import javax.annotation.Nullable; +import org.json.JSONObject; +import software.amazon.awssdk.core.SdkBytes; import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.http.ContentStreamProvider; import software.amazon.awssdk.http.SdkHttpFullRequest; @@ -37,6 +39,9 @@ String serialize(Object target) { if (target instanceof Map) { return serialize(((Map) target).keySet()); } + if (target instanceof SdkBytes) { + return serialize((SdkBytes) target); + } // simple type return target.toString(); } @@ -65,4 +70,120 @@ private String serialize(Collection collection) { String serialized = collection.stream().map(this::serialize).collect(Collectors.joining(",")); return (StringUtils.isEmpty(serialized) ? null : "[" + serialized + "]"); } + + @Nullable + String serialize(String attributeName, Object target) { + try { + JSONObject jsonBody; + if (target instanceof SdkBytes) { + jsonBody = new JSONObject(((SdkBytes) target).asUtf8String()); + } else { + if (target != null) { + return target.toString(); + } + return null; + } + switch (attributeName) { + case "gen_ai.response.finish_reason": + return getFinishReason(jsonBody); + case "gen_ai.usage.completion_tokens": + return getOutputTokens(jsonBody); + case "gen_ai.usage.prompt_tokens": + return getInputTokens(jsonBody); + case "gen_ai.request.top_p": + return getTopP(jsonBody); + case "gen_ai.request.temperature": + return getTemperature(jsonBody); + case "gen_ai.request.max_tokens": + return getMaxTokens(jsonBody); + default: + return null; + } + } catch (RuntimeException e) { + return null; + } + } + + private static String getFinishReason(JSONObject body) { + if (body.has("stop_reason")) { + return body.getString("stop_reason"); + } else if (body.has("results")) { + JSONObject result = (JSONObject) body.getJSONArray("results").get(0); + if (result.has("completionReason")) { + return result.getString("completionReason"); + } + } + return null; + } + + private static String getInputTokens(JSONObject body) { + if (body.has("prompt_token_count")) { + return String.valueOf(body.getInt("prompt_token_count")); + } else if (body.has("inputTextTokenCount")) { + return String.valueOf(body.getInt("inputTextTokenCount")); + } else if (body.has("usage")) { + JSONObject usage = (JSONObject) body.get("usage"); + if (usage.has("input_tokens")) { + return String.valueOf(usage.getInt("input_tokens")); + } + } + return null; + } + + private static String getOutputTokens(JSONObject body) { + if (body.has("generation_token_count")) { + return String.valueOf(body.getInt("generation_token_count")); + } else if (body.has("results")) { + JSONObject result = (JSONObject) body.getJSONArray("results").get(0); + if (result.has("tokenCount")) { + return String.valueOf(result.getInt("tokenCount")); + } + } else if (body.has("inputTextTokenCount")) { + return String.valueOf(body.getInt("inputTextTokenCount")); + } else if (body.has("usage")) { + JSONObject usage = (JSONObject) body.get("usage"); + if (usage.has("output_tokens")) { + return String.valueOf(usage.getInt("output_tokens")); + } + } + return null; + } + + private static String getTopP(JSONObject body) { + if (body.has("top_p")) { + return String.valueOf(body.getFloat("top_p")); + } else if (body.has("textGenerationConfig")) { + JSONObject usage = (JSONObject) body.get("textGenerationConfig"); + if (usage.has("topP")) { + return String.valueOf(usage.getFloat("topP")); + } + } + return null; + } + + private static String getTemperature(JSONObject body) { + if (body.has("temperature")) { + return String.valueOf(body.getFloat("temperature")); + } else if (body.has("textGenerationConfig")) { + JSONObject usage = (JSONObject) body.get("textGenerationConfig"); + if (usage.has("temperature")) { + return String.valueOf(usage.getFloat("temperature")); + } + } + return null; + } + + private static String getMaxTokens(JSONObject body) { + if (body.has("max_tokens")) { + return String.valueOf(body.getInt("max_tokens")); + } else if (body.has("max_gen_len")) { + return String.valueOf(body.getInt("max_gen_len")); + } else if (body.has("textGenerationConfig")) { + JSONObject usage = (JSONObject) body.get("textGenerationConfig"); + if (usage.has("maxTokenCount")) { + return String.valueOf(usage.getInt("maxTokenCount")); + } + } + return null; + } } From dbb4f3f457761507d4b2cf19a2a7959bacc0f006 Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Tue, 25 Jun 2024 11:17:05 -0700 Subject: [PATCH 02/13] Fix common / extra-dependency-management-enforcement workflow failure. --- .../aws-sdk/aws-sdk-2.2/library/build.gradle.kts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 e121354f3a56..e95b9a2031b9 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 @@ -4,12 +4,16 @@ plugins { dependencies { implementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator") + implementation("org.json:json") { + version { + strictly("[20210307,)") + } + } library("software.amazon.awssdk:aws-core:2.2.0") library("software.amazon.awssdk:sqs:2.2.0") library("software.amazon.awssdk:sns:2.2.0") library("software.amazon.awssdk:aws-json-protocol:2.2.0") - implementation("org.json:json:20210307") compileOnly(project(":muzzle")) // For @NoMuzzle testImplementation(project(":instrumentation:aws-sdk:aws-sdk-2.2:testing")) From 63f3a06eecc09fdab59f41ae18abdfdfbd2ffaf5 Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Wed, 26 Jun 2024 20:45:59 +0000 Subject: [PATCH 03/13] Add BedrockAgent Operation based API. --- .../awssdk/v2_2/AwsSdkRequest.java | 36 +++++++++++++++++-- .../awssdk/v2_2/AwsSdkRequestType.java | 9 +++-- 2 files changed, 40 insertions(+), 5 deletions(-) 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 18ff560b802a..183c18ae0f9e 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 @@ -6,7 +6,9 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCK; -import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCKAGENT; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCKAGENTOPERATION; +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; @@ -36,8 +38,38 @@ enum AwsSdkRequest { SqsRequest(SQS, "SqsRequest"), KinesisRequest(KINESIS, "KinesisRequest"), BedrockRequest(BEDROCK, "BedrockRequest"), - BedrockAgentRequest(BEDROCKAGENT, "BedrockAgentRequest"), + BedrockAgentRuntimeRequest(BEDROCKAGENTOPERATION, "BedrockAgentRuntimeRequest"), BedrockRuntimeRequest(BEDROCKRUNTIME, "BedrockRuntimeRequest"), + // BedrockAgent API based requests + BedrockCreateAgentActionGroupRequest(BEDROCKAGENTOPERATION, "CreateAgentActionGroupRequest"), + BedrockCreateAgentAliasRequest(BEDROCKAGENTOPERATION, "CreateAgentAliasRequest"), + BedrockDeleteAgentActionGroupRequest(BEDROCKAGENTOPERATION, "DeleteAgentActionGroupRequest"), + BedrockDeleteAgentAliasRequest(BEDROCKAGENTOPERATION, "DeleteAgentAliasRequest"), + BedrockDeleteAgentVersionRequest(BEDROCKAGENTOPERATION, "DeleteAgentVersionRequest"), + BedrockGetAgentActionGroupRequest(BEDROCKAGENTOPERATION, "GetAgentActionGroupRequest"), + BedrockGetAgentAliasRequest(BEDROCKAGENTOPERATION, "GetAgentAliasRequest"), + BedrockGetAgentRequest(BEDROCKAGENTOPERATION, "GetAgentRequest"), + BedrockGetAgentVersionRequest(BEDROCKAGENTOPERATION, "GetAgentVersionRequest"), + BedrockListAgentActionGroupsRequest(BEDROCKAGENTOPERATION, "ListAgentActionGroupsRequest"), + BedrockListAgentAliasesRequest(BEDROCKAGENTOPERATION, "ListAgentAliasesRequest"), + BedrockListAgentKnowledgeBasesRequest(BEDROCKAGENTOPERATION, "ListAgentKnowledgeBasesRequest"), + BedrocListAgentVersionsRequest(BEDROCKAGENTOPERATION, "ListAgentVersionsRequest"), + BedrockPrepareAgentRequest(BEDROCKAGENTOPERATION, "PrepareAgentRequest"), + BedrockUpdateAgentActionGroupRequest(BEDROCKAGENTOPERATION, "UpdateAgentActionGroupRequest"), + BedrockUpdateAgentAliasRequest(BEDROCKAGENTOPERATION, "UpdateAgentAliasRequest"), + BedrockUpdateAgentRequest(BEDROCKAGENTOPERATION, "UpdateAgentRequest"), + BedrockBedrockAgentRequest(BEDROCKAGENTOPERATION, "BedrockAgentRequest"), + BedrockDeleteDataSourceRequest(BEDROCKDATASOURCEOPERATION, "DeleteDataSourceRequest"), + BedrockGetDataSourceRequest(BEDROCKDATASOURCEOPERATION, "GetDataSourceRequest"), + BedrockUpdateDataSourceRequest(BEDROCKDATASOURCEOPERATION, "UpdateDataSourceRequest"), + BedrocAssociateAgentKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "AssociateAgentKnowledgeBaseRequest"), + BedrockCreateDataSourceRequest(BEDROCKKNOWLEDGEBASEOPERATION, "CreateDataSourceRequest"), + BedrockDeleteKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "DeleteKnowledgeBaseRequest"), + BedrockDisassociateAgentKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "DisassociateAgentKnowledgeBaseRequest"), + BedrockGetAgentKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "GetAgentKnowledgeBaseRequest"), + BedrockGetKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "GetKnowledgeBaseRequest"), + BedrockListDataSourcesRequest(BEDROCKKNOWLEDGEBASEOPERATION, "ListDataSourcesRequest"), + BedrockUpdateAgentKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "UpdateAgentKnowledgeBaseRequest"), // 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 238a6ab746af..856336696911 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 @@ -34,10 +34,13 @@ enum AwsSdkRequestType { KINESIS(request(AWS_STREAM_NAME.getKey(), "StreamName")), DYNAMODB(request(AWS_TABLE_NAME.getKey(), "TableName")), BEDROCK(request(AWS_BEDROCK_GUARDRAIL_ID.getKey(), "guardrailIdentifier")), - BEDROCKAGENT( + BEDROCKAGENTOPERATION( request(AWS_BEDROCK_AGENT_ID.getKey(), "agentId"), - request(AWS_BEDROCK_DATASOURCE_ID.getKey(), "dataSourceId"), - request(AWS_BEDROCK_KNOWLEDGEBASE_ID.getKey(), "knowledgeBaseId")), + response(AWS_BEDROCK_AGENT_ID.getKey(), "agentId")), + BEDROCKDATASOURCEOPERATION( + request(AWS_BEDROCK_DATASOURCE_ID.getKey(), "agentId")), + BEDROCKKNOWLEDGEBASEOPERATION( + request(AWS_BEDROCK_KNOWLEDGEBASE_ID.getKey(), "agentId")), BEDROCKRUNTIME( request(GEN_AI_MODEL.getKey(), "modelId"), request(GEN_AI_TEMPERATURE.getKey(), "body"), From 2434bb7ddadbb01d878de418fa006e23089a2fa2 Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Wed, 26 Jun 2024 14:34:38 -0700 Subject: [PATCH 04/13] Apply spitless. --- .../instrumentation/awssdk/v2_2/AwsSdkRequest.java | 12 ++++++++---- .../awssdk/v2_2/AwsSdkRequestType.java | 6 ++---- 2 files changed, 10 insertions(+), 8 deletions(-) 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 183c18ae0f9e..f5b16280e35e 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 @@ -62,14 +62,18 @@ enum AwsSdkRequest { BedrockDeleteDataSourceRequest(BEDROCKDATASOURCEOPERATION, "DeleteDataSourceRequest"), BedrockGetDataSourceRequest(BEDROCKDATASOURCEOPERATION, "GetDataSourceRequest"), BedrockUpdateDataSourceRequest(BEDROCKDATASOURCEOPERATION, "UpdateDataSourceRequest"), - BedrocAssociateAgentKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "AssociateAgentKnowledgeBaseRequest"), + BedrocAssociateAgentKnowledgeBaseRequest( + BEDROCKKNOWLEDGEBASEOPERATION, "AssociateAgentKnowledgeBaseRequest"), BedrockCreateDataSourceRequest(BEDROCKKNOWLEDGEBASEOPERATION, "CreateDataSourceRequest"), BedrockDeleteKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "DeleteKnowledgeBaseRequest"), - BedrockDisassociateAgentKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "DisassociateAgentKnowledgeBaseRequest"), - BedrockGetAgentKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "GetAgentKnowledgeBaseRequest"), + BedrockDisassociateAgentKnowledgeBaseRequest( + BEDROCKKNOWLEDGEBASEOPERATION, "DisassociateAgentKnowledgeBaseRequest"), + BedrockGetAgentKnowledgeBaseRequest( + BEDROCKKNOWLEDGEBASEOPERATION, "GetAgentKnowledgeBaseRequest"), BedrockGetKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "GetKnowledgeBaseRequest"), BedrockListDataSourcesRequest(BEDROCKKNOWLEDGEBASEOPERATION, "ListDataSourcesRequest"), - BedrockUpdateAgentKnowledgeBaseRequest(BEDROCKKNOWLEDGEBASEOPERATION, "UpdateAgentKnowledgeBaseRequest"), + BedrockUpdateAgentKnowledgeBaseRequest( + BEDROCKKNOWLEDGEBASEOPERATION, "UpdateAgentKnowledgeBaseRequest"), // 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 856336696911..a1903c33d729 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 @@ -37,10 +37,8 @@ enum AwsSdkRequestType { BEDROCKAGENTOPERATION( request(AWS_BEDROCK_AGENT_ID.getKey(), "agentId"), response(AWS_BEDROCK_AGENT_ID.getKey(), "agentId")), - BEDROCKDATASOURCEOPERATION( - request(AWS_BEDROCK_DATASOURCE_ID.getKey(), "agentId")), - BEDROCKKNOWLEDGEBASEOPERATION( - request(AWS_BEDROCK_KNOWLEDGEBASE_ID.getKey(), "agentId")), + BEDROCKDATASOURCEOPERATION(request(AWS_BEDROCK_DATASOURCE_ID.getKey(), "agentId")), + BEDROCKKNOWLEDGEBASEOPERATION(request(AWS_BEDROCK_KNOWLEDGEBASE_ID.getKey(), "agentId")), BEDROCKRUNTIME( request(GEN_AI_MODEL.getKey(), "modelId"), request(GEN_AI_TEMPERATURE.getKey(), "body"), From 8e961c33fb846d3fba01c4e01749a086b03324bc Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Fri, 28 Jun 2024 11:38:09 -0700 Subject: [PATCH 05/13] Change Json dependency pkgs. --- .../aws-sdk-2.2/library/build.gradle.kts | 4 +- .../awssdk/v2_2/AwsSdkRequestType.java | 4 +- .../awssdk/v2_2/Serializer.java | 71 ++++++++++--------- 3 files changed, 41 insertions(+), 38 deletions(-) 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 e95b9a2031b9..804e7cdb0a65 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 @@ -4,9 +4,9 @@ plugins { dependencies { implementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator") - implementation("org.json:json") { + implementation("com.fasterxml.jackson.core:jackson-databind") { version { - strictly("[20210307,)") + strictly("[2.13.3,)") } } 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 a1903c33d729..abdff8c84cb3 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 @@ -37,8 +37,8 @@ enum AwsSdkRequestType { BEDROCKAGENTOPERATION( request(AWS_BEDROCK_AGENT_ID.getKey(), "agentId"), response(AWS_BEDROCK_AGENT_ID.getKey(), "agentId")), - BEDROCKDATASOURCEOPERATION(request(AWS_BEDROCK_DATASOURCE_ID.getKey(), "agentId")), - BEDROCKKNOWLEDGEBASEOPERATION(request(AWS_BEDROCK_KNOWLEDGEBASE_ID.getKey(), "agentId")), + BEDROCKDATASOURCEOPERATION(request(AWS_BEDROCK_DATASOURCE_ID.getKey(), "dataSourceId")), + BEDROCKKNOWLEDGEBASEOPERATION(request(AWS_BEDROCK_KNOWLEDGEBASE_ID.getKey(), "knowledgeBaseId")), BEDROCKRUNTIME( request(GEN_AI_MODEL.getKey(), "modelId"), request(GEN_AI_TEMPERATURE.getKey(), "body"), diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/Serializer.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/Serializer.java index 14e01024ca06..ba8305f6d81d 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/Serializer.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/Serializer.java @@ -5,6 +5,9 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; +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; @@ -12,7 +15,6 @@ import java.util.Optional; import java.util.stream.Collectors; import javax.annotation.Nullable; -import org.json.JSONObject; import software.amazon.awssdk.core.SdkBytes; import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.http.ContentStreamProvider; @@ -22,6 +24,7 @@ import software.amazon.awssdk.utils.StringUtils; class Serializer { + private static final ObjectMapper objectMapper = new ObjectMapper(); @Nullable String serialize(Object target) { @@ -74,9 +77,9 @@ private String serialize(Collection collection) { @Nullable String serialize(String attributeName, Object target) { try { - JSONObject jsonBody; + JsonNode jsonBody; if (target instanceof SdkBytes) { - jsonBody = new JSONObject(((SdkBytes) target).asUtf8String()); + jsonBody = objectMapper.readTree(((SdkBytes) target).asUtf8String()); } else { if (target != null) { return target.toString(); @@ -99,89 +102,89 @@ String serialize(String attributeName, Object target) { default: return null; } - } catch (RuntimeException e) { - return null; + } catch (RuntimeException | JsonProcessingException e) { + throw new IllegalStateException("Failed to instantiate operation class", e); } } - private static String getFinishReason(JSONObject body) { + private static String getFinishReason(JsonNode body) { if (body.has("stop_reason")) { - return body.getString("stop_reason"); + return body.get("stop_reason").asText(); } else if (body.has("results")) { - JSONObject result = (JSONObject) body.getJSONArray("results").get(0); + JsonNode result = body.get("results").get(0); if (result.has("completionReason")) { - return result.getString("completionReason"); + return result.get("completionReason").asText(); } } return null; } - private static String getInputTokens(JSONObject body) { + private static String getInputTokens(JsonNode body) { if (body.has("prompt_token_count")) { - return String.valueOf(body.getInt("prompt_token_count")); + return String.valueOf(body.get("prompt_token_count").asInt()); } else if (body.has("inputTextTokenCount")) { - return String.valueOf(body.getInt("inputTextTokenCount")); + return String.valueOf(body.get("inputTextTokenCount").asInt()); } else if (body.has("usage")) { - JSONObject usage = (JSONObject) body.get("usage"); + JsonNode usage = body.get("usage"); if (usage.has("input_tokens")) { - return String.valueOf(usage.getInt("input_tokens")); + return String.valueOf(usage.get("input_tokens").asInt()); } } return null; } - private static String getOutputTokens(JSONObject body) { + private static String getOutputTokens(JsonNode body) { if (body.has("generation_token_count")) { - return String.valueOf(body.getInt("generation_token_count")); + return String.valueOf(body.get("generation_token_count").asInt()); } else if (body.has("results")) { - JSONObject result = (JSONObject) body.getJSONArray("results").get(0); + JsonNode result = body.get("results").get(0); if (result.has("tokenCount")) { - return String.valueOf(result.getInt("tokenCount")); + return String.valueOf(result.get("tokenCount").asInt()); } } else if (body.has("inputTextTokenCount")) { - return String.valueOf(body.getInt("inputTextTokenCount")); + return String.valueOf(body.get("inputTextTokenCount").asInt()); } else if (body.has("usage")) { - JSONObject usage = (JSONObject) body.get("usage"); + JsonNode usage = body.get("usage"); if (usage.has("output_tokens")) { - return String.valueOf(usage.getInt("output_tokens")); + return String.valueOf(usage.get("output_tokens").asInt()); } } return null; } - private static String getTopP(JSONObject body) { + private static String getTopP(JsonNode body) { if (body.has("top_p")) { - return String.valueOf(body.getFloat("top_p")); + return String.valueOf(body.get("top_p").asDouble()); } else if (body.has("textGenerationConfig")) { - JSONObject usage = (JSONObject) body.get("textGenerationConfig"); + JsonNode usage = body.get("textGenerationConfig"); if (usage.has("topP")) { - return String.valueOf(usage.getFloat("topP")); + return String.valueOf(usage.get("topP").asInt()); } } return null; } - private static String getTemperature(JSONObject body) { + private static String getTemperature(JsonNode body) { if (body.has("temperature")) { - return String.valueOf(body.getFloat("temperature")); + return String.valueOf(body.get("temperature").asDouble()); } else if (body.has("textGenerationConfig")) { - JSONObject usage = (JSONObject) body.get("textGenerationConfig"); + JsonNode usage = body.get("textGenerationConfig"); if (usage.has("temperature")) { - return String.valueOf(usage.getFloat("temperature")); + return String.valueOf(usage.get("temperature").asDouble()); } } return null; } - private static String getMaxTokens(JSONObject body) { + private static String getMaxTokens(JsonNode body) { if (body.has("max_tokens")) { - return String.valueOf(body.getInt("max_tokens")); + return String.valueOf(body.get("max_tokens").asInt()); } else if (body.has("max_gen_len")) { - return String.valueOf(body.getInt("max_gen_len")); + return String.valueOf(body.get("max_gen_len").asInt()); } else if (body.has("textGenerationConfig")) { - JSONObject usage = (JSONObject) body.get("textGenerationConfig"); + JsonNode usage = body.get("textGenerationConfig"); if (usage.has("maxTokenCount")) { - return String.valueOf(usage.getInt("maxTokenCount")); + return String.valueOf(usage.get("maxTokenCount").asInt()); } } return null; From 1768c85df36e76bfc2aedac5d506f32778133805 Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Fri, 28 Jun 2024 15:17:08 -0700 Subject: [PATCH 06/13] Trigger WF. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 27c0818d8e7f..6ebf40893262 100644 --- a/README.md +++ b/README.md @@ -184,3 +184,4 @@ Thanks to all the people who already contributed! [manual]: https://opentelemetry.io/docs/instrumentation/java/manual/ [suppress]: https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/#suppressing-specific-auto-instrumentation + From a3ec28b1ec071d63b22385472f2d47d9a093285b Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Mon, 1 Jul 2024 19:39:33 -0700 Subject: [PATCH 07/13] Add unit tests. --- README.md | 1 - .../aws-sdk-2.2/testing/build.gradle.kts | 9 +++ .../awssdk/v2_2/AbstractAws2ClientTest.groovy | 73 +++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ebf40893262..27c0818d8e7f 100644 --- a/README.md +++ b/README.md @@ -184,4 +184,3 @@ Thanks to all the people who already contributed! [manual]: https://opentelemetry.io/docs/instrumentation/java/manual/ [suppress]: https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/#suppressing-specific-auto-instrumentation - 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 2a7f14d14b72..d9869c5befd8 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 { compileOnly("software.amazon.awssdk:sqs:2.2.0") compileOnly("software.amazon.awssdk:sns:2.2.0") compileOnly("software.amazon.awssdk:ses:2.2.0") + compileOnly("software.amazon.awssdk:bedrock:2.26.8") + compileOnly("software.amazon.awssdk:bedrockagent:2.26.8") + compileOnly("software.amazon.awssdk:bedrockruntime:2.26.8") // 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") @@ -28,4 +31,10 @@ dependencies { implementation("org.apache.groovy:groovy") implementation("io.opentelemetry:opentelemetry-api") implementation("org.spockframework:spock-core") + // needed for BedrockRuntime Json serialization + implementation("com.fasterxml.jackson.core:jackson-databind") { + version { + strictly("[2.13.3,)") + } + } } 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 53390c8d8524..76a8c72f76b4 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 @@ -11,7 +11,9 @@ 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.Assumptions +import com.fasterxml.jackson.databind.ObjectMapper; import software.amazon.awssdk.core.ResponseInputStream +import software.amazon.awssdk.core.SdkBytes import software.amazon.awssdk.core.async.AsyncResponseTransformer import software.amazon.awssdk.core.exception.SdkClientException import software.amazon.awssdk.core.retry.RetryPolicy @@ -33,6 +35,14 @@ 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 +import software.amazon.awssdk.services.bedrock.BedrockClient +import software.amazon.awssdk.services.bedrock.model.GetGuardrailRequest +import software.amazon.awssdk.services.bedrockagent.BedrockAgentClient +import software.amazon.awssdk.services.bedrockagent.model.GetAgentRequest +import software.amazon.awssdk.services.bedrockagent.model.GetKnowledgeBaseRequest +import software.amazon.awssdk.services.bedrockagent.model.GetDataSourceRequest +import software.amazon.awssdk.services.bedrockruntime.BedrockRuntimeClient +import software.amazon.awssdk.services.bedrockruntime.model.InvokeModelRequest import spock.lang.Unroll import java.time.Duration @@ -120,7 +130,25 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest { "$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS" } else if (service == "Kinesis") { "aws.stream.name" "somestream" + } else if (service == "Kinesis") { + "aws.stream.name" "somestream" + } else if (service == "Bedrock" && operation == "GetGuardrail") { + "aws.bedrock.guardrail_id" "guardrailId" + } else if (service == "BedrockAgent" && operation == "GetAgent") { + "aws.bedrock.agent_id" "agentId" + } else if (service == "BedrockAgent" && operation == "GetKnowledgeBase") { + "aws.bedrock.knowledgebase_id" "knowledgeBaseId" + } else if (service == "BedrockAgent" && operation == "GetDataSource") { + "aws.bedrock.datasource_id" "datasourceId" + } else if (service == "BedrockRuntime" && operation == "InvokeModel") { + "gen_ai.request.top_p" "0.9" + "gen_ai.request.temperature" "0.7" + "gen_ai.request.model" "meta.llama2-13b-chat-v1" + "gen_ai.request.max_tokens" "100" + "gen_ai.system" "AWS Bedrock" + "gen_ai.response.finish_reasons" "length" } + } } } @@ -162,6 +190,51 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest { 0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99 """ + "Bedrock" | "GetGuardrail" | "GET" | "UNKNOWN" | BedrockClient.builder() | { c -> c.getGuardrail(GetGuardrailRequest.builder().guardrailIdentifier("guardrailId").build()) } | """ + { + "blockedInputMessaging": "string", + "blockedOutputsMessaging": "string", + "contentPolicy": {}, + "createdAt": "2024-06-12T18:31:45Z", + "description": "string", + "guardrailArn": "string", + "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": {} + } + """ + "BedrockAgent" | "GetAgent" | "GET" | "UNKNOWN" | BedrockAgentClient.builder() | { c -> c.getAgent(GetAgentRequest.builder().agentId("agentId").build()) } | "" + "BedrockAgent" | "GetKnowledgeBase" | "GET" | "UNKNOWN" | BedrockAgentClient.builder() | { c -> c.getKnowledgeBase(GetKnowledgeBaseRequest.builder().knowledgeBaseId("knowledgeBaseId").build()) } | "" + "BedrockAgent" | "GetDataSource" | "GET" | "UNKNOWN" | BedrockAgentClient.builder() | { c -> c.getDataSource(GetDataSourceRequest.builder().dataSourceId("datasourceId").knowledgeBaseId("knowledgeBaseId").build()) } | "" + "BedrockRuntime" | "InvokeModel" | "POST" | "UNKNOWN" | BedrockRuntimeClient.builder() | + { c -> c.invokeModel( + InvokeModelRequest.builder() + .body(SdkBytes.fromUtf8String(new ObjectMapper().createObjectNode().put("prompt", "Hi Amazon bedrock, how are you??").put("max_gen_len", 100).put("temperature", 0.7).put("top_p", 0.9).toString())) + .modelId("meta.llama2-13b-chat-v1") + .contentType("application/json") + .accept("application/json") + .build()) } | """ + { + "completion": " Here is a simple explanation of black ", + "stop_reason": "length", + "stop": "holes" + } + """ } def "send #operation async request with builder #builder.class.getName() mocked response"() { From ba588ec247858a2606e6805a0f7412efbfb2e1c8 Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Mon, 1 Jul 2024 20:22:33 -0700 Subject: [PATCH 08/13] Unit test still dosen't work, removing. --- .../aws-sdk-2.2/testing/build.gradle.kts | 9 --- .../awssdk/v2_2/AbstractAws2ClientTest.groovy | 55 ------------------- 2 files changed, 64 deletions(-) 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 d9869c5befd8..2a7f14d14b72 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,9 +19,6 @@ 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") - compileOnly("software.amazon.awssdk:bedrock:2.26.8") - compileOnly("software.amazon.awssdk:bedrockagent:2.26.8") - compileOnly("software.amazon.awssdk:bedrockruntime:2.26.8") // 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") @@ -31,10 +28,4 @@ dependencies { implementation("org.apache.groovy:groovy") implementation("io.opentelemetry:opentelemetry-api") implementation("org.spockframework:spock-core") - // needed for BedrockRuntime Json serialization - implementation("com.fasterxml.jackson.core:jackson-databind") { - version { - strictly("[2.13.3,)") - } - } } 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 76a8c72f76b4..89e0b7c082dd 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 @@ -11,9 +11,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 org.junit.jupiter.api.Assumptions -import com.fasterxml.jackson.databind.ObjectMapper; import software.amazon.awssdk.core.ResponseInputStream -import software.amazon.awssdk.core.SdkBytes import software.amazon.awssdk.core.async.AsyncResponseTransformer import software.amazon.awssdk.core.exception.SdkClientException import software.amazon.awssdk.core.retry.RetryPolicy @@ -35,14 +33,6 @@ 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 -import software.amazon.awssdk.services.bedrock.BedrockClient -import software.amazon.awssdk.services.bedrock.model.GetGuardrailRequest -import software.amazon.awssdk.services.bedrockagent.BedrockAgentClient -import software.amazon.awssdk.services.bedrockagent.model.GetAgentRequest -import software.amazon.awssdk.services.bedrockagent.model.GetKnowledgeBaseRequest -import software.amazon.awssdk.services.bedrockagent.model.GetDataSourceRequest -import software.amazon.awssdk.services.bedrockruntime.BedrockRuntimeClient -import software.amazon.awssdk.services.bedrockruntime.model.InvokeModelRequest import spock.lang.Unroll import java.time.Duration @@ -190,51 +180,6 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest { 0ac9cda2-bbf4-11d3-f92b-31fa5e8dbc99 """ - "Bedrock" | "GetGuardrail" | "GET" | "UNKNOWN" | BedrockClient.builder() | { c -> c.getGuardrail(GetGuardrailRequest.builder().guardrailIdentifier("guardrailId").build()) } | """ - { - "blockedInputMessaging": "string", - "blockedOutputsMessaging": "string", - "contentPolicy": {}, - "createdAt": "2024-06-12T18:31:45Z", - "description": "string", - "guardrailArn": "string", - "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": {} - } - """ - "BedrockAgent" | "GetAgent" | "GET" | "UNKNOWN" | BedrockAgentClient.builder() | { c -> c.getAgent(GetAgentRequest.builder().agentId("agentId").build()) } | "" - "BedrockAgent" | "GetKnowledgeBase" | "GET" | "UNKNOWN" | BedrockAgentClient.builder() | { c -> c.getKnowledgeBase(GetKnowledgeBaseRequest.builder().knowledgeBaseId("knowledgeBaseId").build()) } | "" - "BedrockAgent" | "GetDataSource" | "GET" | "UNKNOWN" | BedrockAgentClient.builder() | { c -> c.getDataSource(GetDataSourceRequest.builder().dataSourceId("datasourceId").knowledgeBaseId("knowledgeBaseId").build()) } | "" - "BedrockRuntime" | "InvokeModel" | "POST" | "UNKNOWN" | BedrockRuntimeClient.builder() | - { c -> c.invokeModel( - InvokeModelRequest.builder() - .body(SdkBytes.fromUtf8String(new ObjectMapper().createObjectNode().put("prompt", "Hi Amazon bedrock, how are you??").put("max_gen_len", 100).put("temperature", 0.7).put("top_p", 0.9).toString())) - .modelId("meta.llama2-13b-chat-v1") - .contentType("application/json") - .accept("application/json") - .build()) } | """ - { - "completion": " Here is a simple explanation of black ", - "stop_reason": "length", - "stop": "holes" - } - """ } def "send #operation async request with builder #builder.class.getName() mocked response"() { From 006684c6ac71582567ed855eaae7b9d989ae2d6c Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Fri, 5 Jul 2024 01:32:34 +0000 Subject: [PATCH 09/13] Address comments. --- .../aws-sdk-2.2/library/build.gradle.kts | 5 - .../v2_2/AwsExperimentalAttributes.java | 25 +--- .../awssdk/v2_2/AwsSdkRequest.java | 4 +- .../awssdk/v2_2/AwsSdkRequestType.java | 23 +--- .../awssdk/v2_2/FieldMapper.java | 8 +- .../awssdk/v2_2/Serializer.java | 124 ------------------ .../v2_2/TracingExecutionInterceptor.java | 5 + .../awssdk/v2_2/AbstractAws2ClientTest.groovy | 16 +-- 8 files changed, 24 insertions(+), 186 deletions(-) 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 804e7cdb0a65..081d542e76ab 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 @@ -4,11 +4,6 @@ plugins { dependencies { implementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator") - implementation("com.fasterxml.jackson.core:jackson-databind") { - version { - strictly("[2.13.3,)") - } - } library("software.amazon.awssdk:aws-core:2.2.0") library("software.amazon.awssdk:sqs:2.2.0") 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 index 9e5a5834d580..35093b4746b9 100644 --- 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 @@ -19,34 +19,15 @@ final class AwsExperimentalAttributes { stringKey("aws.bedrock.guardrail_id"); static final AttributeKey AWS_BEDROCK_AGENT_ID = stringKey("aws.bedrock.agent_id"); static final AttributeKey AWS_BEDROCK_DATASOURCE_ID = - stringKey("aws.bedrock.datasource_id"); + stringKey("aws.bedrock.data_source_id"); static final AttributeKey AWS_BEDROCK_KNOWLEDGEBASE_ID = - stringKey("aws.bedrock.knowledgebase_id"); - static final AttributeKey GEN_AI_FINISH_REASON = - stringKey("gen_ai.response.finish_reason"); - static final AttributeKey GEN_AI_PROMPT_TOKENS = stringKey("gen_ai.usage.prompt_tokens"); - static final AttributeKey GEN_AI_COMPLETION_TOKENS = - stringKey("gen_ai.usage.completion_tokens"); + stringKey("aws.bedrock.knowledge_base_id"); // OTel GenAI/LLM group has defined gen_ai attributes but not yet add it in // semantic-conventions-java package // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-spans.md#genai-attributes + // TODO: Merge in these attributes in semantic-conventions-java package static final AttributeKey GEN_AI_MODEL = stringKey("gen_ai.request.model"); - static final AttributeKey GEN_AI_TEMPERATURE = stringKey("gen_ai.request.temperature"); - static final AttributeKey GEN_AI_TOP_P = stringKey("gen_ai.request.top_p"); - static final AttributeKey GEN_AI_MAX_TOKENS = stringKey("gen_ai.request.max_tokens"); - static final AttributeKey GEN_AI_SYSTEM = stringKey("gen_ai.system"); private AwsExperimentalAttributes() {} - - static boolean isGenAiAttribute(String attributeKey) { - return attributeKey.equals(GEN_AI_MODEL.getKey()) - || attributeKey.equals(GEN_AI_FINISH_REASON.getKey()) - || attributeKey.equals(GEN_AI_PROMPT_TOKENS.getKey()) - || attributeKey.equals(GEN_AI_COMPLETION_TOKENS.getKey()) - || attributeKey.equals(GEN_AI_TEMPERATURE.getKey()) - || attributeKey.equals(GEN_AI_TOP_P.getKey()) - || attributeKey.equals(GEN_AI_MAX_TOKENS.getKey()) - || attributeKey.equals(GEN_AI_SYSTEM.getKey()); - } } 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 f5b16280e35e..aa570c8ce34b 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 @@ -40,7 +40,9 @@ enum AwsSdkRequest { BedrockRequest(BEDROCK, "BedrockRequest"), BedrockAgentRuntimeRequest(BEDROCKAGENTOPERATION, "BedrockAgentRuntimeRequest"), BedrockRuntimeRequest(BEDROCKRUNTIME, "BedrockRuntimeRequest"), - // BedrockAgent API based requests + // BedrockAgent API based requests. We only support operations that are related to + // Agent/DataSources/KnowledgeBases + // resources and the request/response context contains the resource ID. BedrockCreateAgentActionGroupRequest(BEDROCKAGENTOPERATION, "CreateAgentActionGroupRequest"), BedrockCreateAgentAliasRequest(BEDROCKAGENTOPERATION, "CreateAgentAliasRequest"), BedrockDeleteAgentActionGroupRequest(BEDROCKAGENTOPERATION, "DeleteAgentActionGroupRequest"), 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 abdff8c84cb3..fe9f4803e3f2 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 @@ -14,13 +14,7 @@ import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.AWS_QUEUE_URL; 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_COMPLETION_TOKENS; -import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_FINISH_REASON; -import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_MAX_TOKENS; import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_MODEL; -import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_PROMPT_TOKENS; -import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_TEMPERATURE; -import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsExperimentalAttributes.GEN_AI_TOP_P; import static io.opentelemetry.instrumentation.awssdk.v2_2.FieldMapping.request; import static io.opentelemetry.instrumentation.awssdk.v2_2.FieldMapping.response; @@ -37,16 +31,13 @@ enum AwsSdkRequestType { BEDROCKAGENTOPERATION( request(AWS_BEDROCK_AGENT_ID.getKey(), "agentId"), response(AWS_BEDROCK_AGENT_ID.getKey(), "agentId")), - BEDROCKDATASOURCEOPERATION(request(AWS_BEDROCK_DATASOURCE_ID.getKey(), "dataSourceId")), - BEDROCKKNOWLEDGEBASEOPERATION(request(AWS_BEDROCK_KNOWLEDGEBASE_ID.getKey(), "knowledgeBaseId")), - BEDROCKRUNTIME( - request(GEN_AI_MODEL.getKey(), "modelId"), - request(GEN_AI_TEMPERATURE.getKey(), "body"), - request(GEN_AI_TOP_P.getKey(), "body"), - request(GEN_AI_MAX_TOKENS.getKey(), "body"), - response(GEN_AI_FINISH_REASON.getKey(), "body"), - response(GEN_AI_PROMPT_TOKENS.getKey(), "body"), - response(GEN_AI_COMPLETION_TOKENS.getKey(), "body")); + BEDROCKDATASOURCEOPERATION( + request(AWS_BEDROCK_DATASOURCE_ID.getKey(), "dataSourceId"), + response(AWS_BEDROCK_DATASOURCE_ID.getKey(), "dataSourceId")), + BEDROCKKNOWLEDGEBASEOPERATION( + request(AWS_BEDROCK_KNOWLEDGEBASE_ID.getKey(), "knowledgeBaseId"), + response(AWS_BEDROCK_KNOWLEDGEBASE_ID.getKey(), "knowledgeBaseId")), + BEDROCKRUNTIME(request(GEN_AI_MODEL.getKey(), "modelId")); // 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/FieldMapper.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/FieldMapper.java index 93e3f9508049..2487f9c86949 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/FieldMapper.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/FieldMapper.java @@ -65,14 +65,8 @@ private void mapToAttributes( for (int i = 1; i < path.size() && target != null; i++) { target = next(target, path.get(i)); } - String value; if (target != null) { - if (AwsExperimentalAttributes.isGenAiAttribute(fieldMapping.getAttribute())) { - value = serializer.serialize(fieldMapping.getAttribute(), target); - span.setAttribute("gen_ai.system", "AWS Bedrock"); - } else { - value = serializer.serialize(target); - } + String 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/Serializer.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/Serializer.java index ba8305f6d81d..979ecb08e87d 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/Serializer.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/Serializer.java @@ -5,9 +5,6 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; -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; @@ -15,7 +12,6 @@ import java.util.Optional; import java.util.stream.Collectors; 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; @@ -24,7 +20,6 @@ import software.amazon.awssdk.utils.StringUtils; class Serializer { - private static final ObjectMapper objectMapper = new ObjectMapper(); @Nullable String serialize(Object target) { @@ -42,9 +37,6 @@ String serialize(Object target) { if (target instanceof Map) { return serialize(((Map) target).keySet()); } - if (target instanceof SdkBytes) { - return serialize((SdkBytes) target); - } // simple type return target.toString(); } @@ -73,120 +65,4 @@ private String serialize(Collection collection) { String serialized = collection.stream().map(this::serialize).collect(Collectors.joining(",")); return (StringUtils.isEmpty(serialized) ? null : "[" + serialized + "]"); } - - @Nullable - String serialize(String attributeName, Object target) { - try { - JsonNode jsonBody; - if (target instanceof SdkBytes) { - jsonBody = objectMapper.readTree(((SdkBytes) target).asUtf8String()); - } else { - if (target != null) { - return target.toString(); - } - return null; - } - switch (attributeName) { - case "gen_ai.response.finish_reason": - return getFinishReason(jsonBody); - case "gen_ai.usage.completion_tokens": - return getOutputTokens(jsonBody); - case "gen_ai.usage.prompt_tokens": - return getInputTokens(jsonBody); - case "gen_ai.request.top_p": - return getTopP(jsonBody); - case "gen_ai.request.temperature": - return getTemperature(jsonBody); - case "gen_ai.request.max_tokens": - return getMaxTokens(jsonBody); - default: - return null; - } - } catch (RuntimeException | JsonProcessingException e) { - throw new IllegalStateException("Failed to instantiate operation class", e); - } - } - - private static String getFinishReason(JsonNode body) { - if (body.has("stop_reason")) { - return body.get("stop_reason").asText(); - } else if (body.has("results")) { - JsonNode result = body.get("results").get(0); - if (result.has("completionReason")) { - return result.get("completionReason").asText(); - } - } - return null; - } - - private static String getInputTokens(JsonNode body) { - if (body.has("prompt_token_count")) { - return String.valueOf(body.get("prompt_token_count").asInt()); - } else if (body.has("inputTextTokenCount")) { - return String.valueOf(body.get("inputTextTokenCount").asInt()); - } else if (body.has("usage")) { - JsonNode usage = body.get("usage"); - if (usage.has("input_tokens")) { - return String.valueOf(usage.get("input_tokens").asInt()); - } - } - return null; - } - - private static String getOutputTokens(JsonNode body) { - if (body.has("generation_token_count")) { - return String.valueOf(body.get("generation_token_count").asInt()); - } else if (body.has("results")) { - JsonNode result = body.get("results").get(0); - if (result.has("tokenCount")) { - return String.valueOf(result.get("tokenCount").asInt()); - } - } else if (body.has("inputTextTokenCount")) { - return String.valueOf(body.get("inputTextTokenCount").asInt()); - } else if (body.has("usage")) { - JsonNode usage = body.get("usage"); - if (usage.has("output_tokens")) { - return String.valueOf(usage.get("output_tokens").asInt()); - } - } - return null; - } - - private static String getTopP(JsonNode body) { - if (body.has("top_p")) { - return String.valueOf(body.get("top_p").asDouble()); - } else if (body.has("textGenerationConfig")) { - JsonNode usage = body.get("textGenerationConfig"); - if (usage.has("topP")) { - return String.valueOf(usage.get("topP").asInt()); - } - } - return null; - } - - private static String getTemperature(JsonNode body) { - if (body.has("temperature")) { - return String.valueOf(body.get("temperature").asDouble()); - } else if (body.has("textGenerationConfig")) { - JsonNode usage = body.get("textGenerationConfig"); - if (usage.has("temperature")) { - return String.valueOf(usage.get("temperature").asDouble()); - } - } - return null; - } - - private static String getMaxTokens(JsonNode body) { - if (body.has("max_tokens")) { - return String.valueOf(body.get("max_tokens").asInt()); - } else if (body.has("max_gen_len")) { - return String.valueOf(body.get("max_gen_len").asInt()); - } else if (body.has("textGenerationConfig")) { - JsonNode usage = body.get("textGenerationConfig"); - if (usage.has("maxTokenCount")) { - return String.valueOf(usage.get("maxTokenCount").asInt()); - } - } - return null; - } } 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 f717b1efc44c..6748cb353878 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 @@ -5,6 +5,7 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.BEDROCKRUNTIME; import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkRequestType.DYNAMODB; import io.opentelemetry.api.common.AttributeKey; @@ -317,6 +318,10 @@ private void populateRequestAttributes( span.setAttribute(SemanticAttributes.DB_OPERATION, operation); } } + + if (awsSdkRequest.type() == BEDROCKRUNTIME) { + span.setAttribute("gen_ai.system", "aws_bedrock"); + } } @Override 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 89e0b7c082dd..2833570ca2b6 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 @@ -120,23 +120,17 @@ abstract class AbstractAws2ClientTest extends AbstractAws2ClientCoreTest { "$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS" } else if (service == "Kinesis") { "aws.stream.name" "somestream" - } else if (service == "Kinesis") { - "aws.stream.name" "somestream" } else if (service == "Bedrock" && operation == "GetGuardrail") { - "aws.bedrock.guardrail_id" "guardrailId" + "aws.bedrock.guardrail.id" "guardrailId" } else if (service == "BedrockAgent" && operation == "GetAgent") { - "aws.bedrock.agent_id" "agentId" + "aws.bedrock.agent.id" "agentId" } else if (service == "BedrockAgent" && operation == "GetKnowledgeBase") { - "aws.bedrock.knowledgebase_id" "knowledgeBaseId" + "aws.bedrock.knowledge_base.id" "knowledgeBaseId" } else if (service == "BedrockAgent" && operation == "GetDataSource") { - "aws.bedrock.datasource_id" "datasourceId" + "aws.bedrock.data_source.id" "datasourceId" } else if (service == "BedrockRuntime" && operation == "InvokeModel") { - "gen_ai.request.top_p" "0.9" - "gen_ai.request.temperature" "0.7" "gen_ai.request.model" "meta.llama2-13b-chat-v1" - "gen_ai.request.max_tokens" "100" - "gen_ai.system" "AWS Bedrock" - "gen_ai.response.finish_reasons" "length" + "gen_ai.system" "aws_bedrock" } } From d33e65fb262c9f0f791732479bfbfe7fbace3c2f Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Fri, 5 Jul 2024 19:31:18 +0000 Subject: [PATCH 10/13] Address comments. --- .../awssdk/v2_2/AwsExperimentalAttributes.java | 14 ++++++-------- .../instrumentation/awssdk/v2_2/FieldMapper.java | 1 - .../awssdk/v2_2/TracingExecutionInterceptor.java | 3 ++- 3 files changed, 8 insertions(+), 10 deletions(-) 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 index 35093b4746b9..855c107243bd 100644 --- 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 @@ -16,18 +16,16 @@ final class AwsExperimentalAttributes { static final AttributeKey AWS_STREAM_NAME = stringKey("aws.stream.name"); static final AttributeKey AWS_TABLE_NAME = stringKey("aws.table.name"); static final AttributeKey AWS_BEDROCK_GUARDRAIL_ID = - stringKey("aws.bedrock.guardrail_id"); - static final AttributeKey AWS_BEDROCK_AGENT_ID = stringKey("aws.bedrock.agent_id"); + stringKey("aws.bedrock.guardrail.id"); + static final AttributeKey AWS_BEDROCK_AGENT_ID = stringKey("aws.bedrock.agent.id"); static final AttributeKey AWS_BEDROCK_DATASOURCE_ID = - stringKey("aws.bedrock.data_source_id"); + stringKey("aws.bedrock.data_source.id"); static final AttributeKey AWS_BEDROCK_KNOWLEDGEBASE_ID = - stringKey("aws.bedrock.knowledge_base_id"); + stringKey("aws.bedrock.knowledge_base.id"); - // OTel GenAI/LLM group has defined gen_ai attributes but not yet add it in - // semantic-conventions-java package - // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-spans.md#genai-attributes - // TODO: Merge in these attributes in semantic-conventions-java package + // TODO: Merge in gen_ai attributes in opentelemetry-semconv-incubating once upgrade to v1.25.0 static final AttributeKey GEN_AI_MODEL = stringKey("gen_ai.request.model"); + static final AttributeKey GEN_AI_SYSTEM = stringKey("gen_ai.system"); private AwsExperimentalAttributes() {} } diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/FieldMapper.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/FieldMapper.java index 2487f9c86949..569d0eb5ae18 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/FieldMapper.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/FieldMapper.java @@ -67,7 +67,6 @@ private void mapToAttributes( } if (target != null) { String 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/TracingExecutionInterceptor.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java index 6748cb353878..058a21281ac7 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 @@ -5,6 +5,7 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; +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; @@ -320,7 +321,7 @@ private void populateRequestAttributes( } if (awsSdkRequest.type() == BEDROCKRUNTIME) { - span.setAttribute("gen_ai.system", "aws_bedrock"); + span.setAttribute(GEN_AI_SYSTEM.getKey(), "aws_bedrock"); } } From eb2f2d495a0272c2408a3a7411616d9a1bef26c6 Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Fri, 5 Jul 2024 20:51:22 +0000 Subject: [PATCH 11/13] Address comments. --- .../awssdk/v2_2/AwsExperimentalAttributes.java | 1 - .../awssdk/v2_2/TracingExecutionInterceptor.java | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 index 855c107243bd..a93fab2e6d8b 100644 --- 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 @@ -25,7 +25,6 @@ final class AwsExperimentalAttributes { // TODO: Merge in gen_ai attributes in opentelemetry-semconv-incubating once upgrade to v1.25.0 static final AttributeKey GEN_AI_MODEL = stringKey("gen_ai.request.model"); - static final AttributeKey GEN_AI_SYSTEM = stringKey("gen_ai.system"); private AwsExperimentalAttributes() {} } 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 058a21281ac7..ed0bda7a3541 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 @@ -5,7 +5,6 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; -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; @@ -44,6 +43,8 @@ /** AWS request execution interceptor. */ final class TracingExecutionInterceptor implements ExecutionInterceptor { + private static final AttributeKey GEN_AI_SYSTEM = AttributeKey.stringKey("gen_ai.system"); + 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 @@ -321,7 +322,7 @@ private void populateRequestAttributes( } if (awsSdkRequest.type() == BEDROCKRUNTIME) { - span.setAttribute(GEN_AI_SYSTEM.getKey(), "aws_bedrock"); + span.setAttribute(GEN_AI_SYSTEM, GEN_AI_SYSTEM_BEDROCK); } } From 99ec1afb0978109ae3585699d3027ad0e1a0e099 Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Fri, 5 Jul 2024 21:03:37 +0000 Subject: [PATCH 12/13] Use AwsExperimentalAttributes. --- .../instrumentation/awssdk/v2_2/AwsExperimentalAttributes.java | 1 + .../awssdk/v2_2/TracingExecutionInterceptor.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) 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 index a93fab2e6d8b..855c107243bd 100644 --- 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 @@ -25,6 +25,7 @@ final class AwsExperimentalAttributes { // TODO: Merge in gen_ai attributes in opentelemetry-semconv-incubating once upgrade to v1.25.0 static final AttributeKey GEN_AI_MODEL = stringKey("gen_ai.request.model"); + static final AttributeKey GEN_AI_SYSTEM = stringKey("gen_ai.system"); private AwsExperimentalAttributes() {} } 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 ed0bda7a3541..352b02093ef9 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 @@ -5,6 +5,7 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; +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; @@ -43,7 +44,6 @@ /** AWS request execution interceptor. */ final class TracingExecutionInterceptor implements ExecutionInterceptor { - private static final AttributeKey GEN_AI_SYSTEM = AttributeKey.stringKey("gen_ai.system"); 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 From c3de3f209fa122e66d34f685eaba7ec4efe9f3b8 Mon Sep 17 00:00:00 2001 From: Zhonghao Zhao Date: Fri, 5 Jul 2024 21:38:13 +0000 Subject: [PATCH 13/13] Change to 1.26.0 --- .../instrumentation/awssdk/v2_2/AwsExperimentalAttributes.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 855c107243bd..049410cec77a 100644 --- 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 @@ -23,7 +23,7 @@ final class AwsExperimentalAttributes { static final AttributeKey AWS_BEDROCK_KNOWLEDGEBASE_ID = stringKey("aws.bedrock.knowledge_base.id"); - // TODO: Merge in gen_ai attributes in opentelemetry-semconv-incubating once upgrade to v1.25.0 + // TODO: Merge in gen_ai attributes in opentelemetry-semconv-incubating once upgrade to v1.26.0 static final AttributeKey GEN_AI_MODEL = stringKey("gen_ai.request.model"); static final AttributeKey GEN_AI_SYSTEM = stringKey("gen_ai.system");