From 8200000a3a2d9806617b4b14a800751f4f28773a Mon Sep 17 00:00:00 2001 From: Luc Talatinian <102624213+lucix-aws@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:29:36 -0400 Subject: [PATCH] remove private metrics collection APIs (#2818) --- .../cc02c91a476e488ea53c5fc013918a92.json | 8 + aws/middleware/private/metrics/emf/emf.go | 90 ----- .../private/metrics/emf/emf_test.go | 145 -------- .../private/metrics/emf/emf_test_data.go | 104 ------ aws/middleware/private/metrics/metrics.go | 320 ------------------ .../private/metrics/metrics_test.go | 214 ------------ .../metrics/middleware/configuration.go | 62 ---- .../middleware/endpoint_resolution_end.go | 49 --- .../endpoint_resolution_end_test.go | 32 -- .../middleware/endpoint_resolution_start.go | 49 --- .../endpoint_resolution_start_test.go | 51 --- .../private/metrics/middleware/http.go | 154 --------- .../private/metrics/middleware/http_test.go | 146 -------- .../private/metrics/middleware/identity.go | 47 --- .../metrics/middleware/metric_collection.go | 64 ---- .../middleware/metric_collection_test.go | 89 ----- .../private/metrics/middleware/request.go | 61 ---- .../metrics/middleware/request_attempt.go | 70 ---- .../middleware/request_attempt_test.go | 114 ------- .../metrics/middleware/request_test.go | 86 ----- .../private/metrics/middleware/signing.go | 57 ---- .../middleware/stack_deserialize_end.go | 45 --- .../middleware/stack_deserialize_end_test.go | 63 ---- .../middleware/stack_deserialize_start.go | 44 --- .../stack_deserialize_start_test.go | 59 ---- .../metrics/middleware/stack_serialize_end.go | 33 -- .../middleware/stack_serialize_end_test.go | 29 -- .../middleware/stack_serialize_start.go | 32 -- .../middleware/stack_serialize_start_test.go | 29 -- .../private/metrics/middleware/transport.go | 46 --- .../metrics/middleware/transport_test.go | 45 --- .../private/metrics/middleware/user_agent.go | 29 -- .../metrics/middleware/wrap_data_stream.go | 59 ---- .../middleware/wrap_data_streams_test.go | 114 ------- .../private/metrics/publisher/emf.go | 155 --------- .../private/metrics/publisher/emf_test.go | 251 -------------- .../metrics/publisher/emf_test_data.go | 227 ------------- .../read_closer_with_metrics.go | 56 --- .../read_closer_with_metrics_test.go | 83 ----- .../private/metrics/testutils/test_util.go | 111 ------ aws/retry/middleware.go | 8 - aws/retry/middleware_test.go | 3 +- 42 files changed, 9 insertions(+), 3524 deletions(-) create mode 100644 .changelog/cc02c91a476e488ea53c5fc013918a92.json delete mode 100644 aws/middleware/private/metrics/emf/emf.go delete mode 100644 aws/middleware/private/metrics/emf/emf_test.go delete mode 100644 aws/middleware/private/metrics/emf/emf_test_data.go delete mode 100644 aws/middleware/private/metrics/metrics.go delete mode 100644 aws/middleware/private/metrics/metrics_test.go delete mode 100644 aws/middleware/private/metrics/middleware/configuration.go delete mode 100644 aws/middleware/private/metrics/middleware/endpoint_resolution_end.go delete mode 100644 aws/middleware/private/metrics/middleware/endpoint_resolution_end_test.go delete mode 100644 aws/middleware/private/metrics/middleware/endpoint_resolution_start.go delete mode 100644 aws/middleware/private/metrics/middleware/endpoint_resolution_start_test.go delete mode 100644 aws/middleware/private/metrics/middleware/http.go delete mode 100644 aws/middleware/private/metrics/middleware/http_test.go delete mode 100644 aws/middleware/private/metrics/middleware/identity.go delete mode 100644 aws/middleware/private/metrics/middleware/metric_collection.go delete mode 100644 aws/middleware/private/metrics/middleware/metric_collection_test.go delete mode 100644 aws/middleware/private/metrics/middleware/request.go delete mode 100644 aws/middleware/private/metrics/middleware/request_attempt.go delete mode 100644 aws/middleware/private/metrics/middleware/request_attempt_test.go delete mode 100644 aws/middleware/private/metrics/middleware/request_test.go delete mode 100644 aws/middleware/private/metrics/middleware/signing.go delete mode 100644 aws/middleware/private/metrics/middleware/stack_deserialize_end.go delete mode 100644 aws/middleware/private/metrics/middleware/stack_deserialize_end_test.go delete mode 100644 aws/middleware/private/metrics/middleware/stack_deserialize_start.go delete mode 100644 aws/middleware/private/metrics/middleware/stack_deserialize_start_test.go delete mode 100644 aws/middleware/private/metrics/middleware/stack_serialize_end.go delete mode 100644 aws/middleware/private/metrics/middleware/stack_serialize_end_test.go delete mode 100644 aws/middleware/private/metrics/middleware/stack_serialize_start.go delete mode 100644 aws/middleware/private/metrics/middleware/stack_serialize_start_test.go delete mode 100644 aws/middleware/private/metrics/middleware/transport.go delete mode 100644 aws/middleware/private/metrics/middleware/transport_test.go delete mode 100644 aws/middleware/private/metrics/middleware/user_agent.go delete mode 100644 aws/middleware/private/metrics/middleware/wrap_data_stream.go delete mode 100644 aws/middleware/private/metrics/middleware/wrap_data_streams_test.go delete mode 100644 aws/middleware/private/metrics/publisher/emf.go delete mode 100644 aws/middleware/private/metrics/publisher/emf_test.go delete mode 100644 aws/middleware/private/metrics/publisher/emf_test_data.go delete mode 100644 aws/middleware/private/metrics/readcloserwithmetrics/read_closer_with_metrics.go delete mode 100644 aws/middleware/private/metrics/readcloserwithmetrics/read_closer_with_metrics_test.go delete mode 100644 aws/middleware/private/metrics/testutils/test_util.go diff --git a/.changelog/cc02c91a476e488ea53c5fc013918a92.json b/.changelog/cc02c91a476e488ea53c5fc013918a92.json new file mode 100644 index 00000000000..ded4aab0077 --- /dev/null +++ b/.changelog/cc02c91a476e488ea53c5fc013918a92.json @@ -0,0 +1,8 @@ +{ + "id": "cc02c91a-476e-488e-a53c-5fc013918a92", + "type": "bugfix", + "description": "Remove private metrics collection APIs. These APIs were annotated at the package level that they should not be used by callers and could be removed at any time. With the release of self-instrumented clients for SDK metrics, this internal code is obsolete.", + "modules": [ + "." + ] +} \ No newline at end of file diff --git a/aws/middleware/private/metrics/emf/emf.go b/aws/middleware/private/metrics/emf/emf.go deleted file mode 100644 index c9516f3753a..00000000000 --- a/aws/middleware/private/metrics/emf/emf.go +++ /dev/null @@ -1,90 +0,0 @@ -// Package emf implements an EMF metrics publisher. -// -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. -package emf - -import ( - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" -) - -const ( - emfIdentifier = "_aws" - timestampKey = "Timestamp" - cloudWatchMetricsKey = "CloudWatchMetrics" - namespaceKey = "Namespace" - dimensionsKey = "Dimensions" - metricsKey = "Metrics" -) - -// Entry represents a log entry in the EMF format. -type Entry struct { - namespace string - serializer metrics.Serializer - metrics []metric - dimensions [][]string - fields map[string]interface{} -} - -type metric struct { - Name string -} - -// NewEntry creates a new Entry with the specified namespace and serializer. -func NewEntry(namespace string, serializer metrics.Serializer) Entry { - return Entry{ - namespace: namespace, - serializer: serializer, - metrics: []metric{}, - dimensions: [][]string{{}}, - fields: map[string]interface{}{}, - } -} - -// Build constructs the EMF log entry as a JSON string. -func (e *Entry) Build() (string, error) { - - entry := map[string]interface{}{} - - entry[emfIdentifier] = map[string]interface{}{ - timestampKey: sdk.NowTime().UnixNano() / 1e6, - cloudWatchMetricsKey: []map[string]interface{}{ - { - namespaceKey: e.namespace, - dimensionsKey: e.dimensions, - metricsKey: e.metrics, - }, - }, - } - - for k, v := range e.fields { - entry[k] = v - } - - jsonEntry, err := e.serializer.Serialize(entry) - if err != nil { - return "", err - } - return jsonEntry, nil -} - -// AddDimension adds a CW Dimension to the EMF entry. -func (e *Entry) AddDimension(key string, value string) { - // Dimensions are a list of lists. We only support a single list. - e.dimensions[0] = append(e.dimensions[0], key) - e.fields[key] = value -} - -// AddMetric adds a CW Metric to the EMF entry. -func (e *Entry) AddMetric(key string, value float64) { - e.metrics = append(e.metrics, metric{key}) - e.fields[key] = value -} - -// AddProperty adds a CW Property to the EMF entry. -// Properties are not published as metrics, but they are available in logs and in CW insights. -func (e *Entry) AddProperty(key string, value interface{}) { - e.fields[key] = value -} diff --git a/aws/middleware/private/metrics/emf/emf_test.go b/aws/middleware/private/metrics/emf/emf_test.go deleted file mode 100644 index 00deaada5d8..00000000000 --- a/aws/middleware/private/metrics/emf/emf_test.go +++ /dev/null @@ -1,145 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package emf - -import ( - "fmt" - "reflect" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" -) - -type TestSerializerWithError struct{} - -func (TestSerializerWithError) Serialize(obj interface{}) (string, error) { - return "", fmt.Errorf("serialization error") -} - -func TestCreateNewEntry(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - cases := map[string]struct { - Namespace string - ExpectedEntry Entry - }{ - "success": { - Namespace: "testNamespace", - ExpectedEntry: Entry{ - namespace: "testNamespace", - serializer: metrics.DefaultSerializer{}, - metrics: []metric{}, - dimensions: [][]string{{}}, - fields: map[string]interface{}{}, - }, - }, - } - - for name, c := range cases { - t.Run(name, func(t *testing.T) { - actualEntry := NewEntry(c.Namespace, metrics.DefaultSerializer{}) - if !reflect.DeepEqual(actualEntry, c.ExpectedEntry) { - t.Errorf("Entry contained unexpected values") - } - }) - } -} - -func TestBuild(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - cases := map[string]struct { - Namespace string - Configure func(entry *Entry) - Serializer metrics.Serializer - ExpectedError error - ExpectedResult string - }{ - "completeEntry": { - Namespace: "testNamespace", - Serializer: metrics.DefaultSerializer{}, - Configure: func(entry *Entry) { - entry.AddMetric("testMetric1", 1) - entry.AddMetric("testMetric2", 2) - entry.AddDimension("testDimension1", "dim1") - entry.AddDimension("testDimension2", "dim2") - entry.AddProperty("testProperty1", "prop1") - entry.AddProperty("testProperty2", "prop2") - }, - ExpectedError: nil, - ExpectedResult: completeEntry, - }, - "noMetrics": { - Namespace: "testNamespace", - Serializer: metrics.DefaultSerializer{}, - Configure: func(entry *Entry) { - entry.AddDimension("testDimension1", "dim1") - entry.AddDimension("testDimension2", "dim2") - entry.AddProperty("testProperty1", "prop1") - entry.AddProperty("testProperty2", "prop2") - }, - ExpectedError: nil, - ExpectedResult: noMetrics, - }, - "noDimensions": { - Namespace: "testNamespace", - Serializer: metrics.DefaultSerializer{}, - Configure: func(entry *Entry) { - entry.AddMetric("testMetric1", 1) - entry.AddMetric("testMetric2", 2) - entry.AddProperty("testProperty1", "prop1") - entry.AddProperty("testProperty2", "prop2") - }, - ExpectedError: nil, - ExpectedResult: noDimensions, - }, - "noProperties": { - Namespace: "testNamespace", - Serializer: metrics.DefaultSerializer{}, - Configure: func(entry *Entry) { - entry.AddMetric("testMetric1", 1) - entry.AddMetric("testMetric2", 2) - entry.AddDimension("testDimension1", "dim1") - entry.AddDimension("testDimension2", "dim2") - }, - ExpectedError: nil, - ExpectedResult: noProperties, - }, - "serializationError": { - Namespace: "testNamespace", - Serializer: TestSerializerWithError{}, - Configure: func(entry *Entry) { - }, - ExpectedError: fmt.Errorf("serialization error"), - ExpectedResult: "", - }, - } - - for name, c := range cases { - t.Run(name, func(t *testing.T) { - entry := NewEntry(c.Namespace, c.Serializer) - - c.Configure(&entry) - - result, err := entry.Build() - - if !reflect.DeepEqual(err, c.ExpectedError) { - t.Errorf("Unexpected error, should be '%s' but was '%s'", c.ExpectedError, err) - } - - if !reflect.DeepEqual(result, c.ExpectedResult) { - t.Errorf("Unexpected result, should be '%s' but was '%s'", c.ExpectedResult, result) - } - }) - } -} diff --git a/aws/middleware/private/metrics/emf/emf_test_data.go b/aws/middleware/private/metrics/emf/emf_test_data.go deleted file mode 100644 index 47102e014fd..00000000000 --- a/aws/middleware/private/metrics/emf/emf_test_data.go +++ /dev/null @@ -1,104 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package emf - -import "strings" - -func stripString(str string) string { - str = strings.Replace(str, " ", "", -1) - str = strings.Replace(str, "\t", "", -1) - str = strings.Replace(str, "\n", "", -1) - return str -} - -var completeEntry = stripString(` -{ - "_aws": { - "CloudWatchMetrics": [{ - "Dimensions": [ - ["testDimension1", "testDimension2"] - ], - "Metrics": [{ - "Name": "testMetric1" - }, { - "Name": "testMetric2" - }], - "Namespace": "testNamespace" - }], - "Timestamp": 1234000 - }, - "testDimension1": "dim1", - "testDimension2": "dim2", - "testMetric1": 1, - "testMetric2": 2, - "testProperty1": "prop1", - "testProperty2": "prop2" -} -`) - -var noMetrics = stripString(` -{ - "_aws": { - "CloudWatchMetrics": [{ - "Dimensions": [ - ["testDimension1", "testDimension2"] - ], - "Metrics": [], - "Namespace": "testNamespace" - }], - "Timestamp": 1234000 - }, - "testDimension1": "dim1", - "testDimension2": "dim2", - "testProperty1": "prop1", - "testProperty2": "prop2" -} -`) - -var noProperties = stripString(` -{ - "_aws": { - "CloudWatchMetrics": [{ - "Dimensions": [ - ["testDimension1", "testDimension2"] - ], - "Metrics": [{ - "Name": "testMetric1" - }, { - "Name": "testMetric2" - }], - "Namespace": "testNamespace" - }], - "Timestamp": 1234000 - }, - "testDimension1": "dim1", - "testDimension2": "dim2", - "testMetric1": 1, - "testMetric2": 2 -} -`) - -var noDimensions = stripString(` -{ - "_aws": { - "CloudWatchMetrics": [{ - "Dimensions": [ - [] - ], - "Metrics": [{ - "Name": "testMetric1" - }, { - "Name": "testMetric2" - }], - "Namespace": "testNamespace" - }], - "Timestamp": 1234000 - }, - "testMetric1": 1, - "testMetric2": 2, - "testProperty1": "prop1", - "testProperty2": "prop2" -} -`) diff --git a/aws/middleware/private/metrics/metrics.go b/aws/middleware/private/metrics/metrics.go deleted file mode 100644 index 19d6107c461..00000000000 --- a/aws/middleware/private/metrics/metrics.go +++ /dev/null @@ -1,320 +0,0 @@ -// Package metrics implements metrics gathering for SDK development purposes. -// -// This package is designated as private and is intended for use only by the -// AWS client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. -package metrics - -import ( - "context" - "encoding/json" - "fmt" - "sync" - "time" - - "github.com/aws/smithy-go/middleware" -) - -const ( - // ServiceIDKey is the key for the service ID metric. - ServiceIDKey = "ServiceId" - // OperationNameKey is the key for the operation name metric. - OperationNameKey = "OperationName" - // ClientRequestIDKey is the key for the client request ID metric. - ClientRequestIDKey = "ClientRequestId" - // APICallDurationKey is the key for the API call duration metric. - APICallDurationKey = "ApiCallDuration" - // APICallSuccessfulKey is the key for the API call successful metric. - APICallSuccessfulKey = "ApiCallSuccessful" - // MarshallingDurationKey is the key for the marshalling duration metric. - MarshallingDurationKey = "MarshallingDuration" - // InThroughputKey is the key for the input throughput metric. - InThroughputKey = "InThroughput" - // OutThroughputKey is the key for the output throughput metric. - OutThroughputKey = "OutThroughput" - // RetryCountKey is the key for the retry count metric. - RetryCountKey = "RetryCount" - // HTTPStatusCodeKey is the key for the HTTP status code metric. - HTTPStatusCodeKey = "HttpStatusCode" - // AWSExtendedRequestIDKey is the key for the AWS extended request ID metric. - AWSExtendedRequestIDKey = "AwsExtendedRequestId" - // AWSRequestIDKey is the key for the AWS request ID metric. - AWSRequestIDKey = "AwsRequestId" - // BackoffDelayDurationKey is the key for the backoff delay duration metric. - BackoffDelayDurationKey = "BackoffDelayDuration" - // StreamThroughputKey is the key for the stream throughput metric. - StreamThroughputKey = "Throughput" - // ConcurrencyAcquireDurationKey is the key for the concurrency acquire duration metric. - ConcurrencyAcquireDurationKey = "ConcurrencyAcquireDuration" - // PendingConcurrencyAcquiresKey is the key for the pending concurrency acquires metric. - PendingConcurrencyAcquiresKey = "PendingConcurrencyAcquires" - // SigningDurationKey is the key for the signing duration metric. - SigningDurationKey = "SigningDuration" - // UnmarshallingDurationKey is the key for the unmarshalling duration metric. - UnmarshallingDurationKey = "UnmarshallingDuration" - // TimeToFirstByteKey is the key for the time to first byte metric. - TimeToFirstByteKey = "TimeToFirstByte" - // ServiceCallDurationKey is the key for the service call duration metric. - ServiceCallDurationKey = "ServiceCallDuration" - // EndpointResolutionDurationKey is the key for the endpoint resolution duration metric. - EndpointResolutionDurationKey = "EndpointResolutionDuration" - // AttemptNumberKey is the key for the attempt number metric. - AttemptNumberKey = "AttemptNumber" - // MaxConcurrencyKey is the key for the max concurrency metric. - MaxConcurrencyKey = "MaxConcurrency" - // AvailableConcurrencyKey is the key for the available concurrency metric. - AvailableConcurrencyKey = "AvailableConcurrency" -) - -// MetricPublisher provides the interface to provide custom MetricPublishers. -// PostRequestMetrics will be invoked by the MetricCollection middleware to post request. -// PostStreamMetrics will be invoked by ReadCloserWithMetrics to post stream metrics. -type MetricPublisher interface { - PostRequestMetrics(*MetricData) error - PostStreamMetrics(*MetricData) error -} - -// Serializer provides the interface to provide custom Serializers. -// Serialize will transform any input object in its corresponding string representation. -type Serializer interface { - Serialize(obj interface{}) (string, error) -} - -// DefaultSerializer is an implementation of the Serializer interface. -type DefaultSerializer struct{} - -// Serialize uses the default JSON serializer to obtain the string representation of an object. -func (DefaultSerializer) Serialize(obj interface{}) (string, error) { - bytes, err := json.Marshal(obj) - if err != nil { - return "", err - } - return string(bytes), nil -} - -type metricContextKey struct{} - -// MetricContext contains fields to store metric-related information. -type MetricContext struct { - connectionCounter *SharedConnectionCounter - publisher MetricPublisher - data *MetricData -} - -// MetricData stores the collected metric data. -type MetricData struct { - RequestStartTime time.Time - RequestEndTime time.Time - APICallDuration time.Duration - SerializeStartTime time.Time - SerializeEndTime time.Time - MarshallingDuration time.Duration - ResolveEndpointStartTime time.Time - ResolveEndpointEndTime time.Time - EndpointResolutionDuration time.Duration - GetIdentityStartTime time.Time - GetIdentityEndTime time.Time - InThroughput float64 - OutThroughput float64 - RetryCount int - Success uint8 - StatusCode int - ClientRequestID string - ServiceID string - OperationName string - PartitionID string - Region string - UserAgent string - RequestContentLength int64 - Stream StreamMetrics - Attempts []AttemptMetrics -} - -// StreamMetrics stores metrics related to streaming data. -type StreamMetrics struct { - ReadDuration time.Duration - ReadBytes int64 - Throughput float64 -} - -// AttemptMetrics stores metrics related to individual attempts. -type AttemptMetrics struct { - ServiceCallStart time.Time - ServiceCallEnd time.Time - ServiceCallDuration time.Duration - FirstByteTime time.Time - TimeToFirstByte time.Duration - ConnRequestedTime time.Time - ConnObtainedTime time.Time - ConcurrencyAcquireDuration time.Duration - SignStartTime time.Time - SignEndTime time.Time - SigningDuration time.Duration - DeserializeStartTime time.Time - DeserializeEndTime time.Time - UnMarshallingDuration time.Duration - RetryDelay time.Duration - ResponseContentLength int64 - StatusCode int - RequestID string - ExtendedRequestID string - HTTPClient string - MaxConcurrency int - PendingConnectionAcquires int - AvailableConcurrency int - ActiveRequests int - ReusedConnection bool -} - -// Data returns the MetricData associated with the MetricContext. -func (mc *MetricContext) Data() *MetricData { - return mc.data -} - -// ConnectionCounter returns the SharedConnectionCounter associated with the MetricContext. -func (mc *MetricContext) ConnectionCounter() *SharedConnectionCounter { - return mc.connectionCounter -} - -// Publisher returns the MetricPublisher associated with the MetricContext. -func (mc *MetricContext) Publisher() MetricPublisher { - return mc.publisher -} - -// ComputeRequestMetrics calculates and populates derived metrics based on the collected data. -func (md *MetricData) ComputeRequestMetrics() { - - for idx := range md.Attempts { - attempt := &md.Attempts[idx] - attempt.ConcurrencyAcquireDuration = attempt.ConnObtainedTime.Sub(attempt.ConnRequestedTime) - attempt.SigningDuration = attempt.SignEndTime.Sub(attempt.SignStartTime) - attempt.UnMarshallingDuration = attempt.DeserializeEndTime.Sub(attempt.DeserializeStartTime) - attempt.TimeToFirstByte = attempt.FirstByteTime.Sub(attempt.ServiceCallStart) - attempt.ServiceCallDuration = attempt.ServiceCallEnd.Sub(attempt.ServiceCallStart) - } - - md.APICallDuration = md.RequestEndTime.Sub(md.RequestStartTime) - md.MarshallingDuration = md.SerializeEndTime.Sub(md.SerializeStartTime) - md.EndpointResolutionDuration = md.ResolveEndpointEndTime.Sub(md.ResolveEndpointStartTime) - - md.RetryCount = len(md.Attempts) - 1 - - latestAttempt, err := md.LatestAttempt() - - if err != nil { - fmt.Printf("error retrieving attempts data due to: %s. Skipping Throughput metrics", err.Error()) - } else { - - md.StatusCode = latestAttempt.StatusCode - - if md.Success == 1 { - if latestAttempt.ResponseContentLength > 0 && latestAttempt.ServiceCallDuration > 0 { - md.InThroughput = float64(latestAttempt.ResponseContentLength) / latestAttempt.ServiceCallDuration.Seconds() - } - if md.RequestContentLength > 0 && latestAttempt.ServiceCallDuration > 0 { - md.OutThroughput = float64(md.RequestContentLength) / latestAttempt.ServiceCallDuration.Seconds() - } - } - } -} - -// LatestAttempt returns the latest attempt metrics. -// It returns an error if no attempts are initialized. -func (md *MetricData) LatestAttempt() (*AttemptMetrics, error) { - if md.Attempts == nil || len(md.Attempts) == 0 { - return nil, fmt.Errorf("no attempts initialized. NewAttempt() should be called first") - } - return &md.Attempts[len(md.Attempts)-1], nil -} - -// NewAttempt initializes new attempt metrics. -func (md *MetricData) NewAttempt() { - if md.Attempts == nil { - md.Attempts = []AttemptMetrics{} - } - md.Attempts = append(md.Attempts, AttemptMetrics{}) -} - -// SharedConnectionCounter is a counter shared across API calls. -type SharedConnectionCounter struct { - mu sync.Mutex - - activeRequests int - pendingConnectionAcquire int -} - -// ActiveRequests returns the count of active requests. -func (cc *SharedConnectionCounter) ActiveRequests() int { - cc.mu.Lock() - defer cc.mu.Unlock() - - return cc.activeRequests -} - -// PendingConnectionAcquire returns the count of pending connection acquires. -func (cc *SharedConnectionCounter) PendingConnectionAcquire() int { - cc.mu.Lock() - defer cc.mu.Unlock() - - return cc.pendingConnectionAcquire -} - -// AddActiveRequest increments the count of active requests. -func (cc *SharedConnectionCounter) AddActiveRequest() { - cc.mu.Lock() - defer cc.mu.Unlock() - - cc.activeRequests++ -} - -// RemoveActiveRequest decrements the count of active requests. -func (cc *SharedConnectionCounter) RemoveActiveRequest() { - cc.mu.Lock() - defer cc.mu.Unlock() - - cc.activeRequests-- -} - -// AddPendingConnectionAcquire increments the count of pending connection acquires. -func (cc *SharedConnectionCounter) AddPendingConnectionAcquire() { - cc.mu.Lock() - defer cc.mu.Unlock() - - cc.pendingConnectionAcquire++ -} - -// RemovePendingConnectionAcquire decrements the count of pending connection acquires. -func (cc *SharedConnectionCounter) RemovePendingConnectionAcquire() { - cc.mu.Lock() - defer cc.mu.Unlock() - - cc.pendingConnectionAcquire-- -} - -// InitMetricContext initializes the metric context with the provided counter and publisher. -// It returns the updated context. -func InitMetricContext( - ctx context.Context, counter *SharedConnectionCounter, publisher MetricPublisher, -) context.Context { - if middleware.GetStackValue(ctx, metricContextKey{}) == nil { - ctx = middleware.WithStackValue(ctx, metricContextKey{}, &MetricContext{ - connectionCounter: counter, - publisher: publisher, - data: &MetricData{ - Attempts: []AttemptMetrics{}, - Stream: StreamMetrics{}, - }, - }) - } - return ctx -} - -// Context returns the metric context from the given context. -// It returns nil if the metric context is not found. -func Context(ctx context.Context) *MetricContext { - mctx := middleware.GetStackValue(ctx, metricContextKey{}) - if mctx == nil { - return nil - } - return mctx.(*MetricContext) -} diff --git a/aws/middleware/private/metrics/metrics_test.go b/aws/middleware/private/metrics/metrics_test.go deleted file mode 100644 index bda0190feca..00000000000 --- a/aws/middleware/private/metrics/metrics_test.go +++ /dev/null @@ -1,214 +0,0 @@ -// This package is designated as private and is intended for use only by the -// AWS client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package metrics - -import ( - "context" - "testing" - "time" -) - -type TestPublisher struct{} - -func (tp *TestPublisher) PostRequestMetrics(data *MetricData) error { - return nil -} - -func (tp *TestPublisher) PostStreamMetrics(data *MetricData) error { - return nil -} - -func TestInitAndRetrieveMetricContext(t *testing.T) { - ctx := context.Background() - cc := SharedConnectionCounter{} - tp := TestPublisher{} - - ctx = InitMetricContext(ctx, &cc, &tp) - mctx := Context(ctx) - - if mctx == nil { - t.Errorf("Metric context should not be nil") - } - if mctx.publisher != &tp || mctx.Publisher() != &tp { - t.Errorf("Unexpected publisher") - } - if mctx.connectionCounter != &cc || mctx.ConnectionCounter() != &cc { - t.Errorf("Unexpected connection counter") - } -} - -func TestConnectionCounter(t *testing.T) { - cc := SharedConnectionCounter{} - cc.AddPendingConnectionAcquire() - cc.AddPendingConnectionAcquire() - cc.RemovePendingConnectionAcquire() - cc.AddActiveRequest() - cc.AddActiveRequest() - cc.AddActiveRequest() - cc.RemoveActiveRequest() - - if cc.PendingConnectionAcquire() != 1 { - t.Errorf("Unexpected count for PendingConnectionAcquire") - } - - if cc.ActiveRequests() != 2 { - t.Errorf("Unexpected count for ActiveRequests") - } -} - -func TestAttemptCreationAndRetrieval(t *testing.T) { - ctx := context.TODO() - cc := SharedConnectionCounter{} - tp := TestPublisher{} - - ctx = InitMetricContext(ctx, &cc, &tp) - - mctx := Context(ctx) - - _, err := mctx.Data().LatestAttempt() - - if err == nil { - t.Errorf("Expected error for uninitialized attempt") - } - - mctx.Data().NewAttempt() - - if len(mctx.Data().Attempts) != 1 { - t.Errorf("Unexpected number of attempts") - } - - _, err = mctx.Data().LatestAttempt() - - if err != nil { - t.Errorf("Unexpected error for uninitialized attempt") - } -} - -func TestMetricData_ComputeRequestMetrics(t *testing.T) { - - data := MetricData{ - RequestStartTime: time.Unix(1234, 0), - RequestEndTime: time.Unix(1434, 0), - SerializeStartTime: time.Unix(1234, 0), - SerializeEndTime: time.Unix(1434, 0), - ResolveEndpointStartTime: time.Unix(1234, 0), - ResolveEndpointEndTime: time.Unix(1434, 0), - Success: 1, - ClientRequestID: "crid", - ServiceID: "sid", - OperationName: "operationname", - PartitionID: "partitionid", - Region: "region", - RequestContentLength: 100, - Stream: StreamMetrics{}, - Attempts: []AttemptMetrics{{ - ServiceCallStart: time.Unix(1234, 0), - ServiceCallEnd: time.Unix(1434, 0), - FirstByteTime: time.Unix(1334, 0), - ConnRequestedTime: time.Unix(1234, 0), - ConnObtainedTime: time.Unix(1434, 0), - SignStartTime: time.Unix(1234, 0), - SignEndTime: time.Unix(1434, 0), - DeserializeStartTime: time.Unix(1234, 0), - DeserializeEndTime: time.Unix(1434, 0), - RetryDelay: 100, - ResponseContentLength: 100, - StatusCode: 200, - RequestID: "reqid", - ExtendedRequestID: "exreqid", - HTTPClient: "Default", - MaxConcurrency: 10, - PendingConnectionAcquires: 1, - AvailableConcurrency: 2, - ActiveRequests: 3, - ReusedConnection: false, - }, - { - ServiceCallStart: time.Unix(1234, 0), - ServiceCallEnd: time.Unix(1434, 0), - FirstByteTime: time.Unix(1334, 0), - ConnRequestedTime: time.Unix(1234, 0), - ConnObtainedTime: time.Unix(1434, 0), - SignStartTime: time.Unix(1234, 0), - SignEndTime: time.Unix(1434, 0), - DeserializeStartTime: time.Unix(1234, 0), - DeserializeEndTime: time.Unix(1434, 0), - RetryDelay: 100, - ResponseContentLength: 100, - StatusCode: 200, - RequestID: "reqid", - ExtendedRequestID: "exreqid", - HTTPClient: "Default", - MaxConcurrency: 10, - PendingConnectionAcquires: 1, - AvailableConcurrency: 2, - ActiveRequests: 3, - ReusedConnection: false, - }}, - } - - data.ComputeRequestMetrics() - - expectedAPICallDuration := time.Second * 200 - actualAPICallDuration := data.APICallDuration - - if expectedAPICallDuration != actualAPICallDuration { - t.Errorf("Unexpected ApiCallDuration, should be '%s' but was '%s'", expectedAPICallDuration, actualAPICallDuration) - } - - expectedMarshallingDuration := time.Second * 200 - actualMarshallingDuration := data.MarshallingDuration - - if expectedMarshallingDuration != actualMarshallingDuration { - t.Errorf("Unexpected MarshallingDuration, should be '%s' but was '%s'", expectedMarshallingDuration, actualMarshallingDuration) - } - - expectedEndpointResolutionDuration := time.Second * 200 - actualEndpointResolutionDuration := data.EndpointResolutionDuration - - if expectedEndpointResolutionDuration != actualEndpointResolutionDuration { - t.Errorf("Unexpected EndpointResolutionDuration, should be '%s' but was '%s'", expectedEndpointResolutionDuration, actualEndpointResolutionDuration) - } - - for idx := range data.Attempts { - - attempt := data.Attempts[idx] - - expectedServiceCallDuration := time.Second * 200 - actualServiceCallDuration := attempt.ServiceCallDuration - - if expectedServiceCallDuration != actualServiceCallDuration { - t.Errorf("Unexpected ServiceCallDuration, should be '%s' but was '%s'", expectedServiceCallDuration, actualServiceCallDuration) - } - - expectedTimeToFirstByte := time.Second * 100 - actualTimeToFirstByte := attempt.TimeToFirstByte - - if expectedTimeToFirstByte != actualTimeToFirstByte { - t.Errorf("Unexpected TimeToFirstByte, should be '%s' but was '%s'", expectedTimeToFirstByte, actualTimeToFirstByte) - } - - expectedConcurrencyAcquireDuration := time.Second * 200 - actualConcurrencyAcquireDuration := attempt.ConcurrencyAcquireDuration - - if expectedConcurrencyAcquireDuration != actualConcurrencyAcquireDuration { - t.Errorf("Unexpected ConcurrencyAcquireDuration, should be '%s' but was '%s'", expectedConcurrencyAcquireDuration, actualConcurrencyAcquireDuration) - } - - expectedSigningDuration := time.Second * 200 - actualSigningDuration := attempt.SigningDuration - - if expectedSigningDuration != actualSigningDuration { - t.Errorf("Unexpected SigningDuration, should be '%s' but was '%s'", expectedSigningDuration, actualSigningDuration) - } - - expectedUnMarshallingDuration := time.Second * 200 - actualUnMarshallingDuration := attempt.UnMarshallingDuration - - if expectedUnMarshallingDuration != actualUnMarshallingDuration { - t.Errorf("Unexpected UnMarshallingDuration, should be '%s' but was '%s'", expectedUnMarshallingDuration, actualUnMarshallingDuration) - } - } -} diff --git a/aws/middleware/private/metrics/middleware/configuration.go b/aws/middleware/private/metrics/middleware/configuration.go deleted file mode 100644 index 4e999556c07..00000000000 --- a/aws/middleware/private/metrics/middleware/configuration.go +++ /dev/null @@ -1,62 +0,0 @@ -package middleware - -import ( - "net/http" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/smithy-go/middleware" -) - -func WithMetricMiddlewares( - publisher metrics.MetricPublisher, client *http.Client, -) func(stack *middleware.Stack) error { - connectionCounter := &metrics.SharedConnectionCounter{} - return func(stack *middleware.Stack) error { - if err := stack.Initialize.Add(GetSetupMetricCollectionMiddleware(connectionCounter, publisher), middleware.Before); err != nil { - return err - } - if err := stack.Serialize.Add(GetRecordStackSerializeStartMiddleware(), middleware.Before); err != nil { - return err - } - if err := stack.Serialize.Add(GetRecordStackSerializeEndMiddleware(), middleware.After); err != nil { - return err - } - if err := stack.Finalize.Insert(GetRecordEndpointResolutionStartMiddleware(), "ResolveEndpointV2", middleware.Before); err != nil { - return err - } - if err := stack.Finalize.Insert(GetRecordEndpointResolutionEndMiddleware(), "ResolveEndpointV2", middleware.After); err != nil { - return err - } - if err := stack.Build.Add(GetWrapDataStreamMiddleware(), middleware.After); err != nil { - return err - } - if err := stack.Finalize.Add(GetRegisterRequestMetricContextMiddleware(), middleware.Before); err != nil { - return err - } - if err := stack.Finalize.Insert(GetRegisterAttemptMetricContextMiddleware(), "Retry", middleware.After); err != nil { - return err - } - if err := stack.Finalize.Add(GetHttpMetricMiddleware(client), middleware.After); err != nil { - return err - } - if err := stack.Deserialize.Add(GetRecordStackDeserializeStartMiddleware(), middleware.After); err != nil { - return err - } - if err := stack.Deserialize.Add(GetRecordStackDeserializeEndMiddleware(), middleware.Before); err != nil { - return err - } - if err := stack.Deserialize.Insert(GetTransportMetricsMiddleware(), "StackDeserializeStart", middleware.After); err != nil { - return err - } - if err := timeGetIdentity(stack); err != nil { - return err - } - if err := timeSigning(stack); err != nil { - return err - } - if err := stack.Build.Add(&captureUserAgent{}, middleware.After); err != nil { - return err - } - return nil - } -} diff --git a/aws/middleware/private/metrics/middleware/endpoint_resolution_end.go b/aws/middleware/private/metrics/middleware/endpoint_resolution_end.go deleted file mode 100644 index 5b7c13685b4..00000000000 --- a/aws/middleware/private/metrics/middleware/endpoint_resolution_end.go +++ /dev/null @@ -1,49 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -type EndpointResolutionEnd struct{} - -func GetRecordEndpointResolutionEndMiddleware() *EndpointResolutionEnd { - return &EndpointResolutionEnd{} -} - -func (m *EndpointResolutionEnd) ID() string { - return "EndpointResolutionEnd" -} - -// Deprecated: Endpoint resolution now occurs in Finalize. The ResolveEndpoint -// middleware remains in serialize but is largely a no-op. -func (m *EndpointResolutionEnd) HandleSerialize( - ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler, -) ( - out middleware.SerializeOutput, metadata middleware.Metadata, err error, -) { - - mctx := metrics.Context(ctx) - mctx.Data().ResolveEndpointEndTime = sdk.NowTime() - - out, metadata, err = next.HandleSerialize(ctx, in) - - return out, metadata, err -} - -func (m *EndpointResolutionEnd) HandleFinalize( - ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, -) ( - middleware.FinalizeOutput, middleware.Metadata, error, -) { - mctx := metrics.Context(ctx) - mctx.Data().ResolveEndpointEndTime = sdk.NowTime() - return next.HandleFinalize(ctx, in) -} diff --git a/aws/middleware/private/metrics/middleware/endpoint_resolution_end_test.go b/aws/middleware/private/metrics/middleware/endpoint_resolution_end_test.go deleted file mode 100644 index 6a82b5eda3f..00000000000 --- a/aws/middleware/private/metrics/middleware/endpoint_resolution_end_test.go +++ /dev/null @@ -1,32 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" - "testing" - "time" -) - -func TestEndpointResolutionEnd_HandleSerialize(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - ctx := metrics.InitMetricContext(context.TODO(), &metrics.SharedConnectionCounter{}, &testutils.NoopPublisher{}) - mw := GetRecordEndpointResolutionEndMiddleware() - _, _, _ = mw.HandleSerialize(ctx, middleware.SerializeInput{}, testutils.NoopSerializeHandler{}) - - actualTime := metrics.Context(ctx).Data().ResolveEndpointEndTime - expectedTime := sdk.NowTime() - if actualTime != expectedTime { - t.Errorf("Unexpected ResolveEndpointEndTime, should be '%s' but was '%s'", expectedTime, actualTime) - } -} diff --git a/aws/middleware/private/metrics/middleware/endpoint_resolution_start.go b/aws/middleware/private/metrics/middleware/endpoint_resolution_start.go deleted file mode 100644 index 0ead331fb84..00000000000 --- a/aws/middleware/private/metrics/middleware/endpoint_resolution_start.go +++ /dev/null @@ -1,49 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -type EndpointResolutionStart struct{} - -func GetRecordEndpointResolutionStartMiddleware() *EndpointResolutionStart { - return &EndpointResolutionStart{} -} - -func (m *EndpointResolutionStart) ID() string { - return "EndpointResolutionStart" -} - -// Deprecated: Endpoint resolution now occurs in Finalize. The ResolveEndpoint -// middleware remains in serialize but is largely a no-op. -func (m *EndpointResolutionStart) HandleSerialize( - ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler, -) ( - out middleware.SerializeOutput, metadata middleware.Metadata, err error, -) { - - mctx := metrics.Context(ctx) - mctx.Data().ResolveEndpointStartTime = sdk.NowTime() - - out, metadata, err = next.HandleSerialize(ctx, in) - - return out, metadata, err -} - -func (m *EndpointResolutionStart) HandleFinalize( - ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, -) ( - middleware.FinalizeOutput, middleware.Metadata, error, -) { - mctx := metrics.Context(ctx) - mctx.Data().ResolveEndpointStartTime = sdk.NowTime() - return next.HandleFinalize(ctx, in) -} diff --git a/aws/middleware/private/metrics/middleware/endpoint_resolution_start_test.go b/aws/middleware/private/metrics/middleware/endpoint_resolution_start_test.go deleted file mode 100644 index 5867825c0b3..00000000000 --- a/aws/middleware/private/metrics/middleware/endpoint_resolution_start_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" - "testing" - "time" -) - -func TestEndpointResolutionStart_HandleSerialize_Success(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, &testutils.NoopPublisher{}) - mw := GetRecordEndpointResolutionStartMiddleware() - _, _, _ = mw.HandleSerialize(ctx, middleware.SerializeInput{}, testutils.NoopSerializeHandler{}) - - actualTime := metrics.Context(ctx).Data().ResolveEndpointStartTime - expectedTime := sdk.NowTime() - if actualTime != expectedTime { - t.Errorf("Unexpected ResolveEndpointStartTime, should be '%s' but was '%s'", expectedTime, actualTime) - } -} - -func TestEndpointResolutionStart_HandleSerialize_Error(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - ctx := metrics.InitMetricContext(context.TODO(), &metrics.SharedConnectionCounter{}, &testutils.NoopPublisher{}) - - mw := GetRecordEndpointResolutionStartMiddleware() - _, _, _ = mw.HandleSerialize(ctx, middleware.SerializeInput{}, testutils.NoopSerializeHandler{}) - - actualTime := metrics.Context(ctx).Data().ResolveEndpointStartTime - expectedTime := sdk.NowTime() - if actualTime != expectedTime { - t.Errorf("Unexpected ResolveEndpointStartTime, should be '%s' but was '%s'", expectedTime, actualTime) - } -} diff --git a/aws/middleware/private/metrics/middleware/http.go b/aws/middleware/private/metrics/middleware/http.go deleted file mode 100644 index 95cbffd96dc..00000000000 --- a/aws/middleware/private/metrics/middleware/http.go +++ /dev/null @@ -1,154 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "fmt" - "net/http" - "net/http/httptrace" - "reflect" - "time" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -const ( - idleConnFieldName = "idleConn" - addressFieldName = "addr" - unkHttpClientName = "Other" - defaultHttpClientName = "Default" -) - -type HTTPMetrics struct { - client *http.Client -} - -func GetHttpMetricMiddleware(client *http.Client) *HTTPMetrics { - return &HTTPMetrics{ - client: client, - } -} - -func (m *HTTPMetrics) ID() string { - return "HTTPMetrics" -} - -func (m *HTTPMetrics) HandleFinalize( - ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, -) ( - out middleware.FinalizeOutput, metadata middleware.Metadata, attemptError error, -) { - ctx = m.addTraceContext(ctx) - finalize, metadata, err := next.HandleFinalize(ctx, in) - return finalize, metadata, err -} - -var addClientTrace = func(ctx context.Context, trace *httptrace.ClientTrace) context.Context { - return httptrace.WithClientTrace(ctx, trace) -} - -func (m *HTTPMetrics) addTraceContext(ctx context.Context) context.Context { - mctx := metrics.Context(ctx) - counter := mctx.ConnectionCounter() - - attemptMetrics, attemptErr := mctx.Data().LatestAttempt() - - if attemptErr == nil { - trace := &httptrace.ClientTrace{ - GotFirstResponseByte: func() { - gotFirstResponseByte(attemptMetrics, sdk.NowTime()) - }, - GetConn: func(hostPort string) { - getConn(attemptMetrics, counter, sdk.NowTime(), m.client, hostPort) - }, - GotConn: func(info httptrace.GotConnInfo) { - gotConn(attemptMetrics, counter, info, time.Now()) - }, - } - - ctx = addClientTrace(ctx, trace) - } else { - fmt.Println(attemptErr) - } - return ctx -} - -func gotFirstResponseByte(attemptMetrics *metrics.AttemptMetrics, now time.Time) { - attemptMetrics.FirstByteTime = now -} - -func getConn( - attemptMetrics *metrics.AttemptMetrics, counter *metrics.SharedConnectionCounter, now time.Time, client *http.Client, hostPort string, -) { - attemptMetrics.ConnRequestedTime = now - attemptMetrics.PendingConnectionAcquires = int(counter.PendingConnectionAcquire()) - attemptMetrics.ActiveRequests = int(counter.ActiveRequests()) - - // Adding HTTP client metrics here since we need the hostPort to identify the correct conn queues. - addHTTPClientMetrics(attemptMetrics, client, hostPort) - counter.AddPendingConnectionAcquire() -} - -func gotConn( - attemptMetrics *metrics.AttemptMetrics, counter *metrics.SharedConnectionCounter, info httptrace.GotConnInfo, now time.Time, -) { - attemptMetrics.ReusedConnection = info.Reused - attemptMetrics.ConnObtainedTime = now - counter.RemovePendingConnectionAcquire() -} - -func addHTTPClientMetrics(attemptMetrics *metrics.AttemptMetrics, client *http.Client, hostPort string) { - - maxConnsPerHost := -1 - idleConnCountPerHost := -1 - httpClient := unkHttpClientName - - clientInterface := interface{}(client) - - switch clientInterface.(type) { - // If not a standard HTTP client we cannot retrieve these metrics - case *http.Client: - transport := clientInterface.(*http.Client).Transport - httpClient = defaultHttpClientName - switch transport.(type) { - case *http.Transport: - - maxConnsPerHost = transport.(*http.Transport).MaxConnsPerHost - - transportPtr := reflect.ValueOf(transport.(*http.Transport)) - - if transportPtr.IsValid() && transportPtr.Kind() == reflect.Pointer { - - transportValue := transportPtr.Elem() - idleConn := transportValue.FieldByName(idleConnFieldName) - - if idleConn.IsValid() && idleConn.Kind() == reflect.Map { - - IdleConnMap := idleConn.MapRange() - // We iterate through all the connection queues to look for the target host - for IdleConnMap.Next() { - address := IdleConnMap.Key().FieldByName(addressFieldName) - - if address.IsValid() && address.Kind() == reflect.String { - - if address.String() == hostPort { - // Number of idle connections for the requests host - idleConnCountPerHost = IdleConnMap.Value().Len() - break - } - } - } - } - } - } - } - - attemptMetrics.HTTPClient = httpClient - attemptMetrics.AvailableConcurrency = idleConnCountPerHost - attemptMetrics.MaxConcurrency = maxConnsPerHost -} diff --git a/aws/middleware/private/metrics/middleware/http_test.go b/aws/middleware/private/metrics/middleware/http_test.go deleted file mode 100644 index 15d7caa2036..00000000000 --- a/aws/middleware/private/metrics/middleware/http_test.go +++ /dev/null @@ -1,146 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "net/http" - "net/http/httptrace" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -func TestHTTPMetrics_HandleFinalizes(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - counter := metrics.SharedConnectionCounter{} - - client := http.Client{ - Transport: &http.Transport{ - MaxIdleConnsPerHost: 10, - }, - } - - ctx := metrics.InitMetricContext(context.TODO(), &counter, &testutils.NoopPublisher{}) - - mw := GetHttpMetricMiddleware(&client) - - mctx := metrics.Context(ctx) - mctx.Data().NewAttempt() - - var traceInput *httptrace.ClientTrace - - addClientTrace = func(ctx context.Context, trace *httptrace.ClientTrace) context.Context { - traceInput = trace - return ctx - } - - _, _, _ = mw.HandleFinalize(ctx, middleware.FinalizeInput{}, testutils.NoopFinalizeHandler{}) - - if traceInput == nil { - t.Fatal("trace should be added to context") - } -} - -func TestHTTPMetrics_HandleFinalizes_AttemptErr(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - counter := metrics.SharedConnectionCounter{} - - client := http.Client{ - Transport: &http.Transport{ - MaxIdleConnsPerHost: 10, - }, - } - - ctx := metrics.InitMetricContext(context.TODO(), &counter, &testutils.NoopPublisher{}) - - mw := GetHttpMetricMiddleware(&client) - - var traceInput *httptrace.ClientTrace - - addClientTrace = func(ctx context.Context, trace *httptrace.ClientTrace) context.Context { - traceInput = trace - return ctx - } - - _, _, _ = mw.HandleFinalize(ctx, middleware.FinalizeInput{}, testutils.NoopFinalizeHandler{}) - - if traceInput != nil { - t.Fatal("trace should not be added to context") - } - -} - -func TestHTTPMetrics_callbacks(t *testing.T) { - - counter := metrics.SharedConnectionCounter{} - - client := http.Client{ - Transport: &http.Transport{ - MaxIdleConnsPerHost: 10, - }, - } - - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &counter, &testutils.NoopPublisher{}) - mctx := metrics.Context(ctx) - mctx.Data().NewAttempt() - attempt, _ := mctx.Data().LatestAttempt() - - counter.AddPendingConnectionAcquire() - counter.AddActiveRequest() - - gotFirstResponseByte(attempt, sdk.NowTime()) - - getConn(attempt, &counter, sdk.NowTime(), &client, "hostPort") - - gotConn(attempt, &counter, httptrace.GotConnInfo{ - Conn: nil, - Reused: false, - WasIdle: false, - IdleTime: 0, - }, sdk.NowTime()) - - actualConnRequestedTime := attempt.ConnRequestedTime - expectedConnRequestedTime := sdk.NowTime() - - if actualConnRequestedTime != expectedConnRequestedTime { - t.Errorf("Unexpected ConnRequestedTime, should be '%s' but was '%s'", expectedConnRequestedTime, actualConnRequestedTime) - } - - actualPendingConnectionAcquires := attempt.PendingConnectionAcquires - expectedPendingConnectionAcquires := 1 - - if actualPendingConnectionAcquires != expectedPendingConnectionAcquires { - t.Errorf("Unexpected PendingConnectionAcquires, should be '%d' but was '%d'", expectedPendingConnectionAcquires, actualPendingConnectionAcquires) - } - - actualActiveRequests := attempt.ActiveRequests - expectedActiveRequests := 1 - - if actualActiveRequests != expectedActiveRequests { - t.Errorf("Unexpected ActiveRequests, should be '%d' but was '%d'", expectedActiveRequests, actualActiveRequests) - } - - actualConnObtainedTime := attempt.ConnObtainedTime - expectedConnObtainedTime := sdk.NowTime() - - if actualConnObtainedTime != expectedConnObtainedTime { - t.Errorf("Unexpected ConnObtainedTime, should be '%s' but was '%s'", actualConnObtainedTime, expectedConnObtainedTime) - } - -} diff --git a/aws/middleware/private/metrics/middleware/identity.go b/aws/middleware/private/metrics/middleware/identity.go deleted file mode 100644 index b0a1c6b5cb1..00000000000 --- a/aws/middleware/private/metrics/middleware/identity.go +++ /dev/null @@ -1,47 +0,0 @@ -package middleware - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -func timeGetIdentity(stack *middleware.Stack) error { - if err := stack.Finalize.Insert(getIdentityStart{}, "GetIdentity", middleware.Before); err != nil { - return err - } - if err := stack.Finalize.Insert(getIdentityEnd{}, "GetIdentity", middleware.After); err != nil { - return err - } - return nil -} - -type getIdentityStart struct{} - -func (m getIdentityStart) ID() string { return "getIdentityStart" } - -func (m getIdentityStart) HandleFinalize( - ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, -) ( - out middleware.FinalizeOutput, md middleware.Metadata, err error, -) { - mctx := metrics.Context(ctx) - mctx.Data().GetIdentityStartTime = sdk.NowTime() - return next.HandleFinalize(ctx, in) -} - -type getIdentityEnd struct{} - -func (m getIdentityEnd) ID() string { return "getIdentityEnd" } - -func (m getIdentityEnd) HandleFinalize( - ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, -) ( - out middleware.FinalizeOutput, md middleware.Metadata, err error, -) { - mctx := metrics.Context(ctx) - mctx.Data().GetIdentityEndTime = sdk.NowTime() - return next.HandleFinalize(ctx, in) -} diff --git a/aws/middleware/private/metrics/middleware/metric_collection.go b/aws/middleware/private/metrics/middleware/metric_collection.go deleted file mode 100644 index c553d1a114a..00000000000 --- a/aws/middleware/private/metrics/middleware/metric_collection.go +++ /dev/null @@ -1,64 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "fmt" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -type MetricCollection struct { - cc *metrics.SharedConnectionCounter - publisher metrics.MetricPublisher -} - -func GetSetupMetricCollectionMiddleware( - counter *metrics.SharedConnectionCounter, publisher metrics.MetricPublisher, -) *MetricCollection { - return &MetricCollection{ - cc: counter, - publisher: publisher, - } -} - -func (m *MetricCollection) ID() string { - return "MetricCollection" -} - -func (m *MetricCollection) HandleInitialize( - ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, -) ( - out middleware.InitializeOutput, metadata middleware.Metadata, err error, -) { - - ctx = metrics.InitMetricContext(ctx, m.cc, m.publisher) - - mctx := metrics.Context(ctx) - metricData := mctx.Data() - - metricData.RequestStartTime = sdk.NowTime() - - out, metadata, err = next.HandleInitialize(ctx, in) - - metricData.RequestEndTime = sdk.NowTime() - - if err == nil { - metricData.Success = 1 - } else { - metricData.Success = 0 - } - - metricData.ComputeRequestMetrics() - - publishErr := m.publisher.PostRequestMetrics(metrics.Context(ctx).Data()) - if publishErr != nil { - fmt.Println("Failed to post request metrics") - } - - return out, metadata, err -} diff --git a/aws/middleware/private/metrics/middleware/metric_collection_test.go b/aws/middleware/private/metrics/middleware/metric_collection_test.go deleted file mode 100644 index 7f28ad38242..00000000000 --- a/aws/middleware/private/metrics/middleware/metric_collection_test.go +++ /dev/null @@ -1,89 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -func TestGetSetupMetricCollectionMiddleware(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - cases := map[string]struct { - ConnectionCounter *metrics.SharedConnectionCounter - Publisher metrics.MetricPublisher - Input middleware.InitializeInput - Handler middleware.InitializeHandler - ExpectedStartTime time.Time - ExpectedEndTime time.Time - ExpectedSuccess uint8 - }{ - "success": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: &testutils.NoopPublisher{}, - Input: middleware.InitializeInput{}, - Handler: testutils.NoopInitializeHandler{}, - ExpectedStartTime: time.Unix(1234, 0), - ExpectedEndTime: time.Unix(1234, 0), - ExpectedSuccess: 1, - }, - "!success": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: &testutils.NoopPublisher{}, - Input: middleware.InitializeInput{}, - Handler: testutils.ErrorInitializeHandler{}, - ExpectedStartTime: time.Unix(1234, 0), - ExpectedEndTime: time.Unix(1234, 0), - ExpectedSuccess: 0, - }, - "publisherFailure": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: &testutils.ErrorPublisher{}, - Input: middleware.InitializeInput{}, - Handler: testutils.NoopInitializeHandler{}, - ExpectedStartTime: time.Unix(1234, 0), - ExpectedEndTime: time.Unix(1234, 0), - ExpectedSuccess: 1, - }, - } - - for name, c := range cases { - t.Run(name, func(t *testing.T) { - - ctx := metrics.InitMetricContext(context.TODO(), c.ConnectionCounter, c.Publisher) - - mw := GetSetupMetricCollectionMiddleware(c.ConnectionCounter, c.Publisher) - - _, _, _ = mw.HandleInitialize(ctx, c.Input, c.Handler) - - mctx := metrics.Context(ctx) - - actualRequestStartTime := mctx.Data().RequestStartTime - actualRequestEndTime := mctx.Data().RequestEndTime - - if actualRequestStartTime != c.ExpectedStartTime { - t.Errorf("Unexpected RequestStartTime, should be '%s' but was '%s'", c.ExpectedStartTime, actualRequestStartTime) - } - if actualRequestEndTime != c.ExpectedEndTime { - t.Errorf("Unexpected RequestEndTime, should be '%s' but was '%s'", c.ExpectedEndTime, actualRequestEndTime) - } - if mctx.Data().Success != c.ExpectedSuccess { - t.Errorf("Unexpected Success status, should be '%d' but was '%d'", c.ExpectedSuccess, mctx.Data().Success) - } - - }) - } - -} diff --git a/aws/middleware/private/metrics/middleware/request.go b/aws/middleware/private/metrics/middleware/request.go deleted file mode 100644 index 983fa9c5d58..00000000000 --- a/aws/middleware/private/metrics/middleware/request.go +++ /dev/null @@ -1,61 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - - awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/smithy-go/middleware" - smithyhttp "github.com/aws/smithy-go/transport/http" -) - -const ( - clientRequestIdKey = "Amz-Sdk-Invocation-Id" - unkClientId = "unk" -) - -type RegisterMetricContext struct{} - -func GetRegisterRequestMetricContextMiddleware() *RegisterMetricContext { - return &RegisterMetricContext{} -} - -func (m *RegisterMetricContext) ID() string { - return "RegisterMetricContext" -} - -func (m *RegisterMetricContext) HandleFinalize( - ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, -) ( - out middleware.FinalizeOutput, metadata middleware.Metadata, err error, -) { - - mctx := metrics.Context(ctx) - metricData := mctx.Data() - - metricData.ServiceID = awsmiddleware.GetServiceID(ctx) - metricData.OperationName = awsmiddleware.GetOperationName(ctx) - metricData.PartitionID = awsmiddleware.GetPartitionID(ctx) - metricData.Region = awsmiddleware.GetSigningRegion(ctx) - - switch req := in.Request.(type) { - case *smithyhttp.Request: - crid := req.Header.Get(clientRequestIdKey) - if len(crid) == 0 { - crid = unkClientId - } - metricData.ClientRequestID = crid - metricData.RequestContentLength = req.ContentLength - default: - metricData.ClientRequestID = unkClientId - metricData.RequestContentLength = -1 - } - - out, metadata, err = next.HandleFinalize(ctx, in) - - return out, metadata, err -} diff --git a/aws/middleware/private/metrics/middleware/request_attempt.go b/aws/middleware/private/metrics/middleware/request_attempt.go deleted file mode 100644 index a8a9e10c14c..00000000000 --- a/aws/middleware/private/metrics/middleware/request_attempt.go +++ /dev/null @@ -1,70 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - - awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/smithy-go/middleware" - "github.com/aws/smithy-go/transport/http" -) - -const ( - amznRequestIdKey = "X-Amz-Request-Id" - amznRequestId2Key = "X-Amz-Id-2" - unkAmznReqId = "unk" - unkAmznReqId2 = "unk" -) - -type RegisterAttemptMetricContext struct{} - -func GetRegisterAttemptMetricContextMiddleware() *RegisterAttemptMetricContext { - return &RegisterAttemptMetricContext{} -} - -func (m *RegisterAttemptMetricContext) ID() string { - return "RegisterAttemptMetricContext" -} - -var getRawResponse = func(metadata middleware.Metadata) *http.Response { - switch res := awsmiddleware.GetRawResponse(metadata).(type) { - case *http.Response: - return res - default: - return nil - } -} - -func (m *RegisterAttemptMetricContext) HandleFinalize( - ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, -) ( - out middleware.FinalizeOutput, metadata middleware.Metadata, err error, -) { - - mctx := metrics.Context(ctx) - mctx.Data().NewAttempt() - - out, metadata, err = next.HandleFinalize(ctx, in) - - res := getRawResponse(metadata) - - attemptMetrics, _ := mctx.Data().LatestAttempt() - - if res != nil { - attemptMetrics.RequestID = res.Header.Get(amznRequestIdKey) - attemptMetrics.ExtendedRequestID = res.Header.Get(amznRequestId2Key) - attemptMetrics.StatusCode = res.StatusCode - attemptMetrics.ResponseContentLength = res.ContentLength - } else { - attemptMetrics.RequestID = unkAmznReqId - attemptMetrics.ExtendedRequestID = unkAmznReqId2 - attemptMetrics.StatusCode = -1 - attemptMetrics.ResponseContentLength = -1 - } - - return out, metadata, err -} diff --git a/aws/middleware/private/metrics/middleware/request_attempt_test.go b/aws/middleware/private/metrics/middleware/request_attempt_test.go deleted file mode 100644 index 96408760a9b..00000000000 --- a/aws/middleware/private/metrics/middleware/request_attempt_test.go +++ /dev/null @@ -1,114 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "net/http" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" - smithyhttp "github.com/aws/smithy-go/transport/http" -) - -func TestRegisterAttemptMetricContext_HandleFinalize(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - cases := map[string]struct { - ConnectionCounter *metrics.SharedConnectionCounter - Publisher metrics.MetricPublisher - ProvideResponse func(metadata middleware.Metadata) *smithyhttp.Response - Handler middleware.FinalizeHandler - Input middleware.FinalizeInput - ExpectedRequestId string - ExpectedExtendedRequestId string - ExpectedStatusCode int - ExpectedResponseContentLength int64 - }{ - "success": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: &testutils.NoopPublisher{}, - ProvideResponse: func(metadata middleware.Metadata) *smithyhttp.Response { - res := smithyhttp.Response{} - res.Response = &http.Response{ - StatusCode: 400, - ContentLength: 1234, - Header: map[string][]string{}, - } - res.Header.Set(amznRequestIdKey, "reqId") - res.Header.Set(amznRequestId2Key, "reqId2") - return &res - }, - Handler: testutils.NoopFinalizeHandler{}, - Input: middleware.FinalizeInput{}, - ExpectedRequestId: "reqId", - ExpectedExtendedRequestId: "reqId2", - ExpectedStatusCode: 400, - ExpectedResponseContentLength: 1234, - }, - "noResInfo": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: &testutils.NoopPublisher{}, - ProvideResponse: func(metadata middleware.Metadata) *smithyhttp.Response { - return nil - }, - Handler: testutils.NoopFinalizeHandler{}, - ExpectedRequestId: unkAmznReqId, - ExpectedExtendedRequestId: unkAmznReqId2, - ExpectedStatusCode: -1, - ExpectedResponseContentLength: -1, - }, - "noMetadata": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: &testutils.NoopPublisher{}, - ProvideResponse: getRawResponse, - Handler: testutils.NoopFinalizeHandler{}, - ExpectedRequestId: unkAmznReqId, - ExpectedExtendedRequestId: unkAmznReqId2, - ExpectedStatusCode: -1, - ExpectedResponseContentLength: -1, - }, - } - - for name, c := range cases { - t.Run(name, func(t *testing.T) { - - getRawResponse = c.ProvideResponse - - ctx := metrics.InitMetricContext(context.TODO(), c.ConnectionCounter, c.Publisher) - - mw := GetRegisterAttemptMetricContextMiddleware() - - _, _, _ = mw.HandleFinalize(ctx, c.Input, c.Handler) - - latestAttempt, _ := metrics.Context(ctx).Data().LatestAttempt() - actualRequestId := latestAttempt.RequestID - actualExtendedRequestId := latestAttempt.ExtendedRequestID - actualStatusCode := latestAttempt.StatusCode - actualResponseContentLength := latestAttempt.ResponseContentLength - - if actualRequestId != c.ExpectedRequestId { - t.Errorf("Unexpected RequestId, should be '%s' but was '%s'", c.ExpectedRequestId, actualRequestId) - } - if actualExtendedRequestId != c.ExpectedExtendedRequestId { - t.Errorf("Unexpected ExtendedRequestId, should be '%s' but was '%s'", c.ExpectedExtendedRequestId, actualExtendedRequestId) - } - if actualStatusCode != c.ExpectedStatusCode { - t.Errorf("Unexpected StatusCode, should be '%d' but was '%d'", c.ExpectedStatusCode, actualStatusCode) - } - if actualResponseContentLength != c.ExpectedResponseContentLength { - t.Errorf("Unexpected StatusCode, should be '%d' but was '%d'", c.ExpectedResponseContentLength, actualResponseContentLength) - } - }) - } - -} diff --git a/aws/middleware/private/metrics/middleware/request_test.go b/aws/middleware/private/metrics/middleware/request_test.go deleted file mode 100644 index 84dc4eac9ee..00000000000 --- a/aws/middleware/private/metrics/middleware/request_test.go +++ /dev/null @@ -1,86 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "testing" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/smithy-go/middleware" - smithyhttp "github.com/aws/smithy-go/transport/http" -) - -func TestRegisterMetricContext_HandleFinalize(t *testing.T) { - - cases := map[string]struct { - ConnectionCounter *metrics.SharedConnectionCounter - Publisher metrics.MetricPublisher - ProvideInput func() middleware.FinalizeInput - Handler middleware.FinalizeHandler - ExpectedCrId string - }{ - "success": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: &testutils.NoopPublisher{}, - ProvideInput: func() middleware.FinalizeInput { - req := smithyhttp.NewStackRequest().(*smithyhttp.Request) - req.Header.Set(clientRequestIdKey, "crid") - return middleware.FinalizeInput{Request: req} - }, - Handler: testutils.NoopFinalizeHandler{}, - ExpectedCrId: "crid", - }, - "noCrIdHeader": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: &testutils.NoopPublisher{}, - ProvideInput: func() middleware.FinalizeInput { - req := smithyhttp.NewStackRequest().(*smithyhttp.Request) - return middleware.FinalizeInput{Request: req} - }, - Handler: testutils.NoopFinalizeHandler{}, - ExpectedCrId: unkClientId, - }, - "nilRequest": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: &testutils.NoopPublisher{}, - ProvideInput: func() middleware.FinalizeInput { - return middleware.FinalizeInput{Request: nil} - }, - Handler: testutils.NoopFinalizeHandler{}, - ExpectedCrId: unkClientId, - }, - "wrongRequestType": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: &testutils.NoopPublisher{}, - ProvideInput: func() middleware.FinalizeInput { - return middleware.FinalizeInput{Request: "nil"} - }, - Handler: testutils.NoopFinalizeHandler{}, - ExpectedCrId: unkClientId, - }, - } - - for name, c := range cases { - t.Run(name, func(t *testing.T) { - - ctx := metrics.InitMetricContext(context.TODO(), c.ConnectionCounter, c.Publisher) - - mw := GetRegisterRequestMetricContextMiddleware() - - _, _, _ = mw.HandleFinalize(ctx, c.ProvideInput(), c.Handler) - - mctx := metrics.Context(ctx) - actualCrId := mctx.Data().ClientRequestID - - if actualCrId != c.ExpectedCrId { - t.Errorf("Unexpected ClientRequestId, should be '%s' but was '%s'", c.ExpectedCrId, actualCrId) - } - - }) - } - -} diff --git a/aws/middleware/private/metrics/middleware/signing.go b/aws/middleware/private/metrics/middleware/signing.go deleted file mode 100644 index 8c7c0cf4282..00000000000 --- a/aws/middleware/private/metrics/middleware/signing.go +++ /dev/null @@ -1,57 +0,0 @@ -package middleware - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -func timeSigning(stack *middleware.Stack) error { - if err := stack.Finalize.Insert(signingStart{}, "Signing", middleware.Before); err != nil { - return err - } - if err := stack.Finalize.Insert(signingEnd{}, "Signing", middleware.After); err != nil { - return err - } - return nil -} - -type signingStart struct{} - -func (m signingStart) ID() string { return "signingStart" } - -func (m signingStart) HandleFinalize( - ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, -) ( - out middleware.FinalizeOutput, md middleware.Metadata, err error, -) { - mctx := metrics.Context(ctx) - attempt, err := mctx.Data().LatestAttempt() - if err != nil { - return out, md, err - } - - attempt.SignStartTime = sdk.NowTime() - return next.HandleFinalize(ctx, in) -} - -type signingEnd struct{} - -func (m signingEnd) ID() string { return "signingEnd" } - -func (m signingEnd) HandleFinalize( - ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, -) ( - out middleware.FinalizeOutput, md middleware.Metadata, err error, -) { - mctx := metrics.Context(ctx) - attempt, err := mctx.Data().LatestAttempt() - if err != nil { - return out, md, err - } - - attempt.SignEndTime = sdk.NowTime() - return next.HandleFinalize(ctx, in) -} diff --git a/aws/middleware/private/metrics/middleware/stack_deserialize_end.go b/aws/middleware/private/metrics/middleware/stack_deserialize_end.go deleted file mode 100644 index ac9e109f385..00000000000 --- a/aws/middleware/private/metrics/middleware/stack_deserialize_end.go +++ /dev/null @@ -1,45 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "fmt" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -type StackDeserializeEnd struct{} - -func GetRecordStackDeserializeEndMiddleware() *StackDeserializeEnd { - return &StackDeserializeEnd{} -} - -func (m *StackDeserializeEnd) ID() string { - return "StackDeserializeEnd" -} - -func (m *StackDeserializeEnd) HandleDeserialize( - ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler, -) ( - out middleware.DeserializeOutput, metadata middleware.Metadata, attemptErr error, -) { - - out, metadata, err := next.HandleDeserialize(ctx, in) - - mctx := metrics.Context(ctx) - - attemptMetrics, attemptErr := mctx.Data().LatestAttempt() - - if attemptErr != nil { - fmt.Println(attemptErr) - } else { - attemptMetrics.DeserializeEndTime = sdk.NowTime() - } - - return out, metadata, err - -} diff --git a/aws/middleware/private/metrics/middleware/stack_deserialize_end_test.go b/aws/middleware/private/metrics/middleware/stack_deserialize_end_test.go deleted file mode 100644 index a47d922cbeb..00000000000 --- a/aws/middleware/private/metrics/middleware/stack_deserialize_end_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" - "testing" - "time" -) - -func TestStackDeserializeEnd_HandleDeserializeSuccess(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, &testutils.NoopPublisher{}) - mw := GetRecordStackDeserializeEndMiddleware() - - data := metrics.Context(ctx).Data() - - data.NewAttempt() - - _, _, _ = mw.HandleDeserialize(ctx, middleware.DeserializeInput{}, testutils.NoopDeserializeHandler{}) - - attempt, _ := data.LatestAttempt() - actualTime := attempt.DeserializeEndTime - expectedTime := sdk.NowTime() - if actualTime != expectedTime { - t.Errorf("Unexpected DeserializeEndTime, should be '%s' but was '%s'", expectedTime, actualTime) - } -} - -func TestStackDeserializeEnd_HandleDeserializeNoAttempt(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, &testutils.NoopPublisher{}) - mw := GetRecordStackDeserializeEndMiddleware() - - data := metrics.Context(ctx).Data() - - _, _, _ = mw.HandleDeserialize(ctx, middleware.DeserializeInput{}, testutils.NoopDeserializeHandler{}) - - attempt, err := data.LatestAttempt() - - if attempt != nil { - t.Errorf("Attempt should be nil") - } - if err == nil { - t.Errorf("Err should not be nil") - } -} diff --git a/aws/middleware/private/metrics/middleware/stack_deserialize_start.go b/aws/middleware/private/metrics/middleware/stack_deserialize_start.go deleted file mode 100644 index c21e79df534..00000000000 --- a/aws/middleware/private/metrics/middleware/stack_deserialize_start.go +++ /dev/null @@ -1,44 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "fmt" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -type StackDeserializeStart struct{} - -func GetRecordStackDeserializeStartMiddleware() *StackDeserializeStart { - return &StackDeserializeStart{} -} - -func (m *StackDeserializeStart) ID() string { - return "StackDeserializeStart" -} - -func (m *StackDeserializeStart) HandleDeserialize( - ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler, -) ( - out middleware.DeserializeOutput, metadata middleware.Metadata, err error, -) { - - out, metadata, err = next.HandleDeserialize(ctx, in) - - mctx := metrics.Context(ctx) - - attemptMetrics, attemptErr := mctx.Data().LatestAttempt() - - if attemptErr != nil { - fmt.Println(err) - } else { - attemptMetrics.DeserializeStartTime = sdk.NowTime() - } - - return out, metadata, err -} diff --git a/aws/middleware/private/metrics/middleware/stack_deserialize_start_test.go b/aws/middleware/private/metrics/middleware/stack_deserialize_start_test.go deleted file mode 100644 index a2c5fabec0d..00000000000 --- a/aws/middleware/private/metrics/middleware/stack_deserialize_start_test.go +++ /dev/null @@ -1,59 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" - "testing" - "time" -) - -func TestStackDeserializeStart_HandleDeserializeSuccess(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, &testutils.NoopPublisher{}) - mw := GetRecordStackDeserializeStartMiddleware() - - data := metrics.Context(ctx).Data() - - data.NewAttempt() - - _, _, _ = mw.HandleDeserialize(ctx, middleware.DeserializeInput{}, testutils.NoopDeserializeHandler{}) - - attempt, _ := data.LatestAttempt() - actualTime := attempt.DeserializeStartTime - expectedTime := sdk.NowTime() - if actualTime != expectedTime { - t.Errorf("Unexpected DeserializeStartTime, should be '%s' but was '%s'", expectedTime, actualTime) - } -} - -func TestStackDeserializeStart_HandleDeserializeNoAttempt(t *testing.T) { - - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, &testutils.NoopPublisher{}) - mw := GetRecordStackDeserializeStartMiddleware() - - data := metrics.Context(ctx).Data() - - _, _, _ = mw.HandleDeserialize(ctx, middleware.DeserializeInput{}, testutils.NoopDeserializeHandler{}) - - attempt, err := data.LatestAttempt() - - if attempt != nil { - t.Errorf("Attempt should be nil") - } - if err == nil { - t.Errorf("Err should not be nil") - } -} diff --git a/aws/middleware/private/metrics/middleware/stack_serialize_end.go b/aws/middleware/private/metrics/middleware/stack_serialize_end.go deleted file mode 100644 index c742edcf240..00000000000 --- a/aws/middleware/private/metrics/middleware/stack_serialize_end.go +++ /dev/null @@ -1,33 +0,0 @@ -package middleware - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -type StackSerializeEnd struct{} - -func GetRecordStackSerializeEndMiddleware() *StackSerializeEnd { - return &StackSerializeEnd{} -} - -func (m *StackSerializeEnd) ID() string { - return "StackSerializeEnd" -} - -func (m *StackSerializeEnd) HandleSerialize( - ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler, -) ( - out middleware.SerializeOutput, metadata middleware.Metadata, err error, -) { - - mctx := metrics.Context(ctx) - mctx.Data().SerializeEndTime = sdk.NowTime() - - out, metadata, err = next.HandleSerialize(ctx, in) - - return out, metadata, err - -} diff --git a/aws/middleware/private/metrics/middleware/stack_serialize_end_test.go b/aws/middleware/private/metrics/middleware/stack_serialize_end_test.go deleted file mode 100644 index 66e5c349f25..00000000000 --- a/aws/middleware/private/metrics/middleware/stack_serialize_end_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package middleware - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" - "testing" - "time" -) - -func TestStartSerializeEnd_HandleSerialize(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, &testutils.NoopPublisher{}) - mw := GetRecordStackSerializeEndMiddleware() - _, _, _ = mw.HandleSerialize(ctx, middleware.SerializeInput{}, testutils.NoopSerializeHandler{}) - - actualTime := metrics.Context(ctx).Data().SerializeEndTime - expectedTime := sdk.NowTime() - if actualTime != expectedTime { - t.Errorf("Unexpected SerializeEndTime, should be '%s' but was '%s'", expectedTime, actualTime) - } -} diff --git a/aws/middleware/private/metrics/middleware/stack_serialize_start.go b/aws/middleware/private/metrics/middleware/stack_serialize_start.go deleted file mode 100644 index 996b32fcf6d..00000000000 --- a/aws/middleware/private/metrics/middleware/stack_serialize_start.go +++ /dev/null @@ -1,32 +0,0 @@ -package middleware - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -type StackSerializeStart struct{} - -func GetRecordStackSerializeStartMiddleware() *StackSerializeStart { - return &StackSerializeStart{} -} - -func (m *StackSerializeStart) ID() string { - return "StackSerializeStart" -} - -func (m *StackSerializeStart) HandleSerialize( - ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler, -) ( - out middleware.SerializeOutput, metadata middleware.Metadata, err error, -) { - - mctx := metrics.Context(ctx) - mctx.Data().SerializeStartTime = sdk.NowTime() - - out, metadata, err = next.HandleSerialize(ctx, in) - - return out, metadata, err -} diff --git a/aws/middleware/private/metrics/middleware/stack_serialize_start_test.go b/aws/middleware/private/metrics/middleware/stack_serialize_start_test.go deleted file mode 100644 index c5e536b588e..00000000000 --- a/aws/middleware/private/metrics/middleware/stack_serialize_start_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package middleware - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" - "testing" - "time" -) - -func TestStartSerializeStart_HandleSerialize(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, &testutils.NoopPublisher{}) - mw := GetRecordStackSerializeStartMiddleware() - _, _, _ = mw.HandleSerialize(ctx, middleware.SerializeInput{}, testutils.NoopSerializeHandler{}) - - actualTime := metrics.Context(ctx).Data().SerializeStartTime - expectedTime := sdk.NowTime() - if actualTime != expectedTime { - t.Errorf("Unexpected SerializeStartTime, should be '%s' but was '%s'", expectedTime, actualTime) - } -} diff --git a/aws/middleware/private/metrics/middleware/transport.go b/aws/middleware/private/metrics/middleware/transport.go deleted file mode 100644 index a43e1f9782f..00000000000 --- a/aws/middleware/private/metrics/middleware/transport.go +++ /dev/null @@ -1,46 +0,0 @@ -// This package is designated as private and is intended for use only by the -// smithy client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package middleware - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" -) - -type TransportMetrics struct{} - -func GetTransportMetricsMiddleware() *TransportMetrics { - return &TransportMetrics{} -} - -func (m *TransportMetrics) ID() string { - return "TransportMetrics" -} - -func (m *TransportMetrics) HandleDeserialize( - ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler, -) ( - out middleware.DeserializeOutput, metadata middleware.Metadata, attemptErr error, -) { - - mctx := metrics.Context(ctx) - - if attempt, e := mctx.Data().LatestAttempt(); e == nil { - attempt.ServiceCallStart = sdk.NowTime() - mctx.ConnectionCounter().AddActiveRequest() - } - - out, metadata, err := next.HandleDeserialize(ctx, in) - - if attempt, e := mctx.Data().LatestAttempt(); e == nil { - attempt.ServiceCallEnd = sdk.NowTime() - mctx.ConnectionCounter().RemoveActiveRequest() - } - - return out, metadata, err - -} diff --git a/aws/middleware/private/metrics/middleware/transport_test.go b/aws/middleware/private/metrics/middleware/transport_test.go deleted file mode 100644 index 258952751ed..00000000000 --- a/aws/middleware/private/metrics/middleware/transport_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package middleware - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "github.com/aws/smithy-go/middleware" - "testing" - "time" -) - -func TestTransportMetrics_HandleSerialize(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, &testutils.NoopPublisher{}) - - data := metrics.Context(ctx).Data() - - data.NewAttempt() - - mw := GetTransportMetricsMiddleware() - _, _, _ = mw.HandleDeserialize(ctx, middleware.DeserializeInput{}, testutils.NoopDeserializeHandler{}) - - attempt, _ := data.LatestAttempt() - - actualStartTime := attempt.ServiceCallStart - expectedStartTime := sdk.NowTime() - - if actualStartTime != expectedStartTime { - t.Errorf("Unexpected ServiceCallStart, should be '%s' but was '%s'", expectedStartTime, expectedStartTime) - } - - actualEndTime := attempt.ServiceCallEnd - expectedEndTime := sdk.NowTime() - - if actualEndTime != expectedEndTime { - t.Errorf("Unexpected ServiceCallEnd, should be '%s' but was '%s'", expectedEndTime, actualEndTime) - } - -} diff --git a/aws/middleware/private/metrics/middleware/user_agent.go b/aws/middleware/private/metrics/middleware/user_agent.go deleted file mode 100644 index 8f502ae84bc..00000000000 --- a/aws/middleware/private/metrics/middleware/user_agent.go +++ /dev/null @@ -1,29 +0,0 @@ -package middleware - -import ( - "context" - "fmt" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/smithy-go/middleware" - smithyhttp "github.com/aws/smithy-go/transport/http" -) - -type captureUserAgent struct{} - -func (*captureUserAgent) ID() string { return "captureUserAgent" } - -func (*captureUserAgent) HandleBuild( - ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler, -) ( - out middleware.BuildOutput, md middleware.Metadata, err error, -) { - r, ok := in.Request.(*smithyhttp.Request) - if !ok { - return out, md, fmt.Errorf("unexpected transport type %T", in.Request) - } - - mctx := metrics.Context(ctx) - mctx.Data().UserAgent = r.Header.Get("User-Agent") - return next.HandleBuild(ctx, in) -} diff --git a/aws/middleware/private/metrics/middleware/wrap_data_stream.go b/aws/middleware/private/metrics/middleware/wrap_data_stream.go deleted file mode 100644 index 7f7c5d54ebf..00000000000 --- a/aws/middleware/private/metrics/middleware/wrap_data_stream.go +++ /dev/null @@ -1,59 +0,0 @@ -package middleware - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/readcloserwithmetrics" - "github.com/aws/smithy-go/middleware" - "io" - "reflect" -) - -const ( - responseBodyFieldName = "Body" -) - -type WrapDataContext struct{} - -func GetWrapDataStreamMiddleware() *WrapDataContext { - return &WrapDataContext{} -} - -func (m *WrapDataContext) ID() string { - return "BuildWrapDataStream" -} - -func (m *WrapDataContext) HandleBuild( - ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler, -) ( - out middleware.BuildOutput, metadata middleware.Metadata, err error, -) { - - out, metadata, err = next.HandleBuild(ctx, in) - - value := reflect.ValueOf(out.Result) - - if value.Kind() != reflect.Ptr { - return out, metadata, err - } - value = value.Elem() - - if value.Kind() != reflect.Struct { - return out, metadata, err - } - bodyField := value.FieldByName(responseBodyFieldName) - - if !(bodyField.IsValid() && bodyField.CanInterface()) { - return out, metadata, err - } - - body, ok := bodyField.Interface().(io.ReadCloser) - - if !ok { - return out, metadata, err - } - - bodyField.Set(reflect.ValueOf(readcloserwithmetrics.New(metrics.Context(ctx), body))) - - return out, metadata, err -} diff --git a/aws/middleware/private/metrics/middleware/wrap_data_streams_test.go b/aws/middleware/private/metrics/middleware/wrap_data_streams_test.go deleted file mode 100644 index 1c5c477f243..00000000000 --- a/aws/middleware/private/metrics/middleware/wrap_data_streams_test.go +++ /dev/null @@ -1,114 +0,0 @@ -package middleware - -import ( - "context" - "io" - "reflect" - "testing" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "github.com/aws/smithy-go/middleware" -) - -type TestResult struct { - Body io.ReadCloser -} - -func TestWrapDataStream_HandleBuild(t *testing.T) { - - cases := map[string]struct { - ConnectionCounter *metrics.SharedConnectionCounter - Publisher testutils.MetricDataRecorderPublisher - Result *TestResult - Input middleware.BuildInput - ExpectedStreamData string - ExpectedMetricData metrics.StreamMetrics - }{ - "success": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: testutils.MetricDataRecorderPublisher{}, - Input: middleware.BuildInput{}, - Result: &TestResult{ - Body: &testutils.TestReadCloser{Data: []byte("testString")}, - }, - ExpectedStreamData: "testString", - ExpectedMetricData: metrics.StreamMetrics{ - ReadDuration: 0, - ReadBytes: 10, - }, - }, - "emptyData": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: testutils.MetricDataRecorderPublisher{}, - Input: middleware.BuildInput{}, - Result: &TestResult{ - Body: &testutils.TestReadCloser{Data: []byte("")}, - }, - ExpectedStreamData: "", - ExpectedMetricData: metrics.StreamMetrics{ - ReadDuration: 0, - ReadBytes: 0, - }, - }, - "nilBody": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: testutils.MetricDataRecorderPublisher{}, - Input: middleware.BuildInput{}, - Result: &TestResult{ - Body: nil, - }, - }, - "nilResult": { - ConnectionCounter: &metrics.SharedConnectionCounter{}, - Publisher: testutils.MetricDataRecorderPublisher{}, - Input: middleware.BuildInput{}, - Result: nil, - }, - } - - for name, c := range cases { - t.Run(name, func(t *testing.T) { - - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, c.ConnectionCounter, &c.Publisher) - mw := GetWrapDataStreamMiddleware() - - out, _, _ := mw.HandleBuild(ctx, c.Input, &testutils.StreamingBodyBuildHandler{Result: c.Result}) - - result := out.Result.(*TestResult) - - if result == nil || result.Body == nil { - return - } - - readData, _ := io.ReadAll(result.Body) - actualStreamData := string(readData) - actualMetricData := c.Publisher.Data.Stream - - if actualStreamData != c.ExpectedStreamData { - t.Errorf("Unexpected Data, should be '%s' but was '%s'", c.ExpectedStreamData, actualStreamData) - } - if !reflect.DeepEqual(actualMetricData, c.ExpectedMetricData) { - t.Errorf("Unexpected Metric Data, should be '%+v' but was '%+v'", c.ExpectedMetricData, actualMetricData) - } - - }) - } - -} - -func TestWrapDataStream_WrongResultType(t *testing.T) { - pub := &testutils.NoopPublisher{} - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, pub) - mw := GetWrapDataStreamMiddleware() - - r1 := TestResult{ - Body: &testutils.TestReadCloser{Data: []byte("testString")}, - } - - _, _, _ = mw.HandleBuild(ctx, middleware.BuildInput{}, &testutils.StreamingBodyBuildHandler{Result: r1}) - _, _, _ = mw.HandleBuild(ctx, middleware.BuildInput{}, &testutils.StreamingBodyBuildHandler{Result: pub}) - -} diff --git a/aws/middleware/private/metrics/publisher/emf.go b/aws/middleware/private/metrics/publisher/emf.go deleted file mode 100644 index d5a0a868595..00000000000 --- a/aws/middleware/private/metrics/publisher/emf.go +++ /dev/null @@ -1,155 +0,0 @@ -package publisher - -import ( - "fmt" - "strconv" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/emf" -) - -// EMFPublisher is a MetricPublisher implementation that publishes metrics to stdout using EMF format. -type EMFPublisher struct { - namespace string - serializer metrics.Serializer - additionalDimensions map[string]string -} - -var output = func(format string, a ...interface{}) { - fmt.Printf(format, a...) -} - -// NewEMFPublisher creates a new EMFPublisher with the specified namespace and serializer. -func NewEMFPublisher(namespace string, serializer metrics.Serializer) *EMFPublisher { - return &EMFPublisher{ - namespace: namespace, - serializer: serializer, - additionalDimensions: map[string]string{}, - } -} - -func (p *EMFPublisher) SetAdditionalDimension(key string, value string) { - p.additionalDimensions[key] = value -} - -func (p *EMFPublisher) RemoveAdditionalDimension(key string) { - delete(p.additionalDimensions, key) -} - -func (p *EMFPublisher) populateWithAdditionalDimensions(entry *emf.Entry) { - for k := range p.additionalDimensions { - entry.AddDimension(k, p.additionalDimensions[k]) - } -} - -// perRequestMetrics generates and returns the log entry for per-request metrics. -func (p *EMFPublisher) perRequestMetrics(data *metrics.MetricData) (string, error) { - - entry := emf.NewEntry(p.namespace, p.serializer) - - p.populateWithAdditionalDimensions(&entry) - - entry.AddDimension(metrics.ServiceIDKey, data.ServiceID) - entry.AddDimension(metrics.OperationNameKey, data.OperationName) - entry.AddDimension(metrics.HTTPStatusCodeKey, strconv.Itoa(data.StatusCode)) - - entry.AddProperty(metrics.ClientRequestIDKey, data.ClientRequestID) - - entry.AddMetric(metrics.APICallDurationKey, float64(data.APICallDuration.Nanoseconds())) - entry.AddMetric(metrics.APICallSuccessfulKey, float64(data.Success)) - entry.AddMetric(metrics.MarshallingDurationKey, float64(data.MarshallingDuration.Nanoseconds())) - entry.AddMetric(metrics.EndpointResolutionDurationKey, float64(data.EndpointResolutionDuration.Nanoseconds())) - - entry.AddMetric(metrics.RetryCountKey, float64(data.RetryCount)) - - // We only publish throughput if different then 0 to avoid polluting statistics - if data.InThroughput != 0 { - entry.AddMetric(metrics.InThroughputKey, data.InThroughput) - } - if data.OutThroughput != 0 { - entry.AddMetric(metrics.OutThroughputKey, data.OutThroughput) - } - - return entry.Build() -} - -// perAttemptMetrics generates and returns the log entry for per-attempt metrics. -func (p *EMFPublisher) perAttemptMetrics(data *metrics.MetricData, attemptIndex int) (string, error) { - - attempt := data.Attempts[attemptIndex] - - entry := emf.NewEntry(p.namespace, p.serializer) - - p.populateWithAdditionalDimensions(&entry) - - entry.AddDimension(metrics.ServiceIDKey, data.ServiceID) - entry.AddDimension(metrics.OperationNameKey, data.OperationName) - entry.AddDimension(metrics.HTTPStatusCodeKey, strconv.Itoa(attempt.StatusCode)) - - entry.AddProperty(metrics.ClientRequestIDKey, data.ClientRequestID) - entry.AddProperty(metrics.AWSExtendedRequestIDKey, attempt.ExtendedRequestID) - entry.AddProperty(metrics.AWSRequestIDKey, attempt.RequestID) - entry.AddProperty(metrics.AttemptNumberKey, attemptIndex) - - entry.AddMetric(metrics.MaxConcurrencyKey, float64(attempt.MaxConcurrency)) - entry.AddMetric(metrics.AvailableConcurrencyKey, float64(attempt.AvailableConcurrency)) - entry.AddMetric(metrics.ConcurrencyAcquireDurationKey, float64(attempt.ConcurrencyAcquireDuration.Nanoseconds())) - entry.AddMetric(metrics.PendingConcurrencyAcquiresKey, float64(attempt.PendingConnectionAcquires)) - entry.AddMetric(metrics.SigningDurationKey, float64(attempt.SigningDuration.Nanoseconds())) - entry.AddMetric(metrics.UnmarshallingDurationKey, float64(attempt.UnMarshallingDuration.Nanoseconds())) - entry.AddMetric(metrics.TimeToFirstByteKey, float64(attempt.TimeToFirstByte.Nanoseconds())) - entry.AddMetric(metrics.ServiceCallDurationKey, float64(attempt.ServiceCallDuration.Nanoseconds())) - entry.AddMetric(metrics.BackoffDelayDurationKey, float64(attempt.RetryDelay)) - - return entry.Build() -} - -// perStreamMetrics generates and returns the log entry for per-stream metrics. -func (p *EMFPublisher) perStreamMetrics(data *metrics.MetricData) (string, error) { - - entry := emf.NewEntry(p.namespace, p.serializer) - - p.populateWithAdditionalDimensions(&entry) - - entry.AddDimension(metrics.ServiceIDKey, data.ServiceID) - entry.AddDimension(metrics.OperationNameKey, data.OperationName) - entry.AddDimension(metrics.HTTPStatusCodeKey, strconv.Itoa(data.StatusCode)) - - entry.AddProperty(metrics.ClientRequestIDKey, data.ClientRequestID) - - if data.Stream.Throughput > 0 { - entry.AddMetric(metrics.StreamThroughputKey, data.Stream.Throughput) - } - - return entry.Build() -} - -// PostRequestMetrics publishes the request metrics to stdout using EMF format. -func (p *EMFPublisher) PostRequestMetrics(data *metrics.MetricData) error { - requestMetricLogEntry, err := p.perRequestMetrics(data) - if err != nil { - output("error generating log entry for request metrics due to %s", err.Error()) - } else { - output("%s\n", requestMetricLogEntry) - } - for idx := range data.Attempts { - attemptMetricLogEntry, err := p.perAttemptMetrics(data, idx) - if err != nil { - output("error generating log entry for attempt metrics due to %s", err.Error()) - } else { - output("%s\n", attemptMetricLogEntry) - } - } - return nil -} - -// PostStreamMetrics publishes the stream metrics to stdout using EMF format. -func (p *EMFPublisher) PostStreamMetrics(data *metrics.MetricData) error { - streamMetrics, err := p.perStreamMetrics(data) - if err != nil { - output("error generating log entry for stream metrics due to %s", err.Error()) - } else { - output("%s\n", streamMetrics) - } - return nil -} diff --git a/aws/middleware/private/metrics/publisher/emf_test.go b/aws/middleware/private/metrics/publisher/emf_test.go deleted file mode 100644 index c894edd30a6..00000000000 --- a/aws/middleware/private/metrics/publisher/emf_test.go +++ /dev/null @@ -1,251 +0,0 @@ -// This package is designated as private and is intended for use only by the -// AWS client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package publisher - -import ( - "fmt" - "reflect" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" -) - -type TestSerializerWithError struct{} - -func (TestSerializerWithError) Serialize(obj interface{}) (string, error) { - return "", fmt.Errorf("serialization error") -} - -func TestPostRequestMetrics(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - cases := map[string]struct { - Namespace string - Serializer metrics.Serializer - Data metrics.MetricData - ExpectedError error - ExpectedResults []string - }{ - "emptyRequestMetricData": { - Namespace: "testNamespace", - Serializer: metrics.DefaultSerializer{}, - Data: metrics.MetricData{}, - ExpectedError: nil, - ExpectedResults: []string{ - emptyRequestMetricData, - }, - }, - "serializerError": { - Namespace: "testNamespace", - Serializer: TestSerializerWithError{}, - Data: metrics.MetricData{ - Attempts: []metrics.AttemptMetrics{{}}, - }, - ExpectedError: nil, - ExpectedResults: []string{ - "error generating log entry for request metrics due to [serialization error]", - "error generating log entry for attempt metrics due to [serialization error]", - }, - }, - "completeRequestMetricData": { - Namespace: "testNamespace", - Serializer: metrics.DefaultSerializer{}, - Data: metrics.MetricData{ - RequestStartTime: time.Unix(1234, 0), - RequestEndTime: time.Unix(1434, 0), - SerializeStartTime: time.Unix(1234, 0), - SerializeEndTime: time.Unix(1434, 0), - ResolveEndpointStartTime: time.Unix(1234, 0), - ResolveEndpointEndTime: time.Unix(1434, 0), - Success: 1, - ClientRequestID: "crid", - ServiceID: "sid", - OperationName: "operationname", - PartitionID: "partitionid", - Region: "region", - RequestContentLength: 100, - Stream: metrics.StreamMetrics{}, - Attempts: []metrics.AttemptMetrics{{ - ServiceCallStart: time.Unix(1234, 0), - ServiceCallEnd: time.Unix(1434, 0), - FirstByteTime: time.Unix(1234, 0), - ConnRequestedTime: time.Unix(1234, 0), - ConnObtainedTime: time.Unix(1434, 0), - SignStartTime: time.Unix(1234, 0), - SignEndTime: time.Unix(1434, 0), - DeserializeStartTime: time.Unix(1234, 0), - DeserializeEndTime: time.Unix(1434, 0), - RetryDelay: 100, - ResponseContentLength: 100, - StatusCode: 200, - RequestID: "reqid", - ExtendedRequestID: "exreqid", - HTTPClient: "Default", - MaxConcurrency: 10, - PendingConnectionAcquires: 1, - AvailableConcurrency: 2, - ActiveRequests: 3, - ReusedConnection: false, - }, - { - ServiceCallStart: time.Unix(1234, 0), - ServiceCallEnd: time.Unix(1434, 0), - FirstByteTime: time.Unix(1234, 0), - ConnRequestedTime: time.Unix(1234, 0), - ConnObtainedTime: time.Unix(1434, 0), - SignStartTime: time.Unix(1234, 0), - SignEndTime: time.Unix(1434, 0), - DeserializeStartTime: time.Unix(1234, 0), - DeserializeEndTime: time.Unix(1434, 0), - RetryDelay: 100, - ResponseContentLength: 100, - StatusCode: 200, - RequestID: "reqid", - ExtendedRequestID: "exreqid", - HTTPClient: "Default", - MaxConcurrency: 10, - PendingConnectionAcquires: 1, - AvailableConcurrency: 2, - ActiveRequests: 3, - ReusedConnection: false, - }}, - }, - ExpectedError: nil, - ExpectedResults: []string{ - completeRequestMetricData, - completeMetricDataAttempt1, - completeMetricDataAttempt2, - }, - }, - } - - for name, c := range cases { - t.Run(name, func(t *testing.T) { - - var actualResults []string - - output = func(format string, a ...interface{}) { - actualResults = append(actualResults, fmt.Sprintf(format, a)) - } - - publisher := NewEMFPublisher(c.Namespace, c.Serializer) - - c.Data.ComputeRequestMetrics() - - err := publisher.PostRequestMetrics(&c.Data) - - if !reflect.DeepEqual(err, c.ExpectedError) { - t.Errorf("Unexpected error, should be '%s' but was '%s'", c.ExpectedError, err) - } - - if len(c.ExpectedResults) != len(actualResults) { - t.Errorf("Different number of results. Expected %d but got %d", len(c.ExpectedResults), len(actualResults)) - } - - for i := range c.ExpectedResults { - if !reflect.DeepEqual(actualResults[i], c.ExpectedResults[i]) { - t.Errorf("Unexpected result, should be '%s' but was '%s'", c.ExpectedResults[i], actualResults[i]) - } - } - }) - } -} - -func TestPostStreamMetrics(t *testing.T) { - - sdk.NowTime = func() time.Time { - return time.Unix(1234, 0) - } - - cases := map[string]struct { - Namespace string - Serializer metrics.Serializer - Data metrics.MetricData - ExpectedError error - ExpectedResults []string - }{ - "emptyStreamMetricData": { - Namespace: "testNamespace", - Serializer: metrics.DefaultSerializer{}, - Data: metrics.MetricData{}, - ExpectedError: nil, - ExpectedResults: []string{ - emptyStreamMetricData, - }, - }, - "serializerError": { - Namespace: "testNamespace", - Serializer: TestSerializerWithError{}, - Data: metrics.MetricData{}, - ExpectedError: nil, - ExpectedResults: []string{ - "error generating log entry for stream metrics due to [serialization error]", - }, - }, - "completeStreamMetricData": { - Namespace: "testNamespace", - Serializer: metrics.DefaultSerializer{}, - Data: metrics.MetricData{ - RequestStartTime: time.Unix(1234, 0), - RequestEndTime: time.Unix(1434, 0), - SerializeStartTime: time.Unix(1234, 0), - SerializeEndTime: time.Unix(1434, 0), - ResolveEndpointStartTime: time.Unix(1234, 0), - ResolveEndpointEndTime: time.Unix(1434, 0), - Success: 1, - StatusCode: 200, - ClientRequestID: "crid", - ServiceID: "sid", - OperationName: "operationname", - PartitionID: "partitionid", - Region: "region", - RequestContentLength: 100, - Stream: metrics.StreamMetrics{ - ReadDuration: 150, - ReadBytes: 12, - Throughput: 80000000, - }, - }, - ExpectedError: nil, - ExpectedResults: []string{ - completeStreamMetricData, - }, - }, - } - - for name, c := range cases { - t.Run(name, func(t *testing.T) { - - var actualResults []string - - output = func(format string, a ...interface{}) { - actualResults = append(actualResults, fmt.Sprintf(format, a)) - } - - publisher := NewEMFPublisher(c.Namespace, c.Serializer) - - err := publisher.PostStreamMetrics(&c.Data) - - if !reflect.DeepEqual(err, c.ExpectedError) { - t.Errorf("Unexpected error, should be '%s' but was '%s'", c.ExpectedError, err) - } - - if len(c.ExpectedResults) != len(actualResults) { - t.Errorf("Different number of results. Expected %d but got %d", len(c.ExpectedResults), len(actualResults)) - } - - for i := range c.ExpectedResults { - if !reflect.DeepEqual(actualResults[i], c.ExpectedResults[i]) { - t.Errorf("Unexpected result, should be '%s' but was '%s'", c.ExpectedResults[i], actualResults[i]) - } - } - }) - } -} diff --git a/aws/middleware/private/metrics/publisher/emf_test_data.go b/aws/middleware/private/metrics/publisher/emf_test_data.go deleted file mode 100644 index 73ecd786a3d..00000000000 --- a/aws/middleware/private/metrics/publisher/emf_test_data.go +++ /dev/null @@ -1,227 +0,0 @@ -// This package is designated as private and is intended for use only by the -// AWS client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. - -package publisher - -import "strings" - -func stripString(str string) string { - str = strings.Replace(str, " ", "", -1) - str = strings.Replace(str, "\t", "", -1) - str = strings.Replace(str, "\n", "", -1) - return str + "\n" -} - -var emptyRequestMetricData = stripString(` -[{ - "ApiCallDuration": 0, - "ApiCallSuccessful": 0, - "ClientRequestId": "", - "EndpointResolutionDuration": 0, - "HttpStatusCode":"0", - "MarshallingDuration": 0, - "OperationName": "", - "RetryCount": -1, - "ServiceId": "", - "_aws": { - "CloudWatchMetrics": [{ - "Dimensions": [ - ["ServiceId", "OperationName", "HttpStatusCode"] - ], - "Metrics": [{ - "Name": "ApiCallDuration" - }, { - "Name": "ApiCallSuccessful" - }, { - "Name": "MarshallingDuration" - }, { - "Name": "EndpointResolutionDuration" - }, { - "Name": "RetryCount" - }], - "Namespace": "testNamespace" - }], - "Timestamp": 1234000 - } -}] -`) - -var emptyStreamMetricData = stripString(` -[{ - "ClientRequestId": "", - "HttpStatusCode": "0", - "OperationName": "", - "ServiceId": "", - "_aws": { - "CloudWatchMetrics": [{ - "Dimensions": [ - ["ServiceId", "OperationName", "HttpStatusCode"] - ], - "Metrics": [], - "Namespace": "testNamespace" - }], - "Timestamp": 1234000 - } -}] -`) - -var completeStreamMetricData = stripString(` -[{ - "ClientRequestId": "crid", - "HttpStatusCode": "200", - "OperationName": "operationname", - "ServiceId": "sid", - "Throughput": 80000000, - "_aws": { - "CloudWatchMetrics": [{ - "Dimensions": [ - ["ServiceId", "OperationName", "HttpStatusCode"] - ], - "Metrics": [{ - "Name": "Throughput" - }], - "Namespace": "testNamespace" - }], - "Timestamp": 1234000 - } -}] -`) - -var completeRequestMetricData = stripString(` -[{ - "ApiCallDuration": 200000000000, - "ApiCallSuccessful": 1, - "ClientRequestId": "crid", - "EndpointResolutionDuration": 200000000000, - "HttpStatusCode":"200", - "InThroughput": 0.5, - "MarshallingDuration": 200000000000, - "OperationName": "operationname", - "OutThroughput": 0.5, - "RetryCount": 1, - "ServiceId": "sid", - "_aws": { - "CloudWatchMetrics": [{ - "Dimensions": [ - ["ServiceId", "OperationName", "HttpStatusCode"] - ], - "Metrics": [{ - "Name": "ApiCallDuration" - }, { - "Name": "ApiCallSuccessful" - }, { - "Name": "MarshallingDuration" - }, { - "Name": "EndpointResolutionDuration" - }, { - "Name": "RetryCount" - }, { - "Name": "InThroughput" - }, { - "Name": "OutThroughput" - }], - "Namespace": "testNamespace" - }], - "Timestamp": 1234000 - } -}] -`) - -var completeMetricDataAttempt1 = stripString(` -[{ - "AttemptNumber": 0, - "AvailableConcurrency": 2, - "AwsExtendedRequestId": "exreqid", - "AwsRequestId": "reqid", - "BackoffDelayDuration":100, - "ClientRequestId": "crid", - "ConcurrencyAcquireDuration": 200000000000, - "HttpStatusCode": "200", - "MaxConcurrency":10, - "OperationName": "operationname", - "PendingConcurrencyAcquires": 1, - "ServiceCallDuration": 200000000000, - "ServiceId": "sid", - "SigningDuration": 200000000000, - "TimeToFirstByte": 0, - "UnmarshallingDuration": 200000000000, - "_aws": { - "CloudWatchMetrics": [{ - "Dimensions": [ - ["ServiceId", "OperationName", "HttpStatusCode"] - ], - "Metrics": [{ - "Name": "MaxConcurrency" - }, { - "Name": "AvailableConcurrency" - }, { - "Name": "ConcurrencyAcquireDuration" - }, { - "Name": "PendingConcurrencyAcquires" - }, { - "Name": "SigningDuration" - }, { - "Name": "UnmarshallingDuration" - }, { - "Name": "TimeToFirstByte" - }, { - "Name": "ServiceCallDuration" - }, { - "Name":"BackoffDelayDuration" - }], - "Namespace": "testNamespace" - }], - "Timestamp": 1234000 - } -}] -`) - -var completeMetricDataAttempt2 = stripString(` -[{ - "AttemptNumber": 1, - "AvailableConcurrency": 2, - "AwsExtendedRequestId": "exreqid", - "AwsRequestId": "reqid", - "BackoffDelayDuration":100, - "ClientRequestId": "crid", - "ConcurrencyAcquireDuration": 200000000000, - "HttpStatusCode": "200", - "MaxConcurrency":10, - "OperationName": "operationname", - "PendingConcurrencyAcquires": 1, - "ServiceCallDuration": 200000000000, - "ServiceId": "sid", - "SigningDuration": 200000000000, - "TimeToFirstByte": 0, - "UnmarshallingDuration": 200000000000, - "_aws": { - "CloudWatchMetrics": [{ - "Dimensions": [ - ["ServiceId", "OperationName", "HttpStatusCode"] - ], - "Metrics": [{ - "Name": "MaxConcurrency" - }, { - "Name": "AvailableConcurrency" - }, { - "Name": "ConcurrencyAcquireDuration" - }, { - "Name": "PendingConcurrencyAcquires" - }, { - "Name": "SigningDuration" - }, { - "Name": "UnmarshallingDuration" - }, { - "Name": "TimeToFirstByte" - }, { - "Name": "ServiceCallDuration" - }, { - "Name": "BackoffDelayDuration" - }], - "Namespace": "testNamespace" - }], - "Timestamp": 1234000 - } -}] -`) diff --git a/aws/middleware/private/metrics/readcloserwithmetrics/read_closer_with_metrics.go b/aws/middleware/private/metrics/readcloserwithmetrics/read_closer_with_metrics.go deleted file mode 100644 index eb234ffa762..00000000000 --- a/aws/middleware/private/metrics/readcloserwithmetrics/read_closer_with_metrics.go +++ /dev/null @@ -1,56 +0,0 @@ -package readcloserwithmetrics - -import ( - "fmt" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/internal/sdk" - "io" -) - -type ReadCloserWithMetrics struct { - data *metrics.MetricData - publisher metrics.MetricPublisher - readCloser io.ReadCloser - readFinished bool -} - -func New( - context *metrics.MetricContext, closer io.ReadCloser, -) (trc *ReadCloserWithMetrics) { - return &ReadCloserWithMetrics{ - data: context.Data(), - publisher: context.Publisher(), - readCloser: closer, - readFinished: false, - } -} - -func (r *ReadCloserWithMetrics) Read(p []byte) (n int, err error) { - readRoundStarted := sdk.NowTime() - read, err := r.readCloser.Read(p) - readRoundEnd := sdk.NowTime() - r.data.Stream.ReadDuration += readRoundEnd.Sub(readRoundStarted) - r.data.Stream.ReadBytes += int64(read) - if err == io.EOF { - r.readFinished = true - r.finalize() - } - return read, err -} - -func (r *ReadCloserWithMetrics) Close() error { - if !r.readFinished { - r.finalize() - } - return r.readCloser.Close() -} - -func (r *ReadCloserWithMetrics) finalize() { - if r.data.Stream.ReadDuration > 0 { - r.data.Stream.Throughput = float64(r.data.Stream.ReadBytes) / r.data.Stream.ReadDuration.Seconds() - } - err := r.publisher.PostStreamMetrics(r.data) - if err != nil { - fmt.Println("Failed to post stream metrics") - } -} diff --git a/aws/middleware/private/metrics/readcloserwithmetrics/read_closer_with_metrics_test.go b/aws/middleware/private/metrics/readcloserwithmetrics/read_closer_with_metrics_test.go deleted file mode 100644 index 97d21b1ecd0..00000000000 --- a/aws/middleware/private/metrics/readcloserwithmetrics/read_closer_with_metrics_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package readcloserwithmetrics - -import ( - "context" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" - "io" - "testing" -) - -func TestNew(t *testing.T) { - - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, &testutils.NoopPublisher{}) - mctx := metrics.Context(ctx) - - expectedData := "testString" - trc := testutils.TestReadCloser{Data: []byte(expectedData)} - - reader := New(mctx, &trc) - readData, _ := io.ReadAll(reader) - actualData := string(readData) - - if actualData != expectedData { - t.Errorf("Unexpected Data, should be '%s' but was '%s'", expectedData, actualData) - } -} - -func TestReadCloserWithMetrics_Close(t *testing.T) { - - mdrp := &testutils.MetricDataRecorderPublisher{} - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, mdrp) - mctx := metrics.Context(ctx) - - expectedData := "testString" - trc := testutils.TestReadCloser{Data: []byte(expectedData)} - - reader := New(mctx, &trc) - - err := reader.Close() - - if err != nil { - t.Errorf("Unexpected Error in Close") - } - - if mdrp.Data == nil { - t.Errorf("Data should be set in publisher") - } - - rb := mdrp.Data.Stream.ReadBytes - if mdrp.Data.Stream.ReadBytes != 0 { - t.Errorf("Unexpected ReadBytes, should be '%d' but was '%d'", 0, rb) - } - -} - -func TestReadCloserWithMetrics_Read(t *testing.T) { - mdrp := &testutils.MetricDataRecorderPublisher{} - ctx := context.TODO() - ctx = metrics.InitMetricContext(ctx, &metrics.SharedConnectionCounter{}, mdrp) - mctx := metrics.Context(ctx) - - expectedData := "testString" - trc := testutils.TestReadCloser{Data: []byte(expectedData)} - - reader := New(mctx, &trc) - - err := reader.Close() - - if err != nil { - t.Errorf("Unexpected Error in Close") - } - - if mdrp.Data == nil { - t.Errorf("Data should be set in publisher") - } - - rb := mdrp.Data.Stream.ReadBytes - if mdrp.Data.Stream.ReadBytes != 0 { - t.Errorf("Unexpected ReadBytes, should be '%d' but was '%d'", 0, rb) - } -} diff --git a/aws/middleware/private/metrics/testutils/test_util.go b/aws/middleware/private/metrics/testutils/test_util.go deleted file mode 100644 index 6796a8b5604..00000000000 --- a/aws/middleware/private/metrics/testutils/test_util.go +++ /dev/null @@ -1,111 +0,0 @@ -package testutils - -import ( - "context" - "fmt" - "io" - - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" - "github.com/aws/smithy-go/middleware" -) - -type MetricDataRecorderPublisher struct { - Data *metrics.MetricData -} - -func (mdrp *MetricDataRecorderPublisher) PostRequestMetrics(data *metrics.MetricData) error { - mdrp.Data = data - return nil -} - -func (mdrp *MetricDataRecorderPublisher) PostStreamMetrics(data *metrics.MetricData) error { - mdrp.Data = data - return nil -} - -type NoopPublisher struct{} - -func (np *NoopPublisher) PostRequestMetrics(data *metrics.MetricData) error { - return nil -} - -func (np *NoopPublisher) PostStreamMetrics(data *metrics.MetricData) error { - return nil -} - -type ErrorPublisher struct{} - -func (tp *ErrorPublisher) PostRequestMetrics(data *metrics.MetricData) error { - return fmt.Errorf("publisher error") -} - -func (tp *ErrorPublisher) PostStreamMetrics(data *metrics.MetricData) error { - return fmt.Errorf("publisher error") -} - -type NoopInitializeHandler struct{} -type ErrorInitializeHandler struct{} -type NoopSerializeHandler struct{} -type NoopFinalizeHandler struct{} -type NoopDeserializeHandler struct{} -type StreamingBodyBuildHandler struct { - Result interface{} -} - -func NoopRequestCloner(i interface{}) interface{} { - return i -} - -func (NoopInitializeHandler) HandleInitialize(ctx context.Context, in middleware.InitializeInput) ( - out middleware.InitializeOutput, metadata middleware.Metadata, err error, -) { - return middleware.InitializeOutput{}, middleware.Metadata{}, nil -} - -func (ErrorInitializeHandler) HandleInitialize(ctx context.Context, in middleware.InitializeInput) ( - out middleware.InitializeOutput, metadata middleware.Metadata, err error, -) { - return middleware.InitializeOutput{}, middleware.Metadata{}, fmt.Errorf("init error") -} - -func (NoopFinalizeHandler) HandleFinalize(ctx context.Context, in middleware.FinalizeInput) ( - out middleware.FinalizeOutput, metadata middleware.Metadata, err error, -) { - return middleware.FinalizeOutput{}, middleware.Metadata{}, nil -} - -func (NoopDeserializeHandler) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput) ( - out middleware.DeserializeOutput, metadata middleware.Metadata, err error, -) { - return middleware.DeserializeOutput{}, middleware.Metadata{}, nil -} - -func (NoopSerializeHandler) HandleSerialize(ctx context.Context, in middleware.SerializeInput) ( - out middleware.SerializeOutput, metadata middleware.Metadata, err error, -) { - return middleware.SerializeOutput{}, middleware.Metadata{}, nil -} - -func (s *StreamingBodyBuildHandler) HandleBuild(ctx context.Context, in middleware.BuildInput) ( - out middleware.BuildOutput, metadata middleware.Metadata, err error, -) { - return middleware.BuildOutput{Result: s.Result}, middleware.Metadata{}, nil -} - -type TestReadCloser struct { - Data []byte - offset int -} - -func (m *TestReadCloser) Read(p []byte) (int, error) { - if m.offset >= len(m.Data) { - return 0, io.EOF - } - n := copy(p, m.Data[m.offset:]) - m.offset += n - return n, nil -} - -func (m *TestReadCloser) Close() error { - return nil -} diff --git a/aws/retry/middleware.go b/aws/retry/middleware.go index 286892adc80..52d59b04bf6 100644 --- a/aws/retry/middleware.go +++ b/aws/retry/middleware.go @@ -8,7 +8,6 @@ import ( "strings" "time" - privatemetrics "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" internalcontext "github.com/aws/aws-sdk-go-v2/internal/context" "github.com/aws/smithy-go" @@ -271,13 +270,6 @@ func (r *Attempt) handleAttempt( // that time. Potentially early exist if the sleep is canceled via the // context. retryDelay, reqErr := r.retryer.RetryDelay(attemptNum, err) - mctx := privatemetrics.Context(ctx) - if mctx != nil { - attempt, err := mctx.Data().LatestAttempt() - if err != nil { - attempt.RetryDelay = retryDelay - } - } if reqErr != nil { return out, attemptResult, releaseRetryToken, reqErr } diff --git a/aws/retry/middleware_test.go b/aws/retry/middleware_test.go index b8463d5a8dd..6a56aadcb3f 100644 --- a/aws/retry/middleware_test.go +++ b/aws/retry/middleware_test.go @@ -11,7 +11,6 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/testutils" internalcontext "github.com/aws/aws-sdk-go-v2/internal/context" "github.com/aws/aws-sdk-go-v2/aws/ratelimit" @@ -533,7 +532,7 @@ func TestClockSkew(t *testing.T) { for name, tt := range cases { t.Run(name, func(t *testing.T) { am := NewAttemptMiddleware(NewStandard(func(s *StandardOptions) { - }), testutils.NoopRequestCloner) + }), func(i any) any { return i }) ctx := internalcontext.SetAttemptSkewContext(context.Background(), tt.skew) _, metadata, err := am.HandleFinalize(ctx, middleware.FinalizeInput{}, middleware.FinalizeHandlerFunc( func(ctx context.Context, in middleware.FinalizeInput) (