From 51f2b6b98bc8154a00c937f041ab1b9c96a1cf5a Mon Sep 17 00:00:00 2001 From: Jeffrey Chien Date: Fri, 20 Oct 2023 12:08:51 -0400 Subject: [PATCH] [extension/awsmiddleware] Add ID to context to trace requests. (#128) --- .github/CODEOWNERS | 2 +- cmd/checkapi/allowlist.txt | 1 + extension/awsmiddleware/README.md | 15 +-- extension/awsmiddleware/config.go | 30 +++--- extension/awsmiddleware/config_test.go | 26 +----- extension/awsmiddleware/doc.go | 2 +- extension/awsmiddleware/go.mod | 38 ++++---- extension/awsmiddleware/go.sum | 74 ++++++++------- extension/awsmiddleware/middleware.go | 39 +++++--- extension/awsmiddleware/middleware_test.go | 103 +++++++++++++-------- extension/awsmiddleware/mock.go | 78 ++++++++++++++++ extension/awsmiddleware/wrapper.go | 35 ++++++- 12 files changed, 292 insertions(+), 151 deletions(-) create mode 100644 extension/awsmiddleware/mock.go diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 41a6c72f218d..63c8d5a5888b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -89,7 +89,7 @@ exporter/tencentcloudlogserviceexporter/ @open-telemetry/collect exporter/zipkinexporter/ @open-telemetry/collector-contrib-approvers @MovieStoreGuy @astencel-sumo @crobert-1 extension/asapauthextension/ @open-telemetry/collector-contrib-approvers @jamesmoessis @MovieStoreGuy -extension/awsmiddleware @open-telemetry/collector-contrib-approvers @jefchien +extension/awsmiddleware/ @open-telemetry/collector-contrib-approvers @jefchien extension/awsproxy/ @open-telemetry/collector-contrib-approvers @Aneurysm9 @mxiamxia extension/basicauthextension/ @open-telemetry/collector-contrib-approvers @jpkrohling @svrakitin @frzifus extension/bearertokenauthextension/ @open-telemetry/collector-contrib-approvers @jpkrohling @pavankrish123 @frzifus diff --git a/cmd/checkapi/allowlist.txt b/cmd/checkapi/allowlist.txt index 72745f041595..cef9033c2b3c 100644 --- a/cmd/checkapi/allowlist.txt +++ b/cmd/checkapi/allowlist.txt @@ -13,6 +13,7 @@ exporter/lokiexporter exporter/pulsarexporter exporter/sentryexporter exporter/sumologicexporter +extension/awsmiddleware extension/observer/ecsobserver extension/observer extension/observer/k8sobserver diff --git a/extension/awsmiddleware/README.md b/extension/awsmiddleware/README.md index 67885f503174..644e43b06bf3 100644 --- a/extension/awsmiddleware/README.md +++ b/extension/awsmiddleware/README.md @@ -1,29 +1,30 @@ # AWS Middleware An AWS middleware extension provides request and/or response handlers that can be configured on AWS SDK v1/v2 clients. -Other components can configure their AWS SDK clients using the `awsmiddleware.ConfigureSDKv1` and `awsmiddleware.ConfigureSDKv2` functions. +Other components can configure their AWS SDK clients using `awsmiddleware.GetConfigurer` and the `ConfigureSDKv1` and +`ConfigureSDKv2` functions available on the `Configurer`. -The `awsmiddleware.Extension` interface extends `component.Extension` by adding the following methods: +The `awsmiddleware.Extension` interface extends `component.Extension` by adding the following method: ``` -RequestHandlers() []RequestHandler -ResponseHandlers() []ResponseHandler +Handlers() ([]RequestHandler, []ResponseHandler) ``` The `awsmiddleware.RequestHandler` interface contains the following methods: ``` ID() string Position() HandlerPosition -HandleRequest(r *http.Request) +HandleRequest(id string, r *http.Request) ``` The `awsmiddleware.ResponseHandler` interface contains the following methods: ``` ID() string Position() HandlerPosition -HandleResponse(r *http.Response) +HandleResponse(id string, r *http.Response) ``` - `ID` uniquely identifies a handler. Middleware will fail if there is clashing - `Position` determines whether the handler is appended to the front or back of the existing list. Insertion is done in the order of the handlers provided. -- `HandleRequest/Response` provides a hook to handle the request/response before and after they've been sent. \ No newline at end of file +- `HandleRequest/Response` provides a hook to handle the request/response before and after they've been sent along +with an attached request ID. \ No newline at end of file diff --git a/extension/awsmiddleware/config.go b/extension/awsmiddleware/config.go index f221a347dd35..52f2face2ac3 100644 --- a/extension/awsmiddleware/config.go +++ b/extension/awsmiddleware/config.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package awsmiddleware // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/awsmiddleware" +package awsmiddleware // import "github.com/amazon-contributing/opentelemetry-collector-contrib/extension/awsmiddleware" import ( "fmt" @@ -9,19 +9,25 @@ import ( "go.opentelemetry.io/collector/component" ) -// Config defines the configuration for an AWS Middleware extension. -type Config struct { - // MiddlewareID is the ID of the Middleware extension. - MiddlewareID component.ID `mapstructure:"middleware"` -} +type ID = component.ID -// GetMiddleware retrieves the extension implementing Middleware based on the MiddlewareID. -func (c Config) GetMiddleware(extensions map[component.ID]component.Component) (Middleware, error) { - if ext, found := extensions[c.MiddlewareID]; found { - if mw, ok := ext.(Middleware); ok { - return mw, nil +// getMiddleware retrieves the extension implementing Middleware based on the middlewareID. +func getMiddleware(extensions map[component.ID]component.Component, middlewareID ID) (Middleware, error) { + if extension, found := extensions[middlewareID]; found { + if middleware, ok := extension.(Middleware); ok { + return middleware, nil } return nil, errNotMiddleware } - return nil, fmt.Errorf("failed to resolve AWS client handler %q: %w", c.MiddlewareID, errNotFound) + return nil, fmt.Errorf("failed to resolve AWS middleware %q: %w", middlewareID, errNotFound) +} + +// GetConfigurer retrieves the extension implementing Middleware based on the middlewareID and +// wraps it in a Configurer. +func GetConfigurer(extensions map[component.ID]component.Component, middlewareID ID) (*Configurer, error) { + middleware, err := getMiddleware(extensions, middlewareID) + if err != nil { + return nil, err + } + return newConfigurer(middleware.Handlers()), nil } diff --git a/extension/awsmiddleware/config_test.go b/extension/awsmiddleware/config_test.go index cb317acd6b46..fbdd773dbfbf 100644 --- a/extension/awsmiddleware/config_test.go +++ b/extension/awsmiddleware/config_test.go @@ -13,28 +13,12 @@ import ( "go.opentelemetry.io/collector/extension/extensiontest" ) -type testMiddlewareExtension struct { - component.StartFunc - component.ShutdownFunc - requestHandlers []RequestHandler - responseHandlers []ResponseHandler -} - -var _ Extension = (*testMiddlewareExtension)(nil) - -func (t *testMiddlewareExtension) RequestHandlers() []RequestHandler { - return t.requestHandlers -} - -func (t *testMiddlewareExtension) ResponseHandlers() []ResponseHandler { - return t.responseHandlers -} - -func TestGetMiddleware(t *testing.T) { +func TestGetConfigurer(t *testing.T) { id := component.NewID("test") - cfg := &Config{MiddlewareID: id} nopExtension, err := extensiontest.NewNopBuilder().Create(context.Background(), extensiontest.NewNopCreateSettings()) require.Error(t, err) + middlewareExtension := new(MockMiddlewareExtension) + middlewareExtension.On("Handlers").Return(nil, nil) testCases := map[string]struct { extensions map[component.ID]component.Component wantErr error @@ -48,12 +32,12 @@ func TestGetMiddleware(t *testing.T) { wantErr: errNotMiddleware, }, "WithMiddlewareExtension": { - extensions: map[component.ID]component.Component{id: &testMiddlewareExtension{}}, + extensions: map[component.ID]component.Component{id: middlewareExtension}, }, } for name, testCase := range testCases { t.Run(name, func(t *testing.T) { - got, err := cfg.GetMiddleware(testCase.extensions) + got, err := GetConfigurer(testCase.extensions, id) if testCase.wantErr != nil { assert.Error(t, err) assert.ErrorIs(t, err, testCase.wantErr) diff --git a/extension/awsmiddleware/doc.go b/extension/awsmiddleware/doc.go index dfc6a74dc27e..1426ff222520 100644 --- a/extension/awsmiddleware/doc.go +++ b/extension/awsmiddleware/doc.go @@ -3,4 +3,4 @@ // Package awsmiddleware defines an extension interface providing request and response handlers that can be // configured on AWS SDK clients. -package awsmiddleware // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/awsmiddleware" +package awsmiddleware // import "github.com/amazon-contributing/opentelemetry-collector-contrib/extension/awsmiddleware" diff --git a/extension/awsmiddleware/go.mod b/extension/awsmiddleware/go.mod index 2106c0e24556..a28cb949b823 100644 --- a/extension/awsmiddleware/go.mod +++ b/extension/awsmiddleware/go.mod @@ -1,25 +1,26 @@ -module github.com/open-telemetry/opentelemetry-collector-contrib/extension/awsmiddleware +module github.com/amazon-contributing/opentelemetry-collector-contrib/extension/awsmiddleware go 1.20 require ( - github.com/aws/aws-sdk-go v1.45.24 - github.com/aws/aws-sdk-go-v2 v1.21.1 + github.com/aws/aws-sdk-go v1.45.2 + github.com/aws/aws-sdk-go-v2 v1.21.2 github.com/aws/aws-sdk-go-v2/service/s3 v1.40.0 github.com/aws/smithy-go v1.15.0 + github.com/google/uuid v1.3.1 github.com/stretchr/testify v1.8.4 - go.opentelemetry.io/collector/component v0.87.0 - go.opentelemetry.io/collector/extension v0.87.0 + go.opentelemetry.io/collector/component v0.84.1-0.20230908201109-ab3d6c5b6470 + go.opentelemetry.io/collector/extension v0.84.1-0.20230908201109-ab3d6c5b6470 ) require ( github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.42 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.36 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.36 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -32,20 +33,21 @@ require ( github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/collector/config/configtelemetry v0.87.0 // indirect - go.opentelemetry.io/collector/confmap v0.87.0 // indirect - go.opentelemetry.io/collector/featuregate v1.0.0-rcv0016 // indirect - go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect + go.opentelemetry.io/collector/config/configtelemetry v0.84.1-0.20230908201109-ab3d6c5b6470 // indirect + go.opentelemetry.io/collector/confmap v0.84.1-0.20230908201109-ab3d6c5b6470 // indirect + go.opentelemetry.io/collector/featuregate v1.0.0-rcv0014.0.20230908201109-ab3d6c5b6470 // indirect + go.opentelemetry.io/collector/pdata v1.0.0-rcv0014.0.20230908201109-ab3d6c5b6470 // indirect + go.opentelemetry.io/otel v1.17.0 // indirect + go.opentelemetry.io/otel/metric v1.17.0 // indirect + go.opentelemetry.io/otel/trace v1.17.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.26.0 // indirect + go.uber.org/zap v1.25.0 // indirect golang.org/x/net v0.15.0 // indirect golang.org/x/sys v0.12.0 // indirect golang.org/x/text v0.13.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/grpc v1.58.2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/grpc v1.57.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/extension/awsmiddleware/go.sum b/extension/awsmiddleware/go.sum index 8daaa48f656f..2442edea841d 100644 --- a/extension/awsmiddleware/go.sum +++ b/extension/awsmiddleware/go.sum @@ -1,25 +1,22 @@ -github.com/aws/aws-sdk-go v1.45.24 h1:TZx/CizkmCQn8Rtsb11iLYutEQVGK5PK9wAhwouELBo= -github.com/aws/aws-sdk-go v1.45.24/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.45.2 h1:hTong9YUklQKqzrGk3WnKABReb5R8GjbG4Y6dEQfjnk= +github.com/aws/aws-sdk-go v1.45.2/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= -github.com/aws/aws-sdk-go-v2 v1.21.1 h1:wjHYshtPpYOZm+/mu3NhVgRRc0baM6LJZOmxPZ5Cwzs= -github.com/aws/aws-sdk-go-v2 v1.21.1/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= +github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= +github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 h1:OPLEkmhXf6xFPiz0bLeDArZIDx1NNS4oJyG4nv3Gct0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13/go.mod h1:gpAbvyDGQFozTEmlTFO8XcQKHzubdq0LzRyJpG6MiXM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 h1:22dGT7PneFMx4+b3pz7lMTRyN8ZKH7M2cW4GP9yUS2g= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.42 h1:817VqVe6wvwE46xXy6YF5RywvjOX6U2zRQQ6IbQFK0s= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.42/go.mod h1:oDfgXoBBmj+kXnqxDDnIDnC56QBosglKp8ftRCTxR+0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.36 h1:7ZApaXzWbo8slc+W5TynuUlB4z66g44h7uqa3/d/BsY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.36/go.mod h1:rwr4WnmFi3RJO0M4dxbJtgi9BPLMpVBMX1nUte5ha9U= github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 h1:6lJvvkQ9HmbHZ4h/IEwclwv2mrTW8Uq1SOB/kXy0mfw= github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4/go.mod h1:1PrKYwxTM+zjpw9Y41KFtoJCQrJ34Z47Y4VgVbfndjo= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 h1:m0QTSI6pZYJTk5WSKx3fm5cNW/DCicVzULBgU/6IyD0= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14/go.mod h1:dDilntgHy9WnHXsh7dDtUPgHKEfTJIBUTHM8OWm0f/0= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36 h1:eev2yZX7esGRjqRbnVk1UxMLw4CyVZDpZXRCcy75oQk= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36/go.mod h1:lGnOkH9NJATw0XEPcAknFBj3zzNTEGRHtSw+CwC1YTg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 h1:CdzPW9kKitgIiLV1+MHobfR5Xg25iYnyzWZhyQuSlDI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.36 h1:YXlm7LxwNlauqb2OrinWlcvtsflTzP8GaMvYfQBhoT4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.36/go.mod h1:ou9ffqJ9hKOVZmjlC6kQ6oROAyG1M4yBKzR+9BKbDwk= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 h1:v0jkRigbSD6uOdwcaUQmgEwG1BkPfAPDqaeNt/29ghg= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4/go.mod h1:LhTyt8J04LL+9cIt7pYJ5lbS/U98ZmXovLOR/4LUsk8= github.com/aws/aws-sdk-go-v2/service/s3 v1.40.0 h1:wl5dxN1NONhTDQD9uaEvNsDRX29cBmGED/nl0jkWlt4= @@ -27,6 +24,7 @@ github.com/aws/aws-sdk-go-v2/service/s3 v1.40.0/go.mod h1:rDGMZA7f4pbmTtPOk5v5UM github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8= github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -40,6 +38,8 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -65,34 +65,39 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opentelemetry.io/collector/component v0.87.0 h1:Q+lwM5WAa2x4a5lgyaF6SjFBpIij5gyjsoiv9KFG36A= -go.opentelemetry.io/collector/component v0.87.0/go.mod h1:LsfDQRkwJRHOSHNnM1/pdi/6EQNj41WpIxpZRqSdI0E= -go.opentelemetry.io/collector/config/configtelemetry v0.87.0 h1:xUqayM9b41OvXkjU3p8RkUr8hUrCjfDUmO+oKhRNSwc= -go.opentelemetry.io/collector/config/configtelemetry v0.87.0/go.mod h1:+LAXM5WFMW/UbTlAuSs6L/W72WC+q8TBJt/6z39FPOU= -go.opentelemetry.io/collector/confmap v0.87.0 h1:LFnyDKIOMtlJm5EsdcFN2t0rcU/QLbS9QEs/awM2HOA= -go.opentelemetry.io/collector/confmap v0.87.0/go.mod h1:inqYRP70+bMrUwGGnuhcWyyufxyU3VQT6rl3/EX0f+g= -go.opentelemetry.io/collector/extension v0.87.0 h1:EMIaEequ5rjWzoid6vNImjQGVMfzbME+8JSa5XACYKs= -go.opentelemetry.io/collector/extension v0.87.0/go.mod h1:D3srNZC99QVTAdLNUVuqfmmgJge4sQHDrnt5XWscvxI= -go.opentelemetry.io/collector/featuregate v1.0.0-rcv0016 h1:/6N9990tbjotvXgrXpV5AbaFiyxTdFEXDypGBHVDSQM= -go.opentelemetry.io/collector/featuregate v1.0.0-rcv0016/go.mod h1:fLmJMf1AoHttkF8p5oJAc4o5ZpHu8yO5XYJ7gbLCLzo= -go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 h1:qCPXSQCoD3qeWFb1RuIks8fw9Atxpk78bmtVdi15KhE= -go.opentelemetry.io/collector/pdata v1.0.0-rcv0016/go.mod h1:OdN0alYOlYhHXu6BDlGehrZWgtBuiDsz/rlNeJeXiNg= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/collector/component v0.84.1-0.20230908201109-ab3d6c5b6470 h1:Bh0c9F7Xc2OGGzBPqr8qSf0lTIzhDUES61TRd0UXZsc= +go.opentelemetry.io/collector/component v0.84.1-0.20230908201109-ab3d6c5b6470/go.mod h1:RJcjSU7iI/P4qMvnhvKJU73hkLp8UvPych4LiL8SMhY= +go.opentelemetry.io/collector/config/configtelemetry v0.84.1-0.20230908201109-ab3d6c5b6470 h1:KM7Uu6d35GfDEhtB3e0/fuV31gCIk2qqT2Ppq1FLAqA= +go.opentelemetry.io/collector/config/configtelemetry v0.84.1-0.20230908201109-ab3d6c5b6470/go.mod h1:+LAXM5WFMW/UbTlAuSs6L/W72WC+q8TBJt/6z39FPOU= +go.opentelemetry.io/collector/confmap v0.84.1-0.20230908201109-ab3d6c5b6470 h1:tteTmxiBmllwy6O8gH9gbedc1IjjFfnaGI0/YZY7CYc= +go.opentelemetry.io/collector/confmap v0.84.1-0.20230908201109-ab3d6c5b6470/go.mod h1:/SNHqYkLagF0TjBjQyCy2Gt3ZF6hTK8VKbaan/ZHuJs= +go.opentelemetry.io/collector/extension v0.84.1-0.20230908201109-ab3d6c5b6470 h1:fzzHomPcNWbf6k6fmehHnyz0T1ti96TjP+G5NXfz1og= +go.opentelemetry.io/collector/extension v0.84.1-0.20230908201109-ab3d6c5b6470/go.mod h1:FPOAdIEsz6PA48Xo3oaQxioBPjaMv9Kaj187cqyMqFU= +go.opentelemetry.io/collector/featuregate v1.0.0-rcv0014.0.20230908201109-ab3d6c5b6470 h1:W4D/cCSsvMaNZOk17ak19okMXb2iq07zaeABRlyALzQ= +go.opentelemetry.io/collector/featuregate v1.0.0-rcv0014.0.20230908201109-ab3d6c5b6470/go.mod h1:fLmJMf1AoHttkF8p5oJAc4o5ZpHu8yO5XYJ7gbLCLzo= +go.opentelemetry.io/collector/pdata v1.0.0-rcv0014.0.20230908201109-ab3d6c5b6470 h1:wGdaYUS9S4Ot+WxmsxpagV5+GypvGgX51lR2jT9Kw10= +go.opentelemetry.io/collector/pdata v1.0.0-rcv0014.0.20230908201109-ab3d6c5b6470/go.mod h1:En5jH+YI2KAJhyfpXvjw00OnhWEgGw4Ka0wsBZBWIEo= +go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM= +go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= +go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc= +go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o= +go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ= +go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -141,10 +146,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= @@ -153,5 +158,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/extension/awsmiddleware/middleware.go b/extension/awsmiddleware/middleware.go index 82e42e1d4b28..1d0154358754 100644 --- a/extension/awsmiddleware/middleware.go +++ b/extension/awsmiddleware/middleware.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package awsmiddleware // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/awsmiddleware" +package awsmiddleware // import "github.com/amazon-contributing/opentelemetry-collector-contrib/extension/awsmiddleware" import ( "encoding" @@ -85,20 +85,19 @@ type handlerConfig interface { // RequestHandler allows for custom processing of requests. type RequestHandler interface { handlerConfig - HandleRequest(r *http.Request) + HandleRequest(id string, r *http.Request) } // ResponseHandler allows for custom processing of responses. type ResponseHandler interface { handlerConfig - HandleResponse(r *http.Response) + HandleResponse(id string, r *http.Response) } // Middleware defines the request and response handlers to be configured // on AWS Clients. type Middleware interface { - RequestHandlers() []RequestHandler - ResponseHandlers() []ResponseHandler + Handlers() ([]RequestHandler, []ResponseHandler) } // Extension is an extension that implements Middleware. @@ -107,17 +106,31 @@ type Extension interface { Middleware } +// Configurer provides functions for applying request/response handlers +// to the AWS SDKs. +type Configurer struct { + requestHandlers []RequestHandler + responseHandlers []ResponseHandler +} + +// newConfigurer sets the request/response handlers. +func newConfigurer(requestHandlers []RequestHandler, responseHandlers []ResponseHandler) *Configurer { + return &Configurer{requestHandlers: requestHandlers, responseHandlers: responseHandlers} +} + // ConfigureSDKv1 adds middleware to the AWS SDK v1. Request handlers are added to the -// Build handler list and response handlers are added to the Unmarshal handler list. -func ConfigureSDKv1(mw Middleware, handlers *request.Handlers) error { +// Build handler list and response handlers are added to the ValidateResponse handler list. +// Build will only be run once per request, but if there are errors, ValidateResponse will +// be run again for each configured retry. +func (c Configurer) ConfigureSDKv1(handlers *request.Handlers) error { var errs error - for _, handler := range mw.RequestHandlers() { + for _, handler := range c.requestHandlers { if err := appendHandler(&handlers.Build, namedRequestHandler(handler), handler.Position()); err != nil { errs = errors.Join(errs, fmt.Errorf("%w (%q): %w", errInvalidHandler, handler.ID(), err)) } } - for _, handler := range mw.ResponseHandlers() { - if err := appendHandler(&handlers.Unmarshal, namedResponseHandler(handler), handler.Position()); err != nil { + for _, handler := range c.responseHandlers { + if err := appendHandler(&handlers.ValidateResponse, namedResponseHandler(handler), handler.Position()); err != nil { errs = errors.Join(errs, fmt.Errorf("%w (%q): %w", errInvalidHandler, handler.ID(), err)) } } @@ -126,9 +139,9 @@ func ConfigureSDKv1(mw Middleware, handlers *request.Handlers) error { // ConfigureSDKv2 adds middleware to the AWS SDK v2. Request handlers are added to the // Build step and response handlers are added to the Deserialize step. -func ConfigureSDKv2(mw Middleware, config *aws.Config) error { +func (c Configurer) ConfigureSDKv2(config *aws.Config) error { var errs error - for _, handler := range mw.RequestHandlers() { + for _, handler := range c.requestHandlers { relativePosition, err := toRelativePosition(handler.Position()) if err != nil { errs = errors.Join(errs, fmt.Errorf("%w (%q): %w", errInvalidHandler, handler.ID(), err)) @@ -136,7 +149,7 @@ func ConfigureSDKv2(mw Middleware, config *aws.Config) error { } config.APIOptions = append(config.APIOptions, withBuildOption(&requestMiddleware{RequestHandler: handler}, relativePosition)) } - for _, handler := range mw.ResponseHandlers() { + for _, handler := range c.responseHandlers { relativePosition, err := toRelativePosition(handler.Position()) if err != nil { errs = errors.Join(errs, fmt.Errorf("%w (%q): %w", errInvalidHandler, handler.ID(), err)) diff --git a/extension/awsmiddleware/middleware_test.go b/extension/awsmiddleware/middleware_test.go index 9a21a306600b..0ac775c42252 100644 --- a/extension/awsmiddleware/middleware_test.go +++ b/extension/awsmiddleware/middleware_test.go @@ -17,6 +17,7 @@ import ( "github.com/aws/aws-sdk-go/awstesting" s3v1 "github.com/aws/aws-sdk-go/service/s3" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) @@ -28,10 +29,12 @@ const ( type testHandler struct { id string position HandlerPosition - handleRequest func(r *http.Request) - handleResponse func(r *http.Response) + handleRequest func(id string, r *http.Request) + handleResponse func(id string, r *http.Response) start time.Time end time.Time + requestIDs []string + responseIDs []string } var _ RequestHandler = (*testHandler)(nil) @@ -45,17 +48,19 @@ func (t *testHandler) Position() HandlerPosition { return t.position } -func (t *testHandler) HandleRequest(r *http.Request) { +func (t *testHandler) HandleRequest(id string, r *http.Request) { t.start = time.Now() + t.requestIDs = append(t.requestIDs, id) if t.handleRequest != nil { - t.handleRequest(r) + t.handleRequest(id, r) } } -func (t *testHandler) HandleResponse(r *http.Response) { +func (t *testHandler) HandleResponse(id string, r *http.Response) { t.end = time.Now() + t.responseIDs = append(t.responseIDs, id) if t.handleResponse != nil { - t.handleResponse(r) + t.handleResponse(id, r) } } @@ -67,8 +72,8 @@ type recordOrder struct { order []string } -func (ro *recordOrder) handle(id string) func(*http.Request) { - return func(*http.Request) { +func (ro *recordOrder) Handle(id string) func(string, *http.Request) { + return func(string, *http.Request) { ro.order = append(ro.order, id) } } @@ -103,22 +108,25 @@ func TestInvalidHandlerPosition(t *testing.T) { } func TestInvalidHandlers(t *testing.T) { - invalidHandler := &testHandler{id: "invalid handler", position: -1} - testExtension := &testMiddlewareExtension{ - requestHandlers: []RequestHandler{invalidHandler}, - responseHandlers: []ResponseHandler{invalidHandler}, - } + handler := new(MockHandler) + handler.On("ID").Return("invalid handler") + handler.On("Position").Return(HandlerPosition(-1)) + middleware := new(MockMiddlewareExtension) + middleware.On("Handlers").Return([]RequestHandler{handler}, []ResponseHandler{handler}) + c := newConfigurer(middleware.Handlers()) // v1 client := awstesting.NewClient() - err := ConfigureSDKv1(testExtension, &client.Handlers) + err := c.ConfigureSDKv1(&client.Handlers) assert.Error(t, err) assert.True(t, errors.Is(err, errInvalidHandler)) assert.True(t, errors.Is(err, errUnsupportedPosition)) // v2 - err = ConfigureSDKv2(testExtension, &awsv2.Config{}) + err = c.ConfigureSDKv2(&awsv2.Config{}) assert.Error(t, err) assert.True(t, errors.Is(err, errInvalidHandler)) assert.True(t, errors.Is(err, errUnsupportedPosition)) + handler.AssertNotCalled(t, "HandleRequest", mock.Anything, mock.Anything) + handler.AssertNotCalled(t, "HandleResponse", mock.Anything, mock.Anything) } func TestAppendOrder(t *testing.T) { @@ -161,19 +169,31 @@ func TestAppendOrder(t *testing.T) { } for name, testCase := range testCases { t.Run(name, func(t *testing.T) { - middleware := &testMiddlewareExtension{} recorder := &recordOrder{} + var requestHandlers []RequestHandler for _, handler := range testCase.requestHandlers { - handler.handleRequest = recorder.handle(handler.id) - middleware.requestHandlers = append(middleware.requestHandlers, handler) + handler.handleRequest = recorder.Handle(handler.id) + requestHandlers = append(requestHandlers, handler) } + handler := new(MockHandler) + handler.On("ID").Return("mock") + handler.On("Position").Return(After) + handler.On("HandleRequest", mock.Anything, mock.Anything) + handler.On("HandleResponse", mock.Anything, mock.Anything) + requestHandlers = append(requestHandlers, handler) + middleware := new(MockMiddlewareExtension) + middleware.On("Handlers").Return( + requestHandlers, + []ResponseHandler{handler}, + ) + c := newConfigurer(middleware.Handlers()) // v1 client := awstesting.NewClient(&awsv1.Config{ Region: awsv1.String("mock-region"), DisableSSL: awsv1.Bool(true), Endpoint: awsv1.String(server.URL), }) - assert.NoError(t, ConfigureSDKv1(middleware, &client.Handlers)) + assert.NoError(t, c.ConfigureSDKv1(&client.Handlers)) s3v1Client := &s3v1.S3{Client: client} _, err := s3v1Client.ListBuckets(&s3v1.ListBucketsInput{}) require.NoError(t, err) @@ -181,7 +201,7 @@ func TestAppendOrder(t *testing.T) { recorder.order = nil // v2 cfg := awsv2.Config{Region: "us-east-1"} - assert.NoError(t, ConfigureSDKv2(middleware, &cfg)) + assert.NoError(t, c.ConfigureSDKv2(&cfg)) s3v2Client := s3v2.NewFromConfig(cfg, func(options *s3v2.Options) { options.BaseEndpoint = awsv2.String(server.URL) }) @@ -199,24 +219,26 @@ func TestConfigureSDKv1(t *testing.T) { Region: awsv1.String("mock-region"), DisableSSL: awsv1.Bool(true), Endpoint: awsv1.String(server.URL), + MaxRetries: awsv1.Int(0), }) require.Equal(t, 3, client.Handlers.Build.Len()) - require.Equal(t, 0, client.Handlers.Unmarshal.Len()) - assert.NoError(t, ConfigureSDKv1(middleware, &client.Handlers)) + require.Equal(t, 1, client.Handlers.ValidateResponse.Len()) + assert.NoError(t, newConfigurer(middleware.Handlers()).ConfigureSDKv1(&client.Handlers)) assert.Equal(t, 5, client.Handlers.Build.Len()) - assert.Equal(t, 1, client.Handlers.Unmarshal.Len()) + assert.Equal(t, 2, client.Handlers.ValidateResponse.Len()) s3Client := &s3v1.S3{Client: client} output, err := s3Client.ListBuckets(&s3v1.ListBucketsInput{}) require.NoError(t, err) assert.NotNil(t, output) assert.GreaterOrEqual(t, recorder.Latency(), testLatency) + assert.Equal(t, recorder.requestIDs, recorder.responseIDs) } func TestConfigureSDKv2(t *testing.T) { middleware, recorder, server := setup(t) defer server.Close() - cfg := awsv2.Config{Region: "us-east-1"} - assert.NoError(t, ConfigureSDKv2(middleware, &cfg)) + cfg := awsv2.Config{Region: "us-east-1", RetryMaxAttempts: 0} + assert.NoError(t, newConfigurer(middleware.Handlers()).ConfigureSDKv2(&cfg)) s3Client := s3v2.NewFromConfig(cfg, func(options *s3v2.Options) { options.BaseEndpoint = awsv2.String(server.URL) }) @@ -224,24 +246,27 @@ func TestConfigureSDKv2(t *testing.T) { require.NoError(t, err) assert.NotNil(t, output) assert.GreaterOrEqual(t, recorder.Latency(), testLatency) + assert.Equal(t, recorder.requestIDs, recorder.responseIDs) } -func setup(t *testing.T) (Middleware, *testHandler, *httptest.Server) { - t.Helper() - recorder := &testHandler{id: "LatencyTest", position: After} - middleware := &testMiddlewareExtension{ - requestHandlers: []RequestHandler{ - &testHandler{ - id: "UserAgentTest", - position: Before, - handleRequest: func(r *http.Request) { - r.Header.Set("User-Agent", testUserAgent) - }, - }, - recorder, +func userAgentHandler() RequestHandler { + return &testHandler{ + id: "test.UserAgent", + position: Before, + handleRequest: func(_ string, r *http.Request) { + r.Header.Set("User-Agent", testUserAgent) }, - responseHandlers: []ResponseHandler{recorder}, } +} + +func setup(t *testing.T) (Middleware, *testHandler, *httptest.Server) { + t.Helper() + recorder := &testHandler{id: "test.Latency", position: After} + middleware := new(MockMiddlewareExtension) + middleware.On("Handlers").Return( + []RequestHandler{userAgentHandler(), recorder}, + []ResponseHandler{recorder}, + ) server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotUserAgent := r.Header.Get("User-Agent") assert.Contains(t, gotUserAgent, testUserAgent) diff --git a/extension/awsmiddleware/mock.go b/extension/awsmiddleware/mock.go new file mode 100644 index 000000000000..afb8849c438a --- /dev/null +++ b/extension/awsmiddleware/mock.go @@ -0,0 +1,78 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package awsmiddleware // import "github.com/amazon-contributing/opentelemetry-collector-contrib/extension/awsmiddleware" + +import ( + "net/http" + + "github.com/stretchr/testify/mock" + "go.opentelemetry.io/collector/component" +) + +// MockMiddlewareExtension mocks the Extension interface. +type MockMiddlewareExtension struct { + component.StartFunc + component.ShutdownFunc + mock.Mock +} + +var _ Extension = (*MockMiddlewareExtension)(nil) + +func (m *MockMiddlewareExtension) Handlers() ([]RequestHandler, []ResponseHandler) { + var requestHandlers []RequestHandler + var responseHandlers []ResponseHandler + args := m.Called() + arg := args.Get(0) + if arg != nil { + requestHandlers = arg.([]RequestHandler) + } + arg = args.Get(1) + if arg != nil { + responseHandlers = arg.([]ResponseHandler) + } + return requestHandlers, responseHandlers +} + +// MockHandler mocks the functions for both +// RequestHandler and ResponseHandler. +type MockHandler struct { + mock.Mock +} + +var _ RequestHandler = (*MockHandler)(nil) +var _ ResponseHandler = (*MockHandler)(nil) + +func (m *MockHandler) ID() string { + args := m.Called() + return args.String(0) +} + +func (m *MockHandler) Position() HandlerPosition { + args := m.Called() + return args.Get(0).(HandlerPosition) +} + +func (m *MockHandler) HandleRequest(id string, r *http.Request) { + m.Called(id, r) +} + +func (m *MockHandler) HandleResponse(id string, r *http.Response) { + m.Called(id, r) +} + +// MockExtensionsHost only mocks the GetExtensions function. +// All other functions are ignored and will panic if called. +type MockExtensionsHost struct { + component.Host + mock.Mock +} + +func (m *MockExtensionsHost) GetExtensions() map[component.ID]component.Component { + args := m.Called() + arg := args.Get(0) + if arg == nil { + return nil + } + return arg.(map[component.ID]component.Component) +} diff --git a/extension/awsmiddleware/wrapper.go b/extension/awsmiddleware/wrapper.go index 77aa87fd9b83..9509b3c80515 100644 --- a/extension/awsmiddleware/wrapper.go +++ b/extension/awsmiddleware/wrapper.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package awsmiddleware // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/awsmiddleware" +package awsmiddleware // import "github.com/amazon-contributing/opentelemetry-collector-contrib/extension/awsmiddleware" import ( "context" @@ -9,17 +9,25 @@ import ( "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/transport/http" + "github.com/google/uuid" ) +type key struct{} + +var requestID key + func namedRequestHandler(handler RequestHandler) request.NamedHandler { return request.NamedHandler{Name: handler.ID(), Fn: func(r *request.Request) { - handler.HandleRequest(r.HTTPRequest) + ctx, id := setID(r.Context()) + r.SetContext(ctx) + handler.HandleRequest(id, r.HTTPRequest) }} } func namedResponseHandler(handler ResponseHandler) request.NamedHandler { return request.NamedHandler{Name: handler.ID(), Fn: func(r *request.Request) { - handler.HandleResponse(r.HTTPResponse) + id, _ := getID(r.Context()) + handler.HandleResponse(id, r.HTTPResponse) }} } @@ -32,7 +40,9 @@ var _ middleware.BuildMiddleware = (*requestMiddleware)(nil) func (r requestMiddleware) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) (out middleware.BuildOutput, metadata middleware.Metadata, err error) { req, ok := in.Request.(*http.Request) if ok { - r.HandleRequest(req.Request) + var id string + ctx, id = setID(ctx) + r.HandleRequest(id, req.Request) } return next.HandleBuild(ctx, in) } @@ -53,7 +63,8 @@ func (r responseMiddleware) HandleDeserialize(ctx context.Context, in middleware out, metadata, err = next.HandleDeserialize(ctx, in) res, ok := out.RawResponse.(*http.Response) if ok { - r.HandleResponse(res.Response) + id, _ := getID(ctx) + r.HandleResponse(id, res.Response) } return } @@ -63,3 +74,17 @@ func withDeserializeOption(rmw *responseMiddleware, position middleware.Relative return stack.Deserialize.Add(rmw, position) } } + +func setID(ctx context.Context) (context.Context, string) { + id, ok := getID(ctx) + if !ok { + id = uuid.NewString() + return context.WithValue(ctx, requestID, id), id + } + return ctx, id +} + +func getID(ctx context.Context) (string, bool) { + id, ok := ctx.Value(requestID).(string) + return id, ok +}