Skip to content

Commit

Permalink
add tracking for checksum algorithm and retry mode business metrics (#…
Browse files Browse the repository at this point in the history
…3944)

Adds business metric tracking for checksum algorithms and retry modes.
This PR includes tests.


----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._
  • Loading branch information
Velfi authored Dec 18, 2024
1 parent 9b2236a commit b9458df
Show file tree
Hide file tree
Showing 14 changed files with 368 additions and 112 deletions.
8 changes: 4 additions & 4 deletions aws/rust-runtime/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions aws/rust-runtime/aws-config/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion aws/rust-runtime/aws-runtime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "aws-runtime"
version = "1.5.1"
version = "1.5.2"
authors = ["AWS Rust SDK Team <[email protected]>"]
description = "Runtime support code for the AWS SDK. This crate isn't intended to be used directly."
edition = "2021"
Expand Down
44 changes: 41 additions & 3 deletions aws/rust-runtime/aws-runtime/src/user_agent/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,16 @@ iterable_enum!(
AccountIdModeDisabled,
AccountIdModeRequired,
Sigv4aSigning,
ResolvedAccountId
ResolvedAccountId,
FlexibleChecksumsReqCrc32,
FlexibleChecksumsReqCrc32c,
FlexibleChecksumsReqCrc64,
FlexibleChecksumsReqSha1,
FlexibleChecksumsReqSha256,
FlexibleChecksumsReqWhenSupported,
FlexibleChecksumsReqWhenRequired,
FlexibleChecksumsResWhenSupported,
FlexibleChecksumsResWhenRequired
);

pub(crate) trait ProvideBusinessMetric {
Expand All @@ -142,6 +151,25 @@ impl ProvideBusinessMetric for SmithySdkFeature {
Paginator => Some(BusinessMetric::Paginator),
GzipRequestCompression => Some(BusinessMetric::GzipRequestCompression),
ProtocolRpcV2Cbor => Some(BusinessMetric::ProtocolRpcV2Cbor),
RetryModeStandard => Some(BusinessMetric::RetryModeStandard),
RetryModeAdaptive => Some(BusinessMetric::RetryModeAdaptive),
FlexibleChecksumsReqCrc32 => Some(BusinessMetric::FlexibleChecksumsReqCrc32),
FlexibleChecksumsReqCrc32c => Some(BusinessMetric::FlexibleChecksumsReqCrc32c),
FlexibleChecksumsReqCrc64 => Some(BusinessMetric::FlexibleChecksumsReqCrc64),
FlexibleChecksumsReqSha1 => Some(BusinessMetric::FlexibleChecksumsReqSha1),
FlexibleChecksumsReqSha256 => Some(BusinessMetric::FlexibleChecksumsReqSha256),
FlexibleChecksumsReqWhenSupported => {
Some(BusinessMetric::FlexibleChecksumsReqWhenSupported)
}
FlexibleChecksumsReqWhenRequired => {
Some(BusinessMetric::FlexibleChecksumsReqWhenRequired)
}
FlexibleChecksumsResWhenSupported => {
Some(BusinessMetric::FlexibleChecksumsResWhenSupported)
}
FlexibleChecksumsResWhenRequired => {
Some(BusinessMetric::FlexibleChecksumsResWhenRequired)
}
otherwise => {
// This may occur if a customer upgrades only the `aws-smithy-runtime-api` crate
// while continuing to use an outdated version of an SDK crate or the `aws-runtime`
Expand Down Expand Up @@ -260,16 +288,26 @@ mod tests {
"ACCOUNT_ID_MODE_DISABLED": "Q",
"ACCOUNT_ID_MODE_REQUIRED": "R",
"SIGV4A_SIGNING": "S",
"RESOLVED_ACCOUNT_ID": "T"
"RESOLVED_ACCOUNT_ID": "T",
"FLEXIBLE_CHECKSUMS_REQ_CRC32" : "U",
"FLEXIBLE_CHECKSUMS_REQ_CRC32C" : "V",
"FLEXIBLE_CHECKSUMS_REQ_CRC64" : "W",
"FLEXIBLE_CHECKSUMS_REQ_SHA1" : "X",
"FLEXIBLE_CHECKSUMS_REQ_SHA256" : "Y",
"FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED" : "Z",
"FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED" : "a",
"FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED" : "b",
"FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED" : "c"
}
"#;

let expected: HashMap<&str, &str> = serde_json::from_str(EXPECTED).unwrap();
assert_eq!(expected.len(), FEATURE_ID_TO_METRIC_VALUE.len());

for (feature_id, metric_value) in &*FEATURE_ID_TO_METRIC_VALUE {
let expected = expected.get(format!("{feature_id}").as_str());
assert_eq!(
expected.get(format!("{feature_id}").as_str()).unwrap(),
expected.expect(&format!("Expected {feature_id} to have value `{metric_value}` but it was `{expected:?}` instead.")),
metric_value,
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ internal fun RuntimeConfig.awsInlineableHttpRequestChecksum() =
CargoDependency.smithyHttp(this),
CargoDependency.smithyRuntimeApiClient(this),
CargoDependency.smithyTypes(this),
CargoDependency.TempFile,
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package software.amazon.smithy.rustsdk

import org.junit.jupiter.api.Test
import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency
import software.amazon.smithy.rust.codegen.core.rustlang.rust
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
Expand Down Expand Up @@ -176,9 +177,7 @@ class UserAgentDecoratorTest {
val moduleName = ctx.moduleUseName()
rustTemplate(
"""
use $moduleName::config::{
Region,
};
use $moduleName::config::Region;
use $moduleName::{Client, Config};
let (http_client, rcvr) = #{capture_request}(#{None});
Expand All @@ -197,7 +196,126 @@ class UserAgentDecoratorTest {
#{assert_ua_contains_metric_values}(user_agent, &["M"]);
""",
*preludeScope,
"assert_ua_contains_metric_values" to AwsRuntimeType.awsRuntimeTestUtil(rc).resolve("user_agent::test_util::assert_ua_contains_metric_values"),
"assert_ua_contains_metric_values" to
AwsRuntimeType.awsRuntimeTestUtil(rc)
.resolve("user_agent::test_util::assert_ua_contains_metric_values"),
"capture_request" to RuntimeType.captureRequest(rc),
"disable_interceptor" to
RuntimeType.smithyRuntimeApiClient(rc)
.resolve("client::interceptors::disable_interceptor"),
"UserAgentInterceptor" to
AwsRuntimeType.awsRuntime(rc)
.resolve("user_agent::UserAgentInterceptor"),
)
}
}
}
}

@Test
fun `it emits business metrics for retry modes`() {
val model =
"""
namespace test
use aws.auth#sigv4
use aws.api#service
use aws.protocols#restJson1
use smithy.rules#endpointRuleSet
@auth([sigv4])
@sigv4(name: "dontcare")
@endpointRuleSet({
"version": "1.0",
"rules": [{ "type": "endpoint", "conditions": [], "endpoint": { "url": "https://example.com" } }],
"parameters": {}
})
@service(sdkId: "dontcare")
@restJson1
service TestService { version: "2023-01-01", operations: [SomeOperation] }
@http(uri: "/SomeOperation", method: "GET")
@optionalAuth
operation SomeOperation {
input: SomeInput,
output: SomeOutput
}
@input
structure SomeInput {}
@output
structure SomeOutput {}
""".asSmithyModel()

awsSdkIntegrationTest(model) { ctx, rustCrate ->
rustCrate.integrationTest("retry_mode_feature_tracker") {
val rc = ctx.runtimeConfig
val moduleName = ctx.moduleUseName()

rust(
"""
use $moduleName::config::{Region, retry::RetryConfig};
use $moduleName::{Client, Config};
""",
)

tokioTest("should_emit_metric_in_user_agent_standard_mode") {
rustTemplate(
"""
let (http_client, rcvr) = #{capture_request}(#{None});
let config = Config::builder()
.region(Region::new("us-east-1"))
.http_client(http_client.clone())
.retry_config(RetryConfig::standard())
.with_test_defaults()
.build();
let client = Client::from_conf(config);
let _ = client.some_operation().send().await;
let expected_req = rcvr.expect_request();
let user_agent = expected_req
.headers()
.get("x-amz-user-agent")
.unwrap();
#{assert_ua_contains_metric_values}(user_agent, &["E"]);
""",
*preludeScope,
"assert_ua_contains_metric_values" to
AwsRuntimeType.awsRuntimeTestUtil(rc)
.resolve("user_agent::test_util::assert_ua_contains_metric_values"),
"capture_request" to RuntimeType.captureRequest(rc),
"disable_interceptor" to
RuntimeType.smithyRuntimeApiClient(rc)
.resolve("client::interceptors::disable_interceptor"),
"UserAgentInterceptor" to
AwsRuntimeType.awsRuntime(rc)
.resolve("user_agent::UserAgentInterceptor"),
)
}

tokioTest("should_emit_metric_in_user_agent_adaptive_mode") {
rustTemplate(
"""
let (http_client, rcvr) = #{capture_request}(#{None});
let config = Config::builder()
.region(Region::new("us-east-1"))
.http_client(http_client.clone())
.retry_config(RetryConfig::adaptive())
.with_test_defaults()
.build();
let client = Client::from_conf(config);
let _ = client.some_operation().send().await;
let expected_req = rcvr.expect_request();
let user_agent = expected_req
.headers()
.get("x-amz-user-agent")
.unwrap();
#{assert_ua_contains_metric_values}(user_agent, &["F"]);
""",
*preludeScope,
"assert_ua_contains_metric_values" to
AwsRuntimeType.awsRuntimeTestUtil(rc)
.resolve("user_agent::test_util::assert_ua_contains_metric_values"),
"capture_request" to RuntimeType.captureRequest(rc),
"disable_interceptor" to
RuntimeType.smithyRuntimeApiClient(rc)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.rust.codegen.client.smithy.customizations

import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization
import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginSection
import software.amazon.smithy.rust.codegen.core.rustlang.InlineDependency
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
import software.amazon.smithy.rust.codegen.core.rustlang.rust
import software.amazon.smithy.rust.codegen.core.rustlang.writable
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType

class RetryModeFeatureTrackerRuntimePluginCustomization(codegenContext: ClientCodegenContext) :
ServiceRuntimePluginCustomization() {
private val runtimeConfig = codegenContext.runtimeConfig

override fun section(section: ServiceRuntimePluginSection): Writable =
writable {
when (section) {
is ServiceRuntimePluginSection.RegisterRuntimeComponents -> {
section.registerInterceptor(this) {
rust(
"#T::new()",
RuntimeType.forInlineDependency(
InlineDependency.sdkFeatureTracker(runtimeConfig),
).resolve("retry_mode::RetryModeFeatureTrackerInterceptor"),
)
}
}

else -> emptySection
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import software.amazon.smithy.rust.codegen.client.smithy.customizations.Resilien
import software.amazon.smithy.rust.codegen.client.smithy.customizations.RetryClassifierConfigCustomization
import software.amazon.smithy.rust.codegen.client.smithy.customizations.RetryClassifierOperationCustomization
import software.amazon.smithy.rust.codegen.client.smithy.customizations.RetryClassifierServiceRuntimePluginCustomization
import software.amazon.smithy.rust.codegen.client.smithy.customizations.RetryModeFeatureTrackerRuntimePluginCustomization
import software.amazon.smithy.rust.codegen.client.smithy.customizations.TimeSourceCustomization
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization
import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization
Expand Down Expand Up @@ -134,5 +135,6 @@ class RequiredCustomizations : ClientCodegenDecorator {
): List<ServiceRuntimePluginCustomization> =
baseCustomizations +
ConnectionPoisoningRuntimePluginCustomization(codegenContext) +
RetryClassifierServiceRuntimePluginCustomization(codegenContext)
RetryClassifierServiceRuntimePluginCustomization(codegenContext) +
RetryModeFeatureTrackerRuntimePluginCustomization(codegenContext)
}
Loading

0 comments on commit b9458df

Please sign in to comment.