diff --git a/src/aws-cpp-sdk-core/include/aws/core/client/AWSClient.h b/src/aws-cpp-sdk-core/include/aws/core/client/AWSClient.h index 777e58e3417..77dc135b96f 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/client/AWSClient.h +++ b/src/aws-cpp-sdk-core/include/aws/core/client/AWSClient.h @@ -72,6 +72,13 @@ namespace Aws typedef Utils::Outcome, AWSError> HttpResponseOutcome; typedef Utils::Outcome, AWSError> StreamOutcome; + class AWS_CORE_API AWSClient; + class FeatureLogger{ + public: + void LogFeature(const AWSClient* clientPtr, const std::string& featureMetadata) const; + }; + + /** * Abstract AWS Client. Contains most of the functionality necessary to build an http request, get it signed, and send it across the wire. */ @@ -333,6 +340,7 @@ namespace Aws static bool DoesResponseGenerateError(const std::shared_ptr& response); std::shared_ptr m_telemetryProvider; std::shared_ptr m_signerProvider; + FeatureLogger m_featureLogger; private: /** * Try to adjust signer's clock @@ -356,6 +364,8 @@ namespace Aws Aws::Client::RequestCompressionConfig m_requestCompressionConfig; std::shared_ptr m_userAgentInterceptor; Aws::Vector> m_interceptors; + + friend class FeatureLogger; }; AWS_CORE_API Aws::String GetAuthorizationHeader(const Aws::Http::HttpRequest& httpRequest); diff --git a/src/aws-cpp-sdk-core/include/aws/core/client/UserAgent.h b/src/aws-cpp-sdk-core/include/aws/core/client/UserAgent.h index 70e83c178cb..1da5667ec49 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/client/UserAgent.h +++ b/src/aws-cpp-sdk-core/include/aws/core/client/UserAgent.h @@ -34,6 +34,7 @@ class AWS_CORE_API UserAgent { Aws::String SerializeWithFeatures(const Aws::Set& features) const; void SetApiName(const Aws::String& apiName) { m_api = apiName; } void AddLegacyFeature(const Aws::String& legacyFeature); + void SetFeatureMetadataIfNotSet(const Aws::String& metadata) { if(m_featureMetadata.empty()){m_featureMetadata = metadata;} } private: const Aws::String m_sdkVersion; @@ -48,6 +49,7 @@ class AWS_CORE_API UserAgent { const Aws::String m_execEnv; const Aws::String m_appId; const Aws::String m_customizations; + Aws::String m_featureMetadata; Aws::Set m_features; }; } // namespace Client diff --git a/src/aws-cpp-sdk-core/include/smithy/client/features/UserAgentInterceptor.h b/src/aws-cpp-sdk-core/include/smithy/client/features/UserAgentInterceptor.h index 35e6436e0a1..4408f3b0058 100644 --- a/src/aws-cpp-sdk-core/include/smithy/client/features/UserAgentInterceptor.h +++ b/src/aws-cpp-sdk-core/include/smithy/client/features/UserAgentInterceptor.h @@ -35,6 +35,8 @@ class UserAgentInterceptor : public interceptor::Interceptor { return context.GetTransmitResponse(); } + void SetFeatureMetadataIfNotSet(const Aws::String& metadata) { m_userAgent.SetFeatureMetadataIfNotSet(metadata); } + void SetApiName(const Aws::String& apiName) { m_userAgent.SetApiName(apiName); } void AddLegacyFeaturesToUserAgent(const Aws::String& valueToAppend) { m_userAgent.AddLegacyFeature(valueToAppend); } diff --git a/src/aws-cpp-sdk-core/source/client/AWSClient.cpp b/src/aws-cpp-sdk-core/source/client/AWSClient.cpp index 205970795c8..2a9b41dad9b 100644 --- a/src/aws-cpp-sdk-core/source/client/AWSClient.cpp +++ b/src/aws-cpp-sdk-core/source/client/AWSClient.cpp @@ -667,6 +667,7 @@ StreamOutcome AWSClient::MakeRequestWithUnparsedResponse(const Aws::Http::URI& u const char* signerRegionOverride, const char* signerServiceNameOverride) const { + m_featureLogger.LogFeature(this, __func__); HttpResponseOutcome httpResponseOutcome = AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride); if (httpResponseOutcome.IsSuccess()) { @@ -685,6 +686,7 @@ StreamOutcome AWSClient::MakeRequestWithUnparsedResponse(const Aws::Http::URI& u const char* signerRegionOverride, const char* signerServiceNameOverride) const { + m_featureLogger.LogFeature(this, __func__); HttpResponseOutcome httpResponseOutcome = AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride); if (httpResponseOutcome.IsSuccess()) { @@ -703,6 +705,7 @@ StreamOutcome AWSClient::MakeRequestWithUnparsedResponse(const Aws::AmazonWebSer const char* signerRegionOverride, const char* signerServiceNameOverride) const { + m_featureLogger.LogFeature(this, __func__); const Aws::Http::URI& uri = endpoint.GetURI(); if (endpoint.GetAttributes()) { signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); @@ -727,6 +730,7 @@ XmlOutcome AWSXMLClient::MakeRequestWithEventStream(const Aws::AmazonWebServiceR const char* signerRegionOverride, const char* signerServiceNameOverride) const { + m_featureLogger.LogFeature(this, __func__); const Aws::Http::URI& uri = endpoint.GetURI(); if (endpoint.GetAttributes()) { signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); @@ -751,6 +755,7 @@ XmlOutcome AWSXMLClient::MakeRequestWithEventStream(const Aws::Http::URI& uri, const char* signerRegionOverride, const char* signerServiceNameOverride) const { + m_featureLogger.LogFeature(this, __func__); HttpResponseOutcome httpOutcome = AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride); if (httpOutcome.IsSuccess()) { @@ -767,6 +772,7 @@ XmlOutcome AWSXMLClient::MakeRequestWithEventStream(const Aws::Http::URI& uri, const char* signerRegionOverride, const char* signerServiceNameOverride) const { + m_featureLogger.LogFeature(this, __func__); HttpResponseOutcome httpOutcome = AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride); if (httpOutcome.IsSuccess()) { @@ -925,31 +931,37 @@ void AWSClient::BuildHttpRequest(const Aws::AmazonWebServiceRequest& request, co Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http::HttpMethod method, long long expirationInSeconds, const std::shared_ptr serviceSpecificParameter) { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, expirationInSeconds, serviceSpecificParameter); } Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds, const std::shared_ptr serviceSpecificParameter) { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, customizedHeaders, expirationInSeconds, serviceSpecificParameter); } Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, long long expirationInSeconds, const std::shared_ptr serviceSpecificParameter) const { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, region, expirationInSeconds, serviceSpecificParameter); } Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds, const std::shared_ptr serviceSpecificParameter) { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, region, customizedHeaders, expirationInSeconds, serviceSpecificParameter); } Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, long long expirationInSeconds, const std::shared_ptr serviceSpecificParameter) const { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, region, serviceName, expirationInSeconds, serviceSpecificParameter); } Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds, const std::shared_ptr serviceSpecificParameter) { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, region, serviceName, customizedHeaders, expirationInSeconds, serviceSpecificParameter); } @@ -960,6 +972,7 @@ Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, const char* signerName, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds, const std::shared_ptr serviceSpecificParameter) { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, region, serviceName, signerName, customizedHeaders, expirationInSeconds, serviceSpecificParameter); } @@ -972,18 +985,21 @@ Aws::String AWSClient::GeneratePresignedUrl(const Aws::Endpoint::AWSEndpoint& en const char* signerServiceNameOverride /* = nullptr */, const std::shared_ptr serviceSpecificParameter) { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(endpoint, method, customizedHeaders, expirationInSeconds, signerName, signerRegionOverride, signerServiceNameOverride, serviceSpecificParameter); } Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds, const std::shared_ptr serviceSpecificParameter) const { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(request, uri, method, region, extraParams, expirationInSeconds, serviceSpecificParameter); } Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds, const std::shared_ptr serviceSpecificParameter) const { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(request, uri, method, region, serviceName, extraParams, expirationInSeconds, serviceSpecificParameter); } @@ -997,17 +1013,20 @@ Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& long long expirationInSeconds, const std::shared_ptr serviceSpecificParameter) const { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(request, uri, method, region, serviceName, signerName, extraParams, expirationInSeconds, serviceSpecificParameter); } Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds, const std::shared_ptr serviceSpecificParameter) const { + m_featureLogger.LogFeature(this, __func__); return AWSUrlPresigner(*this).GeneratePresignedUrl(request, uri, method, extraParams, expirationInSeconds, serviceSpecificParameter); } std::shared_ptr AWSClient::MakeHttpRequest(std::shared_ptr& request) const { + m_featureLogger.LogFeature(this, __func__); return m_httpClient->MakeRequest(request, m_readRateLimiter.get(), m_writeRateLimiter.get()); } @@ -1045,4 +1064,12 @@ void AWSClient::AppendRecursionDetectionHeader(std::shared_ptrSetHeaderValue(Aws::Http::X_AMZN_TRACE_ID_HEADER, xAmznTraceIdVal); -} \ No newline at end of file +} + +void FeatureLogger::LogFeature(const AWSClient* clientPtr, const std::string& featureMetadata) const +{ + if(clientPtr) + { + clientPtr->m_userAgentInterceptor->SetFeatureMetadataIfNotSet(featureMetadata); + } + } \ No newline at end of file diff --git a/src/aws-cpp-sdk-core/source/client/AWSJsonClient.cpp b/src/aws-cpp-sdk-core/source/client/AWSJsonClient.cpp index f42a306156d..aa2080819b7 100644 --- a/src/aws-cpp-sdk-core/source/client/AWSJsonClient.cpp +++ b/src/aws-cpp-sdk-core/source/client/AWSJsonClient.cpp @@ -58,6 +58,7 @@ JsonOutcome AWSJsonClient::MakeRequest(const Aws::AmazonWebServiceRequest& reque const char* signerRegionOverride /* = nullptr */, const char* signerServiceNameOverride /* = nullptr */) const { + m_featureLogger.LogFeature(this, __func__); const Aws::Http::URI& uri = endpoint.GetURI(); if (endpoint.GetAttributes()) { signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); @@ -80,6 +81,7 @@ JsonOutcome AWSJsonClient::MakeRequest(const Aws::Endpoint::AWSEndpoint& endpoin const char* signerRegionOverride /* = nullptr */, const char* signerServiceNameOverride /* = nullptr */) const { + m_featureLogger.LogFeature(this, __func__); const Aws::Http::URI& uri = endpoint.GetURI(); if (endpoint.GetAttributes()) { signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); @@ -103,6 +105,7 @@ JsonOutcome AWSJsonClient::MakeRequest(const Aws::Http::URI& uri, const char* signerRegionOverride, const char* signerServiceNameOverride) const { + m_featureLogger.LogFeature(this, __func__); HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride)); if (!httpOutcome.IsSuccess()) { @@ -142,6 +145,7 @@ JsonOutcome AWSJsonClient::MakeRequest(const Aws::Http::URI& uri, const char* signerRegionOverride, const char* signerServiceNameOverride) const { + m_featureLogger.LogFeature(this, __func__); HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride)); if (!httpOutcome.IsSuccess()) { @@ -189,6 +193,7 @@ JsonOutcome AWSJsonClient::MakeRequest(const Aws::Http::URI& uri, JsonOutcome AWSJsonClient::MakeEventStreamRequest(std::shared_ptr& request) const { + m_featureLogger.LogFeature(this, __func__); // request is assumed to be signed std::shared_ptr httpResponse = MakeHttpRequest(request); @@ -223,6 +228,7 @@ JsonOutcome AWSJsonClient::MakeEventStreamRequest(std::shared_ptr AWSJsonClient::BuildAWSError( const std::shared_ptr& httpResponse) const { + m_featureLogger.LogFeature(this, __func__); AWSError error; if (httpResponse->HasClientError()) { diff --git a/src/aws-cpp-sdk-core/source/client/AWSXmlClient.cpp b/src/aws-cpp-sdk-core/source/client/AWSXmlClient.cpp index f1ac1793caa..da700e07952 100644 --- a/src/aws-cpp-sdk-core/source/client/AWSXmlClient.cpp +++ b/src/aws-cpp-sdk-core/source/client/AWSXmlClient.cpp @@ -52,6 +52,7 @@ XmlOutcome AWSXMLClient::MakeRequest(const Aws::AmazonWebServiceRequest& request const char* signerRegionOverride /* = nullptr */, const char* signerServiceNameOverride /* = nullptr */) const { + m_featureLogger.LogFeature(this, __func__); const Aws::Http::URI& uri = endpoint.GetURI(); if (endpoint.GetAttributes()) { signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); @@ -98,6 +99,7 @@ XmlOutcome AWSXMLClient::MakeRequest(const Aws::Http::URI& uri, const char* signerRegionOverride, const char* signerServiceNameOverride) const { + m_featureLogger.LogFeature(this, __func__); HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride)); if (!httpOutcome.IsSuccess()) { @@ -140,6 +142,7 @@ XmlOutcome AWSXMLClient::MakeRequest(const Aws::Http::URI& uri, const char* signerRegionOverride, const char* signerServiceNameOverride) const { + m_featureLogger.LogFeature(this, __func__); HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride)); if (!httpOutcome.IsSuccess()) { diff --git a/src/aws-cpp-sdk-core/source/client/UserAgent.cpp b/src/aws-cpp-sdk-core/source/client/UserAgent.cpp index f0cc5adc08c..ce800ab49d0 100644 --- a/src/aws-cpp-sdk-core/source/client/UserAgent.cpp +++ b/src/aws-cpp-sdk-core/source/client/UserAgent.cpp @@ -70,6 +70,7 @@ const char* CPP = "c++"; const char* EXEC_ENV = "exec-env"; const char* APP_ID = "app"; const char* BUSINESS_METRICS = "m"; +const char* FEATURE_METADATA = "ft"; } // namespace UserAgent::UserAgent(const ClientConfiguration& clientConfiguration, @@ -128,6 +129,10 @@ Aws::String UserAgent::SerializeWithFeatures(const Aws::Set& f } // Does not need to be in order + if (!m_featureMetadata.empty()) { + SerializeMetadata(FEATURE_METADATA, m_featureMetadata); + } + if (!m_archName.empty()) { SerializeMetadataWithVersion(METADATA, ARCH, m_archName); }