Skip to content

Commit

Permalink
feat: Add auto-instrumentation support for Step Functions, SNS, Secre… (
Browse files Browse the repository at this point in the history
#899)

### *Description of changes:*

Changes in ADOT package to support new AWS resources in Java V1 & V2
SDKs.

Related changes for V1 SDK in upstream package:
mxiamxia/opentelemetry-java-instrumentation#11

Related changes for V2 SDK in upstream package:
mxiamxia/opentelemetry-java-instrumentation#12

These changes add auto-instrumentation support for the following AWS
resources. Additionally, a new attribute for
`aws.remote.resource.cfn.primary.identifier` is also added for each new
resource.

- Populate `aws.sns.topic.arn` in Span by extracting `TopicArn` from the
request body.

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sns-topic.html
  - The CFN Id should be the ARN of the Topic.
- Populate `aws.secretsmanager.secret.arn` in Span by extracting `ARN`
from response body.

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-secretsmanager-secret.html
  - The CFN Id should be the ARN of the Secret.
- Populate `aws.stepfunctions.state_machine.arn` in Span by extracting
`stateMachineArn` from the request body.

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-statemachine.html
  - The CFN Id should be the ARN of the State Machine.
- Populate `aws.stepfunctions.activity.arn` in Span by extracting
`activityArn` from the request body.

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-stepfunctions-activity.html
  - The CFN Id should be the ARN of the Activity.
- Populate `aws.lambda.function.name` in Span by extracting
`FunctionName` from the request body.

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html
  - The CFN Id should be the ARN of the Lambda Function.
- Populate `aws.lambda.resource_mapping.id` in Span by extracting `UUID`
from the request body.

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html
  - The CFN Id should be the UUID of the Event Source Mapping.

### *Test Plan:*
Set up a client-server with auto-instrumentation to verify that the
correct span data is being generated.

Note: V1 span data is top pic and V2 span data is bottom pic for each
resource.

`aws.lambda.function.name`
<img width="1512" alt="lambda-function-name-span-data-verification-v1"
src="https://github.com/user-attachments/assets/ecc6780e-546b-4776-a916-16cac97863ec">
<img width="1512" alt="lambda-function-name-span-data-verification-v2"
src="https://github.com/user-attachments/assets/eb4d288d-dbb4-4dd1-9562-abea8ec91937">

`aws.lambda.resource_mapping.id`
<img width="1512"
alt="lambda-resource-mapping-id-span-data-verification-v1"
src="https://github.com/user-attachments/assets/5059000a-ef5a-4eec-a0d8-e2e63c144ff3">
<img width="1512"
alt="lambda-resource-mapping-id-span-data-verification-v2"
src="https://github.com/user-attachments/assets/54fea71d-05bc-40ac-98b8-5e4d49b0d391">

`aws.secretsmanager.secret.arn`
<img width="1512"
alt="secretsmanager-secret-arn-span-data-verification-v1"
src="https://github.com/user-attachments/assets/e0cf9fcb-1d99-4ed9-bf33-f9e04c4ad352">
<img width="1512"
alt="secretsmanager-secret-arn-span-data-verification-v2"
src="https://github.com/user-attachments/assets/2db81495-d8a7-43cf-a616-4cbe6bd3d3f8">

`aws.sns.topic.arn`
<img width="1512" alt="sns-topic-arn-span-data-verification-v1"
src="https://github.com/user-attachments/assets/cc000f1f-ded7-4d02-98e6-545583f47e5e">
<img width="1512" alt="sns-topic-arn-span-data-verification-v2"
src="https://github.com/user-attachments/assets/666fcfd2-045a-4a0a-a5c2-662bcaa60e41">

`aws.stepfunctions.activity.arn`
<img width="1512"
alt="stepfunctions-activity-arn-span-data-verification-v1"
src="https://github.com/user-attachments/assets/e3ade244-eb1e-4f5c-9878-5c78ee4f2a32">
<img width="1512" alt="sfn-activity-arn-span-data-verification-v2"
src="https://github.com/user-attachments/assets/89814a71-bbac-4026-b4e1-591f767e3a13">

`aws.stepfunction.state_machine.arn`
<img width="1512"
alt="stepfunctions-state-machine-arn-span-data-verification-v1"
src="https://github.com/user-attachments/assets/91670d86-a726-472a-8f0f-b156cd68ef63">
<img width="1512" alt="sfn-state-machine-arn-span-data-verification-v2"
src="https://github.com/user-attachments/assets/70f59b80-af4c-400d-84e5-35fd06eef20e">

Metric Attribute Generator Unit Test
<img width="1512" alt="Screenshot 2024-10-02 at 2 59 35 PM"
src="https://github.com/user-attachments/assets/fadf5ec5-dba3-46a4-abdd-d8cd9ab56cc5">


By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license.
  • Loading branch information
yiyuan-he authored Oct 9, 2024
1 parent 47ce3b1 commit cb31105
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 0 deletions.
2 changes: 2 additions & 0 deletions awsagentprovider/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ dependencies {
implementation("io.opentelemetry.contrib:opentelemetry-aws-resources")
// Json file reader
implementation("com.fasterxml.jackson.core:jackson-databind:2.16.1")
// Import AWS SDK v1 core for ARN parsing utilities
implementation("com.amazonaws:aws-java-sdk-core:1.12.773")
// Export configuration
compileOnly("io.opentelemetry:opentelemetry-exporter-otlp")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ private AwsAttributeKeys() {}
static final AttributeKey<String> AWS_REMOTE_RESOURCE_IDENTIFIER =
AttributeKey.stringKey("aws.remote.resource.identifier");

static final AttributeKey<String> AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER =
AttributeKey.stringKey("aws.remote.resource.cfn.primary.identifier");

static final AttributeKey<String> AWS_REMOTE_RESOURCE_TYPE =
AttributeKey.stringKey("aws.remote.resource.type");

Expand All @@ -50,6 +53,26 @@ private AwsAttributeKeys() {}
static final AttributeKey<String> AWS_CONSUMER_PARENT_SPAN_KIND =
AttributeKey.stringKey("aws.consumer.parent.span.kind");

static final AttributeKey<String> AWS_STATE_MACHINE_ARN =
AttributeKey.stringKey("aws.stepfunctions.state_machine.arn");

static final AttributeKey<String> AWS_STEP_FUNCTIONS_ACTIVITY_ARN =
AttributeKey.stringKey("aws.stepfunctions.activity.arn");

static final AttributeKey<String> AWS_SNS_TOPIC_ARN = AttributeKey.stringKey("aws.sns.topic.arn");

static final AttributeKey<String> AWS_SECRET_ARN =
AttributeKey.stringKey("aws.secretsmanager.secret.arn");

static final AttributeKey<String> AWS_LAMBDA_NAME =
AttributeKey.stringKey("aws.lambda.function.name");

static final AttributeKey<String> AWS_LAMBDA_ARN =
AttributeKey.stringKey("aws.lambda.function.arn");

static final AttributeKey<String> AWS_LAMBDA_RESOURCE_ID =
AttributeKey.stringKey("aws.lambda.resource_mapping.id");

// use the same AWS Resource attribute name defined by OTel java auto-instr for aws_sdk_v_1_1
// TODO: all AWS specific attributes should be defined in semconv package and reused cross all
// otel packages. Related sim -
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@
import static io.opentelemetry.semconv.SemanticAttributes.SERVER_SOCKET_PORT;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_AGENT_ID;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_BUCKET_NAME;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_DATA_SOURCE_ID;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_GUARDRAIL_ID;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_KNOWLEDGE_BASE_ID;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LAMBDA_NAME;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LAMBDA_RESOURCE_ID;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_OPERATION;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_SERVICE;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_QUEUE_NAME;
Expand All @@ -54,7 +57,11 @@
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_RESOURCE_IDENTIFIER;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_RESOURCE_TYPE;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_SERVICE;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SECRET_ARN;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SNS_TOPIC_ARN;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SPAN_KIND;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_STATE_MACHINE_ARN;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_STEP_FUNCTIONS_ACTIVITY_ARN;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_STREAM_NAME;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_TABLE_NAME;
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.GEN_AI_REQUEST_MODEL;
Expand All @@ -67,6 +74,7 @@
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isDBSpan;
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isKeyPresent;

import com.amazonaws.arn.Arn;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
Expand Down Expand Up @@ -111,6 +119,10 @@ final class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
private static final String NORMALIZED_SQS_SERVICE_NAME = "AWS::SQS";
private static final String NORMALIZED_BEDROCK_SERVICE_NAME = "AWS::Bedrock";
private static final String NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME = "AWS::BedrockRuntime";
private static final String NORMALIZED_STEPFUNCTIONS_SERVICE_NAME = "AWS::StepFunctions";
private static final String NORMALIZED_SNS_SERVICE_NAME = "AWS::SNS";
private static final String NORMALIZED_SECRETSMANAGER_SERVICE_NAME = "AWS::SecretsManager";
private static final String NORMALIZED_LAMBDA_SERVICE_NAME = "AWS::Lambda";

// Special DEPENDENCY attribute value if GRAPHQL_OPERATION_TYPE attribute key is present.
private static final String GRAPHQL = "graphql";
Expand Down Expand Up @@ -371,6 +383,18 @@ private static String normalizeRemoteServiceName(SpanData span, String serviceNa
case "AmazonBedrockRuntime": // AWS SDK v1
case "BedrockRuntime": // AWS SDK v2
return NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME;
case "AWSStepFunctions": // AWS SDK v1
case "Sfn": // AWS SDK v2
return NORMALIZED_STEPFUNCTIONS_SERVICE_NAME;
case "AmazonSNS":
case "Sns":
return NORMALIZED_SNS_SERVICE_NAME;
case "AWSSecretsManager": // AWS SDK v1
case "SecretsManager": // AWS SDK v2
return NORMALIZED_SECRETSMANAGER_SERVICE_NAME;
case "AWSLambda": // AWS SDK v1
case "Lambda": // AWS SDK v2
return NORMALIZED_LAMBDA_SERVICE_NAME;
default:
return "AWS::" + serviceName;
}
Expand All @@ -392,6 +416,7 @@ private static String normalizeRemoteServiceName(SpanData span, String serviceNa
private static void setRemoteResourceTypeAndIdentifier(SpanData span, AttributesBuilder builder) {
Optional<String> remoteResourceType = Optional.empty();
Optional<String> remoteResourceIdentifier = Optional.empty();
Optional<String> cloudformationPrimaryIdentifier = Optional.empty();

if (isAwsSDKSpan(span)) {
if (isKeyPresent(span, AWS_TABLE_NAME)) {
Expand Down Expand Up @@ -434,18 +459,88 @@ private static void setRemoteResourceTypeAndIdentifier(SpanData span, Attributes
remoteResourceType = Optional.of(NORMALIZED_BEDROCK_SERVICE_NAME + "::Model");
remoteResourceIdentifier =
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(GEN_AI_REQUEST_MODEL)));
} else if (isKeyPresent(span, AWS_STATE_MACHINE_ARN)) {
remoteResourceType = Optional.of(NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + "::StateMachine");
remoteResourceIdentifier =
getSfnResourceNameFromArn(
Optional.ofNullable(
escapeDelimiters(span.getAttributes().get(AWS_STATE_MACHINE_ARN))));
cloudformationPrimaryIdentifier =
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_STATE_MACHINE_ARN)));
} else if (isKeyPresent(span, AWS_STEP_FUNCTIONS_ACTIVITY_ARN)) {
remoteResourceType = Optional.of(NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + "::Activity");
remoteResourceIdentifier =
getSfnResourceNameFromArn(
Optional.ofNullable(
escapeDelimiters(span.getAttributes().get(AWS_STEP_FUNCTIONS_ACTIVITY_ARN))));
cloudformationPrimaryIdentifier =
Optional.ofNullable(
escapeDelimiters(span.getAttributes().get(AWS_STEP_FUNCTIONS_ACTIVITY_ARN)));
} else if (isKeyPresent(span, AWS_SNS_TOPIC_ARN)) {
remoteResourceType = Optional.of(NORMALIZED_SNS_SERVICE_NAME + "::Topic");
remoteResourceIdentifier =
getSnsResourceNameFromArn(
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_SNS_TOPIC_ARN))));
cloudformationPrimaryIdentifier =
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_SNS_TOPIC_ARN)));
} else if (isKeyPresent(span, AWS_SECRET_ARN)) {
remoteResourceType = Optional.of(NORMALIZED_SECRETSMANAGER_SERVICE_NAME + "::Secret");
remoteResourceIdentifier =
getSecretsManagerResourceNameFromArn(
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_SECRET_ARN))));
cloudformationPrimaryIdentifier =
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_SECRET_ARN)));
} else if (isKeyPresent(span, AWS_LAMBDA_NAME)) {
remoteResourceType = Optional.of(NORMALIZED_LAMBDA_SERVICE_NAME + "::Function");
remoteResourceIdentifier =
getLambdaResourceNameFromAribitraryName(
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_LAMBDA_NAME))));
} else if (isKeyPresent(span, AWS_LAMBDA_RESOURCE_ID)) {
remoteResourceType = Optional.of(NORMALIZED_LAMBDA_SERVICE_NAME + "::EventSourceMapping");
remoteResourceIdentifier =
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_LAMBDA_RESOURCE_ID)));
}
} else if (isDBSpan(span)) {
remoteResourceType = Optional.of(DB_CONNECTION_RESOURCE_TYPE);
remoteResourceIdentifier = getDbConnection(span);
}

if (cloudformationPrimaryIdentifier.isEmpty()) {
cloudformationPrimaryIdentifier = remoteResourceIdentifier;
}

if (remoteResourceType.isPresent() && remoteResourceIdentifier.isPresent()) {
builder.put(AWS_REMOTE_RESOURCE_TYPE, remoteResourceType.get());
builder.put(AWS_REMOTE_RESOURCE_IDENTIFIER, remoteResourceIdentifier.get());
builder.put(AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER, cloudformationPrimaryIdentifier.get());
}
}

// NOTE: "name" in this case can be either the lambda name or lambda arn
private static Optional<String> getLambdaResourceNameFromAribitraryName(
Optional<String> arbitraryName) {
if (arbitraryName != null && arbitraryName.get().startsWith("arn:aws:lambda:")) {
Arn resourceArn = Arn.fromString(arbitraryName.get());
return Optional.of(resourceArn.getResource().toString().split(":")[1]);
}
return arbitraryName;
}

private static Optional<String> getSecretsManagerResourceNameFromArn(Optional<String> stringArn) {
Arn resourceArn = Arn.fromString(stringArn.get());
return Optional.of(resourceArn.getResource().toString().split(":")[1]);
}

private static Optional<String> getSfnResourceNameFromArn(Optional<String> stringArn) {
Arn resourceArn = Arn.fromString(stringArn.get());
return Optional.of(resourceArn.getResource().toString().split(":")[1]);
}

private static Optional<String> getSnsResourceNameFromArn(Optional<String> stringArn) {
Arn resourceArn = Arn.fromString(stringArn.get());
return Optional.of(resourceArn.getResource().toString());
}

/**
* RemoteResourceIdentifier is populated with rule <code>
* ^[{db.name}|]?{address}[|{port}]?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_DATA_SOURCE_ID;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_GUARDRAIL_ID;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_KNOWLEDGE_BASE_ID;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LAMBDA_NAME;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LAMBDA_RESOURCE_ID;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_OPERATION;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_SERVICE;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_QUEUE_NAME;
Expand All @@ -35,7 +37,11 @@
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_RESOURCE_IDENTIFIER;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_RESOURCE_TYPE;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_SERVICE;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SECRET_ARN;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SNS_TOPIC_ARN;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SPAN_KIND;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_STATE_MACHINE_ARN;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_STEP_FUNCTIONS_ACTIVITY_ARN;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_STREAM_NAME;
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_TABLE_NAME;
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.GEN_AI_REQUEST_MODEL;
Expand Down Expand Up @@ -770,6 +776,42 @@ public void testSdkClientSpanWithRemoteResourceAttributes() {
mockAttribute(GEN_AI_REQUEST_MODEL, "test.service_^id");
validateRemoteResourceAttributes("AWS::Bedrock::Model", "test.service_^^id");
mockAttribute(GEN_AI_REQUEST_MODEL, null);

// Validate behaviour of AWS_STATE_MACHINE_ARN attribute, then remove it.
mockAttribute(
AWS_STATE_MACHINE_ARN,
"arn:aws:states:us-east-1:123456789012:stateMachine:test_state_machine");
validateRemoteResourceAttributes("AWS::StepFunctions::StateMachine", "test_state_machine");
mockAttribute(AWS_STATE_MACHINE_ARN, null);

// Validate behaviour of AWS_STEPFUNCTIONS_ACTIVITY_ARN, then remove it.
mockAttribute(
AWS_STEP_FUNCTIONS_ACTIVITY_ARN,
"arn:aws:states:us-east-1:007003123456789012:activity:testActivity");
validateRemoteResourceAttributes("AWS::StepFunctions::Activity", "testActivity");
mockAttribute(AWS_STEP_FUNCTIONS_ACTIVITY_ARN, null);

// Validate behaviour of AWS_SNS_TOPIC_ARN, then remove it.
mockAttribute(AWS_SNS_TOPIC_ARN, "arn:aws:sns:us-west-2:012345678901:testTopic");
validateRemoteResourceAttributes("AWS::SNS::Topic", "testTopic");
mockAttribute(AWS_SNS_TOPIC_ARN, null);

// Validate behaviour of AWS_SECRET_ARN, then remove it.
mockAttribute(
AWS_SECRET_ARN, "arn:aws:secretsmanager:us-east-1:123456789012:secret:secretName");
validateRemoteResourceAttributes("AWS::SecretsManager::Secret", "secretName");
mockAttribute(AWS_SECRET_ARN, null);

// Validate behaviour of AWS_LAMBDA_NAME, then remove it.
mockAttribute(AWS_LAMBDA_NAME, "arn:aws:lambda:us-east-1:123456789012:function:functionName");
validateRemoteResourceAttributes("AWS::Lambda::Function", "functionName");
mockAttribute(AWS_LAMBDA_NAME, null);

// Validate behaviour of AWS_LAMBDA_RESOURCE_ID
mockAttribute(AWS_LAMBDA_RESOURCE_ID, "eventSourceId");
validateRemoteResourceAttributes("AWS::Lambda::EventSourceMapping", "eventSourceId");
mockAttribute(AWS_LAMBDA_RESOURCE_ID, null);

mockAttribute(RPC_SYSTEM, "null");
}

Expand Down Expand Up @@ -1175,6 +1217,7 @@ public void testNormalizeRemoteServiceName_AwsSdk() {
testAwsSdkServiceNormalization("AWSBedrockAgentRuntime", "AWS::Bedrock");
testAwsSdkServiceNormalization("AWSBedrockAgent", "AWS::Bedrock");
testAwsSdkServiceNormalization("AmazonBedrockRuntime", "AWS::BedrockRuntime");
testAwsSdkServiceNormalization("AWSStepFunctions", "AWS::StepFunctions");

// AWS SDK V2
testAwsSdkServiceNormalization("DynamoDb", "AWS::DynamoDB");
Expand Down

0 comments on commit cb31105

Please sign in to comment.