-
Notifications
You must be signed in to change notification settings - Fork 81
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add BusinessMetrics struct, Context extension for businessMetrics computed property, utility function for grabbing flags from config / context and saving them into context.businessMetrics. * Move AWSUserAgentMetadata construction from within generated UserAgentMiddlewrae initialization code, to the runtime UserAgentMiddleware code. This delays user agent struct initialization to right before the request is sent, and is done because we need access to the last-minute values in the context right before the request is sent, in order to grab all features used in request flow and put them in the business metrics section of the user agent. * Replace config metadata and feature metadata with business metrics. Refactor fromConfig() initializer wrapper to fromConfigAndContext(), now that business metrics needs values saved in context as well. * Remove config metadata and feature metadata code and tests. * Add UserAgetnValuesFromConfig class to act as container for subset of relevant values from config. Add unit tests for BusinessMetrics. * Update codegen tests with new UserAgentMiddleware init params * Refine comment for progress tracking in future --------- Co-authored-by: Sichan Yoo <[email protected]>
- Loading branch information
Showing
11 changed files
with
221 additions
and
139 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
Sources/Core/AWSClientRuntime/Sources/AWSClientRuntime/UserAgent/BusinessMetrics.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import ClientRuntime | ||
import class Smithy.Context | ||
import struct Smithy.AttributeKey | ||
|
||
struct BusinessMetrics { | ||
// Mapping of human readable feature ID to the corresponding metric value | ||
let features: [String: String] | ||
|
||
init( | ||
config: UserAgentValuesFromConfig, | ||
context: Context | ||
) { | ||
setFlagsIntoContext(config: config, context: context) | ||
self.features = context.businessMetrics | ||
} | ||
} | ||
|
||
extension BusinessMetrics: CustomStringConvertible { | ||
var description: String { | ||
var commaSeparatedMetricValues = features.values.sorted().joined(separator: ",") | ||
// Cut last metric value from string until the | ||
// comma-separated list of metric values are at or below 1024 bytes in size | ||
if commaSeparatedMetricValues.lengthOfBytes(using: .ascii) > 1024 { | ||
while commaSeparatedMetricValues.lengthOfBytes(using: .ascii) > 1024 { | ||
commaSeparatedMetricValues = commaSeparatedMetricValues.substringBeforeLast(",") | ||
} | ||
} | ||
return "m/\(commaSeparatedMetricValues)" | ||
} | ||
} | ||
|
||
private extension String { | ||
func substringBeforeLast(_ separator: String) -> String { | ||
if let range = self.range(of: separator, options: .backwards) { | ||
return String(self[..<range.lowerBound]) | ||
} else { | ||
return self | ||
} | ||
} | ||
} | ||
|
||
public extension Context { | ||
var businessMetrics: Dictionary<String, String> { | ||
get { attributes.get(key: businessMetricsKey) ?? [:] } | ||
set(newPair) { | ||
var combined = businessMetrics | ||
combined.merge(newPair) { (current, new) in new } | ||
attributes.set(key: businessMetricsKey, value: combined) | ||
} | ||
} | ||
} | ||
|
||
public let businessMetricsKey = AttributeKey<Dictionary<String, String>>(name: "BusinessMetrics") | ||
|
||
/* List of readable "feature ID" to "metric value"; last updated on 08/19/2024 | ||
[Feature ID] [Metric Value] [Flag Supported] | ||
"RESOURCE_MODEL" : "A" : | ||
"WAITER" : "B" : | ||
"PAGINATOR" : "C" : | ||
"RETRY_MODE_LEGACY" : "D" : Y | ||
"RETRY_MODE_STANDARD" : "E" : Y | ||
"RETRY_MODE_ADAPTIVE" : "F" : Y | ||
"S3_TRANSFER" : "G" : | ||
"S3_CRYPTO_V1N" : "H" : | ||
"S3_CRYPTO_V2" : "I" : | ||
"S3_EXPRESS_BUCKET" : "J" : | ||
"S3_ACCESS_GRANTS" : "K" : | ||
"GZIP_REQUEST_COMPRESSION" : "L" : | ||
"PROTOCOL_RPC_V2_CBOR" : "M" : | ||
"ENDPOINT_OVERRIDE" : "N" : Y | ||
"ACCOUNT_ID_ENDPOINT" : "O" : | ||
"ACCOUNT_ID_MODE_PREFERRED" : "P" : | ||
"ACCOUNT_ID_MODE_DISABLED" : "Q" : | ||
"ACCOUNT_ID_MODE_REQUIRED" : "R" : | ||
"SIGV4A_SIGNING" : "S" : Y | ||
"RESOLVED_ACCOUNT_ID" : "T" : | ||
*/ | ||
fileprivate func setFlagsIntoContext( | ||
config: UserAgentValuesFromConfig, | ||
context: Context | ||
) { | ||
// Handle D, E, F | ||
switch config.awsRetryMode { | ||
case .legacy: | ||
context.businessMetrics = ["RETRY_MODE_LEGACY": "D"] | ||
case .standard: | ||
context.businessMetrics = ["RETRY_MODE_STANDARD": "E"] | ||
case .adaptive: | ||
context.businessMetrics = ["RETRY_MODE_ADAPTIVE": "F"] | ||
} | ||
// Handle N | ||
if let endpoint = config.endpoint, !endpoint.isEmpty { | ||
context.businessMetrics = ["ENDPOINT_OVERRIDE": "N"] | ||
} | ||
// Handle S | ||
if context.selectedAuthScheme?.schemeID == "aws.auth#sigv4a" { | ||
context.businessMetrics = ["SIGV4A_SIGNING": "S"] | ||
} | ||
} |
24 changes: 0 additions & 24 deletions
24
Sources/Core/AWSClientRuntime/Sources/AWSClientRuntime/UserAgent/ConfigMetadata.swift
This file was deleted.
Oops, something went wrong.
29 changes: 0 additions & 29 deletions
29
Sources/Core/AWSClientRuntime/Sources/AWSClientRuntime/UserAgent/FeatureMetadata.swift
This file was deleted.
Oops, something went wrong.
60 changes: 60 additions & 0 deletions
60
...es/Core/AWSClientRuntime/Tests/AWSClientRuntimeTests/UserAgent/BusinessMetricsTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import XCTest | ||
import ClientRuntime | ||
@testable import AWSClientRuntime | ||
import SmithyRetriesAPI | ||
import SmithyHTTPAuthAPI | ||
import SmithyIdentity | ||
import SmithyRetriesAPI | ||
import Smithy | ||
|
||
class BusinessMetricsTests: XCTestCase { | ||
var context: Context! | ||
|
||
override func setUp() async throws { | ||
context = Context(attributes: Attributes()) | ||
} | ||
|
||
func test_business_metrics_section_truncation() { | ||
context.businessMetrics = ["SHORT_FILLER": "A"] | ||
let longMetricValue = String(repeating: "F", count: 1025) | ||
context.businessMetrics = ["LONG_FILLER": longMetricValue] | ||
let userAgent = AWSUserAgentMetadata.fromConfigAndContext( | ||
serviceID: "test", | ||
version: "1.0", | ||
config: UserAgentValuesFromConfig(appID: nil, endpoint: nil, awsRetryMode: .standard), | ||
context: context | ||
) | ||
// Assert values in context match with values assigned to user agent | ||
XCTAssertEqual(userAgent.businessMetrics?.features, context.businessMetrics) | ||
// Assert string gets truncated successfully | ||
let expectedTruncatedString = "m/A,E" | ||
XCTAssertEqual(userAgent.businessMetrics?.description, expectedTruncatedString) | ||
} | ||
|
||
func test_multiple_flags_in_context() { | ||
context.businessMetrics = ["FIRST": "A"] | ||
context.businessMetrics = ["SECOND": "B"] | ||
context.setSelectedAuthScheme(SelectedAuthScheme( // S | ||
schemeID: "aws.auth#sigv4a", | ||
identity: nil, | ||
signingProperties: nil, | ||
signer: nil | ||
)) | ||
let userAgent = AWSUserAgentMetadata.fromConfigAndContext( | ||
serviceID: "test", | ||
version: "1.0", | ||
config: UserAgentValuesFromConfig(appID: nil, endpoint: "test-endpoint", awsRetryMode: .adaptive), | ||
context: context | ||
) | ||
// F comes from retry mode being adaptive & N comes from endpoint override | ||
let expectedString = "m/A,B,F,N,S" | ||
XCTAssertEqual(userAgent.businessMetrics?.description, expectedString) | ||
} | ||
} |
Oops, something went wrong.