diff --git a/.chloggen/middleware-struct.yaml b/.chloggen/middleware-struct.yaml new file mode 100644 index 00000000000..870041bd700 --- /dev/null +++ b/.chloggen/middleware-struct.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: configmiddleware + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add configmiddleware struct. + +# One or more tracking issues or pull requests related to the change +issues: [12603, 9591] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] diff --git a/.github/workflows/utils/cspell.json b/.github/workflows/utils/cspell.json index 834c8c557b6..ddae277a155 100644 --- a/.github/workflows/utils/cspell.json +++ b/.github/workflows/utils/cspell.json @@ -192,6 +192,7 @@ "extensionauthtest", "extensioncapabilities", "extensionmiddleware", + "extensionmiddlewaretest", "extensionhelper", "extensiontest", "extensionz", @@ -269,6 +270,7 @@ "lables", "lastest", "ldflags", + "limitermiddleware", "localhostgate", "loggingexporter", "logstest", diff --git a/config/configmiddleware/Makefile b/config/configmiddleware/Makefile new file mode 100644 index 00000000000..ded7a36092d --- /dev/null +++ b/config/configmiddleware/Makefile @@ -0,0 +1 @@ +include ../../Makefile.Common diff --git a/config/configmiddleware/README.md b/config/configmiddleware/README.md new file mode 100644 index 00000000000..2dfe728f3fb --- /dev/null +++ b/config/configmiddleware/README.md @@ -0,0 +1,37 @@ +# OpenTelemetry Collector Middleware Configuration + +This package implements a configuration struct for referring to +[middleware extensions](../../extension/extensionmiddleware/README.md). + +## Overview + +The `configmiddleware` package defines a `Config` type that +allows components to configure middleware extensions, typically as +an ordered list. +This support is built in for push-based receivers configured through +`confighttp` and `configgrpc`, as for example in the OTLP receiver: + +```yaml +receivers: + otlp: + protocols: + http: + middlewares: + - id: limitermiddleware +``` + +## Methods + +The package provides four key methods to retrieve appropriate middleware handlers: + +1. **GetHTTPClientRoundTripper**: Obtains a function to wrap an HTTP client with a middleware extension via a `http.RoundTripper`. + +2. **GetHTTPServerHandler**: Obtains a function to wrap an HTTP server with a middleware extension via a `http.Handler`. + +3. **GetGRPCClientOptions**: Obtains a `[]grpc.DialOption` that configure a middleware extension for gRPC clients. + +4. **GetGRPCServerOptions**: Obtains a `[]grpc.ServerOption` that configure a middleware extension for gRPC servers. + +These functions are typically called during Start() by a component, +passing the `component.Host` extensions. +An error is returned if the named extension cannot be found. diff --git a/config/configmiddleware/configmiddleware.go b/config/configmiddleware/configmiddleware.go new file mode 100644 index 00000000000..de21ad844b4 --- /dev/null +++ b/config/configmiddleware/configmiddleware.go @@ -0,0 +1,92 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Package configmiddleware implements a configuration struct to +// name middleware extensions. +package configmiddleware // import "go.opentelemetry.io/collector/config/configmiddleware" + +import ( + "context" + "errors" + "fmt" + "net/http" + + "google.golang.org/grpc" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/extension/extensionmiddleware" +) + +var ( + errMiddlewareNotFound = errors.New("middleware not found") + errNotHTTPServer = errors.New("requested extension is not an HTTP server middleware") + errNotGRPCServer = errors.New("requested extension is not a gRPC server middleware") + errNotHTTPClient = errors.New("requested extension is not an HTTP client middleware") + errNotGRPCClient = errors.New("requested extension is not a gRPC client middleware") +) + +// Middleware defines the extension ID for a middleware component. +type Config struct { + // ID specifies the name of the extension to use. + ID component.ID `mapstructure:"id,omitempty"` +} + +// GetHTTPClientRoundTripper attempts to select the appropriate +// extensionmiddleware.HTTPClient from the map of extensions, and +// returns the HTTP client wrapper function. If a middleware is not +// found, an error is returned. This should only be used by HTTP +// clients. +func (m Config) GetHTTPClientRoundTripper(_ context.Context, extensions map[component.ID]component.Component) (func(http.RoundTripper) (http.RoundTripper, error), error) { + if ext, found := extensions[m.ID]; found { + if client, ok := ext.(extensionmiddleware.HTTPClient); ok { + return client.GetHTTPRoundTripper, nil + } + return nil, errNotHTTPClient + } + return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound) +} + +// GetHTTPServerHandler attempts to select the appropriate +// extensionmiddleware.HTTPServer from the map of extensions, and +// returns the http.Handler wrapper function. If a middleware is not +// found, an error is returned. This should only be used by HTTP +// servers. +func (m Config) GetHTTPServerHandler(_ context.Context, extensions map[component.ID]component.Component) (func(http.Handler) (http.Handler, error), error) { + if ext, found := extensions[m.ID]; found { + if server, ok := ext.(extensionmiddleware.HTTPServer); ok { + return server.GetHTTPHandler, nil + } + return nil, errNotHTTPServer + } + + return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound) +} + +// GetGRPCClientOptions attempts to select the appropriate +// extensionmiddleware.GRPCClient from the map of extensions, and +// returns the gRPC dial options. If a middleware is not found, an +// error is returned. This should only be used by gRPC clients. +func (m Config) GetGRPCClientOptions(_ context.Context, extensions map[component.ID]component.Component) ([]grpc.DialOption, error) { + if ext, found := extensions[m.ID]; found { + if client, ok := ext.(extensionmiddleware.GRPCClient); ok { + return client.GetGRPCClientOptions() + } + return nil, errNotGRPCClient + } + return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound) +} + +// GetGRPCServerOptions attempts to select the appropriate +// extensionmiddleware.GRPCServer from the map of extensions, and +// returns the gRPC server options. If a middleware is not found, an +// error is returned. This should only be used by gRPC servers. +func (m Config) GetGRPCServerOptions(_ context.Context, extensions map[component.ID]component.Component) ([]grpc.ServerOption, error) { + if ext, found := extensions[m.ID]; found { + if server, ok := ext.(extensionmiddleware.GRPCServer); ok { + return server.GetGRPCServerOptions() + } + return nil, errNotGRPCServer + } + + return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound) +} diff --git a/config/configmiddleware/configmiddleware_test.go b/config/configmiddleware/configmiddleware_test.go new file mode 100644 index 00000000000..5cdb2628fba --- /dev/null +++ b/config/configmiddleware/configmiddleware_test.go @@ -0,0 +1,256 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package configmiddleware + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/extension" + "go.opentelemetry.io/collector/extension/extensionmiddleware" + "go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest" +) + +var testID = component.MustNewID("test") + +type mockWrongType struct { + component.StartFunc + component.ShutdownFunc +} + +func TestConfig_GetHTTPServerHandler(t *testing.T) { + ctx := context.Background() + + tests := []struct { + name string + middleware Config + extensions map[component.ID]component.Component + wantErr error + }{ + { + name: "found_and_valid", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{ + testID: extensionmiddlewaretest.NewNop(), + }, + wantErr: nil, + }, + { + name: "middleware_not_found", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{}, + wantErr: errMiddlewareNotFound, + }, + { + name: "middleware_wrong_type", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{ + testID: mockWrongType{}, + }, + wantErr: errNotHTTPServer, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + value, err := tt.middleware.GetHTTPServerHandler(ctx, tt.extensions) + + if tt.wantErr != nil { + require.ErrorIs(t, err, tt.wantErr) + } else { + require.NoError(t, err) + require.NotNil(t, value) + } + }) + } +} + +func TestConfig_GetHTTPClientRoundTripper(t *testing.T) { + ctx := context.Background() + + tests := []struct { + name string + middleware Config + extensions map[component.ID]component.Component + wantErr error + }{ + { + name: "found_and_valid", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{ + testID: extensionmiddlewaretest.NewNop(), + }, + wantErr: nil, + }, + { + name: "middleware_not_found", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{}, + wantErr: errMiddlewareNotFound, + }, + { + name: "middleware_wrong_type", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{ + testID: mockWrongType{}, + }, + wantErr: errNotHTTPClient, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + value, err := tt.middleware.GetHTTPClientRoundTripper(ctx, tt.extensions) + + if tt.wantErr != nil { + require.ErrorIs(t, err, tt.wantErr) + } else { + require.NoError(t, err) + require.NotNil(t, value) + } + }) + } +} + +func TestConfig_GetGRPCServerOptions(t *testing.T) { + ctx := context.Background() + + tests := []struct { + name string + middleware Config + extensions map[component.ID]component.Component + wantErr error + }{ + { + name: "found_and_valid", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{ + testID: struct { + extension.Extension + extensionmiddleware.GetGRPCServerOptionsFunc + }{ + Extension: extensionmiddlewaretest.NewNop(), + GetGRPCServerOptionsFunc: func() ([]grpc.ServerOption, error) { + return []grpc.ServerOption{ + grpc.EmptyServerOption{}, + }, nil + }, + }, + }, + wantErr: nil, + }, + { + name: "middleware_not_found", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{}, + wantErr: errMiddlewareNotFound, + }, + { + name: "middleware_wrong_type", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{ + testID: mockWrongType{}, + }, + wantErr: errNotGRPCServer, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + value, err := tt.middleware.GetGRPCServerOptions(ctx, tt.extensions) + + if tt.wantErr != nil { + require.ErrorIs(t, err, tt.wantErr) + } else { + require.NoError(t, err) + require.NotNil(t, value) + } + }) + } +} + +func TestConfig_GetGRPCClientOptions(t *testing.T) { + ctx := context.Background() + + tests := []struct { + name string + middleware Config + extensions map[component.ID]component.Component + wantErr error + }{ + { + name: "found_and_valid", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{ + testID: struct { + extension.Extension + extensionmiddleware.GetGRPCClientOptionsFunc + }{ + Extension: extensionmiddlewaretest.NewNop(), + GetGRPCClientOptionsFunc: func() ([]grpc.DialOption, error) { + return []grpc.DialOption{ + grpc.EmptyDialOption{}, + }, nil + }, + }, + }, + wantErr: nil, + }, + { + name: "middleware_not_found", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{}, + wantErr: errMiddlewareNotFound, + }, + { + name: "middleware_wrong_type", + middleware: Config{ + ID: testID, + }, + extensions: map[component.ID]component.Component{ + testID: mockWrongType{}, + }, + wantErr: errNotGRPCClient, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + value, err := tt.middleware.GetGRPCClientOptions(ctx, tt.extensions) + + if tt.wantErr != nil { + require.ErrorIs(t, err, tt.wantErr) + } else { + require.NoError(t, err) + require.NotNil(t, value) + } + }) + } +} diff --git a/config/configmiddleware/go.mod b/config/configmiddleware/go.mod new file mode 100644 index 00000000000..7eb41290f22 --- /dev/null +++ b/config/configmiddleware/go.mod @@ -0,0 +1,56 @@ +module go.opentelemetry.io/collector/config/configmiddleware + +go 1.23.0 + +require ( + github.com/stretchr/testify v1.10.0 + go.opentelemetry.io/collector/component v1.30.0 + go.opentelemetry.io/collector/extension v1.30.0 + go.opentelemetry.io/collector/extension/extensionmiddleware v1.30.0 + go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest v0.0.0-00010101000000-000000000000 + google.golang.org/grpc v1.71.1 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/collector/featuregate v1.30.0 // indirect + go.opentelemetry.io/collector/internal/telemetry v0.124.0 // indirect + go.opentelemetry.io/collector/pdata v1.30.0 // indirect + go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/log v0.11.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/sdk v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/text v0.24.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace go.opentelemetry.io/collector/component => ../../component + +replace go.opentelemetry.io/collector/internal/telemetry => ../../internal/telemetry + +replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware + +replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest + +replace go.opentelemetry.io/collector/pdata => ../../pdata + +replace go.opentelemetry.io/collector/pipeline => ../../pipeline + +replace go.opentelemetry.io/collector/featuregate => ../../featuregate + +replace go.opentelemetry.io/collector/extension => ../../extension diff --git a/config/configmiddleware/go.sum b/config/configmiddleware/go.sum new file mode 100644 index 00000000000..519e188048f --- /dev/null +++ b/config/configmiddleware/go.sum @@ -0,0 +1,95 @@ +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= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 h1:ojdSRDvjrnm30beHOmwsSvLpoRF40MlwNCA+Oo93kXU= +go.opentelemetry.io/contrib/bridges/otelzap v0.10.0/go.mod h1:oTTm4g7NEtHSV2i/0FeVdPaPgUIZPfQkFbq0vbzqnv0= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/log v0.11.0 h1:c24Hrlk5WJ8JWcwbQxdBqxZdOK7PcP/LFtOtwpDTe3Y= +go.opentelemetry.io/otel/log v0.11.0/go.mod h1:U/sxQ83FPmT29trrifhQg+Zj2lo1/IPN1PF6RTFqdwc= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +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.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +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= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI= +google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +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/extensionmiddleware/README.md b/extension/extensionmiddleware/README.md index a28aa0f8842..fd4c8747ed8 100644 --- a/extension/extensionmiddleware/README.md +++ b/extension/extensionmiddleware/README.md @@ -2,7 +2,8 @@ This package implements interfaces for injecting middleware behavior in OpenTelemetry Collector exporters and receivers. See the -associated `configmiddleware` package for referring to middleware +[associated `configmiddleware` package](../../config/configmiddleware/README.md) +for referring to middleware extensions in component configurations. ## Overview @@ -35,7 +36,8 @@ extension cannot be configured. New protocols and new ways to configure middleware can be introduced by adding new interfaces. Note that for each interface, there is a corresponding method to locate a named middleware extension that -satisfies the interface in the `configmiddleware` package. +satisfies the interface in +[the `configmiddleware` package](../../config/configmiddleware/README.md) . ### HTTP diff --git a/extension/extensionmiddleware/client.go b/extension/extensionmiddleware/client.go index 7b70bf82b0a..fb24a18339e 100644 --- a/extension/extensionmiddleware/client.go +++ b/extension/extensionmiddleware/client.go @@ -20,3 +20,27 @@ type GRPCClient interface { // GetGRPCClientOptions returns the gRPC dial options to use for client connections. GetGRPCClientOptions() ([]grpc.DialOption, error) } + +var _ HTTPClient = (*GetHTTPRoundTripperFunc)(nil) + +// GetHTTPRoundTripperFunc is a function that implements HTTPClient. +type GetHTTPRoundTripperFunc func(base http.RoundTripper) (http.RoundTripper, error) + +func (f GetHTTPRoundTripperFunc) GetHTTPRoundTripper(base http.RoundTripper) (http.RoundTripper, error) { + if f == nil { + return base, nil + } + return f(base) +} + +var _ GRPCClient = (*GetGRPCClientOptionsFunc)(nil) + +// GetGRPCClientOptionsFunc is a function that implements GRPCClient. +type GetGRPCClientOptionsFunc func() ([]grpc.DialOption, error) + +func (f GetGRPCClientOptionsFunc) GetGRPCClientOptions() ([]grpc.DialOption, error) { + if f == nil { + return nil, nil + } + return f() +} diff --git a/extension/extensionmiddleware/client_test.go b/extension/extensionmiddleware/client_test.go new file mode 100644 index 00000000000..c525ffa3b76 --- /dev/null +++ b/extension/extensionmiddleware/client_test.go @@ -0,0 +1,114 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package extensionmiddleware + +import ( + "errors" + "net/http" + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/grpc" +) + +func TestGetHTTPRoundTripperFunc(t *testing.T) { + // Create a base round tripper for testing + baseRT := http.DefaultTransport + + t.Run("nil function", func(t *testing.T) { + var nilFunc GetHTTPRoundTripperFunc + rt, err := nilFunc.GetHTTPRoundTripper(baseRT) + require.NoError(t, err) + require.Equal(t, baseRT, rt) + }) + + t.Run("identity function", func(t *testing.T) { + identityFunc := GetHTTPRoundTripperFunc(func(base http.RoundTripper) (http.RoundTripper, error) { + return base, nil + }) + rt, err := identityFunc.GetHTTPRoundTripper(baseRT) + require.NoError(t, err) + require.Equal(t, baseRT, rt) + }) + + t.Run("wrapping function", func(t *testing.T) { + // Create a custom round tripper wrapper for testing + customRT := &testRoundTripper{base: baseRT} + + wrapperFunc := GetHTTPRoundTripperFunc(func(base http.RoundTripper) (http.RoundTripper, error) { + return &testRoundTripper{base: base}, nil + }) + + rt, err := wrapperFunc.GetHTTPRoundTripper(baseRT) + require.NoError(t, err) + require.IsType(t, customRT, rt, "wrapper function should return the custom round tripper") + }) + + t.Run("error function", func(t *testing.T) { + expectedErr := errors.New("round tripper error") + errorFunc := GetHTTPRoundTripperFunc(func(_ http.RoundTripper) (http.RoundTripper, error) { + return nil, expectedErr + }) + + rt, err := errorFunc.GetHTTPRoundTripper(baseRT) + require.Error(t, err) + require.Equal(t, expectedErr, err) + require.Nil(t, rt) + }) +} + +// testRoundTripper is a simple round tripper implementation for testing +type testRoundTripper struct { + base http.RoundTripper +} + +func (t *testRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + // Just delegate to the base round tripper + return t.base.RoundTrip(req) +} + +func TestGetGRPCClientOptionsFunc(t *testing.T) { + t.Run("nil function", func(t *testing.T) { + var nilFunc GetGRPCClientOptionsFunc + options, err := nilFunc.GetGRPCClientOptions() + require.NoError(t, err) + require.Nil(t, options) + }) + + t.Run("empty options function", func(t *testing.T) { + emptyFunc := GetGRPCClientOptionsFunc(func() ([]grpc.DialOption, error) { + return []grpc.DialOption{}, nil + }) + + options, err := emptyFunc.GetGRPCClientOptions() + require.NoError(t, err) + require.Empty(t, options) + }) + + t.Run("options function", func(t *testing.T) { + // Create some test dial options + dialOpt1 := grpc.WithAuthority("test-authority") + dialOpt2 := grpc.WithDisableRetry() + + optionsFunc := GetGRPCClientOptionsFunc(func() ([]grpc.DialOption, error) { + return []grpc.DialOption{dialOpt1, dialOpt2}, nil + }) + + options, err := optionsFunc.GetGRPCClientOptions() + require.NoError(t, err) + require.Len(t, options, 2) + }) + + t.Run("error function", func(t *testing.T) { + expectedErr := errors.New("grpc options error") + errorFunc := GetGRPCClientOptionsFunc(func() ([]grpc.DialOption, error) { + return nil, expectedErr + }) + + options, err := errorFunc.GetGRPCClientOptions() + require.Error(t, err) + require.Equal(t, expectedErr, err) + require.Nil(t, options) + }) +} diff --git a/extension/extensionmiddleware/extensionmiddlewaretest/Makefile b/extension/extensionmiddleware/extensionmiddlewaretest/Makefile new file mode 100644 index 00000000000..bdd863a203b --- /dev/null +++ b/extension/extensionmiddleware/extensionmiddlewaretest/Makefile @@ -0,0 +1 @@ +include ../../../Makefile.Common diff --git a/extension/extensionmiddleware/extensionmiddlewaretest/err.go b/extension/extensionmiddleware/extensionmiddlewaretest/err.go new file mode 100644 index 00000000000..b881dae2c51 --- /dev/null +++ b/extension/extensionmiddleware/extensionmiddlewaretest/err.go @@ -0,0 +1,50 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package extensionmiddlewaretest // import "go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest" + +import ( + "net/http" + + "google.golang.org/grpc" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/extension" + "go.opentelemetry.io/collector/extension/extensionmiddleware" +) + +var ( + _ extension.Extension = (*baseExtension)(nil) + _ extensionmiddleware.HTTPClient = (*baseExtension)(nil) + _ extensionmiddleware.GRPCClient = (*baseExtension)(nil) + _ extensionmiddleware.HTTPServer = (*baseExtension)(nil) + _ extensionmiddleware.GRPCServer = (*baseExtension)(nil) +) + +type baseExtension struct { + component.StartFunc + component.ShutdownFunc + extensionmiddleware.GetHTTPHandlerFunc + extensionmiddleware.GetGRPCServerOptionsFunc + extensionmiddleware.GetHTTPRoundTripperFunc + extensionmiddleware.GetGRPCClientOptionsFunc +} + +// NewErr returns a new [extension.Extension] that implements all +// extensionmiddleware interface and always returns an error. +func NewErr(err error) extension.Extension { + return &baseExtension{ + GetHTTPRoundTripperFunc: func(http.RoundTripper) (http.RoundTripper, error) { + return nil, err + }, + GetGRPCClientOptionsFunc: func() ([]grpc.DialOption, error) { + return nil, err + }, + GetHTTPHandlerFunc: func(http.Handler) (http.Handler, error) { + return nil, err + }, + GetGRPCServerOptionsFunc: func() ([]grpc.ServerOption, error) { + return nil, err + }, + } +} diff --git a/extension/extensionmiddleware/extensionmiddlewaretest/err_test.go b/extension/extensionmiddleware/extensionmiddlewaretest/err_test.go new file mode 100644 index 00000000000..14bcf291b5b --- /dev/null +++ b/extension/extensionmiddleware/extensionmiddlewaretest/err_test.go @@ -0,0 +1,41 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package extensionmiddlewaretest + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/extension/extensionmiddleware" +) + +func TestErrClient(t *testing.T) { + client := NewErr(errors.New("error")) + + httpClient, ok := client.(extensionmiddleware.HTTPClient) + require.True(t, ok) + _, err := httpClient.GetHTTPRoundTripper(nil) + require.Error(t, err) + + grpcClient, ok := client.(extensionmiddleware.GRPCClient) + require.True(t, ok) + _, err = grpcClient.GetGRPCClientOptions() + require.Error(t, err) +} + +func TestErrServer(t *testing.T) { + server := NewErr(errors.New("error")) + + httpServer, ok := server.(extensionmiddleware.HTTPServer) + require.True(t, ok) + _, err := httpServer.GetHTTPHandler(nil) + require.Error(t, err) + + grpcServer, ok := server.(extensionmiddleware.GRPCServer) + require.True(t, ok) + _, err = grpcServer.GetGRPCServerOptions() + require.Error(t, err) +} diff --git a/extension/extensionmiddleware/extensionmiddlewaretest/go.mod b/extension/extensionmiddleware/extensionmiddlewaretest/go.mod new file mode 100644 index 00000000000..802ca6673ee --- /dev/null +++ b/extension/extensionmiddleware/extensionmiddlewaretest/go.mod @@ -0,0 +1,53 @@ +module go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest + +go 1.23.0 + +require ( + github.com/stretchr/testify v1.10.0 + go.opentelemetry.io/collector/component v1.30.0 + go.opentelemetry.io/collector/extension v1.30.0 + go.opentelemetry.io/collector/extension/extensionmiddleware v1.30.0 + google.golang.org/grpc v1.71.1 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/collector/featuregate v1.30.0 // indirect + go.opentelemetry.io/collector/internal/telemetry v0.124.0 // indirect + go.opentelemetry.io/collector/pdata v1.30.0 // indirect + go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/log v0.11.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/sdk v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/text v0.24.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace go.opentelemetry.io/collector/extension/extensionmiddleware => .. + +replace go.opentelemetry.io/collector/component => ../../../component + +replace go.opentelemetry.io/collector/pdata => ../../../pdata + +replace go.opentelemetry.io/collector/extension => ../.. + +replace go.opentelemetry.io/collector/internal/telemetry => ../../../internal/telemetry + +replace go.opentelemetry.io/collector/pipeline => ../../../pipeline + +replace go.opentelemetry.io/collector/featuregate => ../../../featuregate diff --git a/extension/extensionmiddleware/extensionmiddlewaretest/go.sum b/extension/extensionmiddleware/extensionmiddlewaretest/go.sum new file mode 100644 index 00000000000..519e188048f --- /dev/null +++ b/extension/extensionmiddleware/extensionmiddlewaretest/go.sum @@ -0,0 +1,95 @@ +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= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 h1:ojdSRDvjrnm30beHOmwsSvLpoRF40MlwNCA+Oo93kXU= +go.opentelemetry.io/contrib/bridges/otelzap v0.10.0/go.mod h1:oTTm4g7NEtHSV2i/0FeVdPaPgUIZPfQkFbq0vbzqnv0= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/log v0.11.0 h1:c24Hrlk5WJ8JWcwbQxdBqxZdOK7PcP/LFtOtwpDTe3Y= +go.opentelemetry.io/otel/log v0.11.0/go.mod h1:U/sxQ83FPmT29trrifhQg+Zj2lo1/IPN1PF6RTFqdwc= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +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.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +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= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI= +google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +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/extensionmiddleware/extensionmiddlewaretest/nop.go b/extension/extensionmiddleware/extensionmiddlewaretest/nop.go new file mode 100644 index 00000000000..7d8415577cf --- /dev/null +++ b/extension/extensionmiddleware/extensionmiddlewaretest/nop.go @@ -0,0 +1,16 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package extensionmiddlewaretest // import "go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest" + +import ( + "go.opentelemetry.io/collector/extension" +) + +// NewNop returns a new [extension.Extension] that implements +// the all the extensionmiddleware interfaces. For HTTP requests it +// returns the base RoundTripper and for gRPC requests it returns an +// empty slice of options. +func NewNop() extension.Extension { + return &baseExtension{} +} diff --git a/extension/extensionmiddleware/extensionmiddlewaretest/nop_test.go b/extension/extensionmiddleware/extensionmiddlewaretest/nop_test.go new file mode 100644 index 00000000000..4b136369f75 --- /dev/null +++ b/extension/extensionmiddleware/extensionmiddlewaretest/nop_test.go @@ -0,0 +1,44 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package extensionmiddlewaretest + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/extension/extensionmiddleware" +) + +func TestNopClient(t *testing.T) { + client := NewNop() + + httpClient, ok := client.(extensionmiddleware.HTTPClient) + require.True(t, ok) + rt, err := httpClient.GetHTTPRoundTripper(nil) + require.NoError(t, err) + require.Nil(t, rt) + + grpcClient, ok := client.(extensionmiddleware.GRPCClient) + require.True(t, ok) + grpcOpts, err := grpcClient.GetGRPCClientOptions() + require.NoError(t, err) + require.Nil(t, grpcOpts) +} + +func TestNopServer(t *testing.T) { + client := NewNop() + + httpServer, ok := client.(extensionmiddleware.HTTPServer) + require.True(t, ok) + rt, err := httpServer.GetHTTPHandler(nil) + require.NoError(t, err) + require.Nil(t, rt) + + grpcServer, ok := client.(extensionmiddleware.GRPCServer) + require.True(t, ok) + grpcOpts, err := grpcServer.GetGRPCServerOptions() + require.NoError(t, err) + require.Nil(t, grpcOpts) +} diff --git a/extension/extensionmiddleware/go.mod b/extension/extensionmiddleware/go.mod index 8dba1fab9a5..f088b016566 100644 --- a/extension/extensionmiddleware/go.mod +++ b/extension/extensionmiddleware/go.mod @@ -2,12 +2,18 @@ module go.opentelemetry.io/collector/extension/extensionmiddleware go 1.23.0 -require google.golang.org/grpc v1.71.1 +require ( + github.com/stretchr/testify v1.10.0 + google.golang.org/grpc v1.71.1 +) require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/net v0.39.0 // indirect golang.org/x/sys v0.32.0 // indirect golang.org/x/text v0.24.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect google.golang.org/protobuf v1.36.4 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/extension/extensionmiddleware/go.sum b/extension/extensionmiddleware/go.sum index abed198de41..17e3a338101 100644 --- a/extension/extensionmiddleware/go.sum +++ b/extension/extensionmiddleware/go.sum @@ -1,3 +1,5 @@ +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= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -8,6 +10,10 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= @@ -32,3 +38,7 @@ google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI= google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +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/extensionmiddleware/server.go b/extension/extensionmiddleware/server.go index 46fdb105126..6fa9ca1ae60 100644 --- a/extension/extensionmiddleware/server.go +++ b/extension/extensionmiddleware/server.go @@ -20,3 +20,27 @@ type GRPCServer interface { // GetGRPCServerOptions returns options for a gRPC server. GetGRPCServerOptions() ([]grpc.ServerOption, error) } + +var _ HTTPServer = (*GetHTTPHandlerFunc)(nil) + +// GetHTTPHandlerFunc is a function that implements HTTPServer. +type GetHTTPHandlerFunc func(base http.Handler) (http.Handler, error) + +func (f GetHTTPHandlerFunc) GetHTTPHandler(base http.Handler) (http.Handler, error) { + if f == nil { + return base, nil + } + return f(base) +} + +var _ GRPCServer = (*GetGRPCServerOptionsFunc)(nil) + +// GetGRPCServerOptionsFunc is a function that implements GRPCServer. +type GetGRPCServerOptionsFunc func() ([]grpc.ServerOption, error) + +func (f GetGRPCServerOptionsFunc) GetGRPCServerOptions() ([]grpc.ServerOption, error) { + if f == nil { + return nil, nil + } + return f() +} diff --git a/extension/extensionmiddleware/server_test.go b/extension/extensionmiddleware/server_test.go new file mode 100644 index 00000000000..e5b00cb7f1c --- /dev/null +++ b/extension/extensionmiddleware/server_test.go @@ -0,0 +1,106 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package extensionmiddleware + +import ( + "context" + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/grpc" +) + +func TestGetHTTPHandlerFunc(t *testing.T) { + t.Run("nil_function", func(t *testing.T) { + var f GetHTTPHandlerFunc + baseHandler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNoContent) + }) + + handler, err := f.GetHTTPHandler(baseHandler) + require.NoError(t, err) + + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/", nil)) + require.Equal(t, http.StatusNoContent, rr.Code) + }) + + t.Run("returns_wrapped_handler", func(t *testing.T) { + called := false + baseHandler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }) + + f := GetHTTPHandlerFunc(func(base http.Handler) (http.Handler, error) { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + called = true + base.ServeHTTP(w, r) + }), nil + }) + + handler, err := f.GetHTTPHandler(baseHandler) + require.NoError(t, err) + require.NotNil(t, handler) + + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/", nil)) + require.True(t, called) + require.Equal(t, http.StatusOK, rr.Code) + }) + + t.Run("returns_error", func(t *testing.T) { + expectedErr := errors.New("test error") + f := GetHTTPHandlerFunc(func(http.Handler) (http.Handler, error) { + return nil, expectedErr + }) + + baseHandler := http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) + handler, err := f.GetHTTPHandler(baseHandler) + require.Equal(t, expectedErr, err) + require.Nil(t, handler) + }) +} + +func TestGetGRPCServerOptionsFunc(t *testing.T) { + t.Run("nil_function", func(t *testing.T) { + var f GetGRPCServerOptionsFunc + opts, err := f.GetGRPCServerOptions() + require.NoError(t, err) + require.Nil(t, opts) + }) + + t.Run("returns_server_options", func(t *testing.T) { + var interceptor grpc.UnaryServerInterceptor = func( + context.Context, + any, + *grpc.UnaryServerInfo, + grpc.UnaryHandler, + ) (resp any, err error) { + return nil, nil + } + expectedOpts := []grpc.ServerOption{grpc.UnaryInterceptor(interceptor)} + + f := GetGRPCServerOptionsFunc(func() ([]grpc.ServerOption, error) { + return expectedOpts, nil + }) + + opts, err := f.GetGRPCServerOptions() + require.NoError(t, err) + require.Equal(t, expectedOpts, opts) + }) + + t.Run("returns_error", func(t *testing.T) { + expectedErr := errors.New("test error") + f := GetGRPCServerOptionsFunc(func() ([]grpc.ServerOption, error) { + return nil, expectedErr + }) + + opts, err := f.GetGRPCServerOptions() + require.Equal(t, expectedErr, err) + require.Nil(t, opts) + }) +} diff --git a/versions.yaml b/versions.yaml index 99c4e58a863..c45665201b9 100644 --- a/versions.yaml +++ b/versions.yaml @@ -42,6 +42,7 @@ module-sets: - go.opentelemetry.io/collector/config/configgrpc - go.opentelemetry.io/collector/config/confighttp - go.opentelemetry.io/collector/config/confighttp/xconfighttp + - go.opentelemetry.io/collector/config/configmiddleware - go.opentelemetry.io/collector/config/configtelemetry - go.opentelemetry.io/collector/connector - go.opentelemetry.io/collector/connector/connectortest @@ -62,6 +63,7 @@ module-sets: - go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest - go.opentelemetry.io/collector/extension/extensioncapabilities - go.opentelemetry.io/collector/extension/extensionmiddleware + - go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest - go.opentelemetry.io/collector/extension/extensiontest - go.opentelemetry.io/collector/extension/zpagesextension - go.opentelemetry.io/collector/extension/memorylimiterextension