diff --git a/.chloggen/rename_httpforwarder_extension.yaml b/.chloggen/rename_httpforwarder_extension.yaml new file mode 100755 index 0000000000000..70fdf8d79abbc --- /dev/null +++ b/.chloggen/rename_httpforwarder_extension.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: breaking + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: httpforwarderextension + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Rename the extension httpforwarder to httpforwarderextension + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [24171] + +# (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: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# 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: [api] diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 09efbbea47cb6..b4c3acdcead51 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -95,6 +95,7 @@ extension/encoding/zipkinencodingextension/ @open-telemetry/collect extension/headerssetterextension/ @open-telemetry/collector-contrib-approvers @jpkrohling extension/healthcheckextension/ @open-telemetry/collector-contrib-approvers @jpkrohling extension/httpforwarder/ @open-telemetry/collector-contrib-approvers @atoulme @rmfitzpatrick +extension/httpforwarderextension/ @open-telemetry/collector-contrib-approvers @atoulme @rmfitzpatrick extension/jaegerremotesampling/ @open-telemetry/collector-contrib-approvers @yurishkuro @frzifus extension/oauth2clientauthextension/ @open-telemetry/collector-contrib-approvers @pavankrish123 @jpkrohling extension/observer/ @open-telemetry/collector-contrib-approvers @dmitryax @rmfitzpatrick diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index c1a9b6ab3408f..963be869484f0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -95,6 +95,7 @@ body: - extension/headerssetter - extension/healthcheck - extension/httpforwarder + - extension/httpforwarder - extension/jaegerremotesampling - extension/oauth2clientauth - extension/observer diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 5beccbc3d90a3..d0be3e7e593d3 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -89,6 +89,7 @@ body: - extension/headerssetter - extension/healthcheck - extension/httpforwarder + - extension/httpforwarder - extension/jaegerremotesampling - extension/oauth2clientauth - extension/observer diff --git a/.github/ISSUE_TEMPLATE/other.yaml b/.github/ISSUE_TEMPLATE/other.yaml index 8bb53e45f08d8..9381aa28e559a 100644 --- a/.github/ISSUE_TEMPLATE/other.yaml +++ b/.github/ISSUE_TEMPLATE/other.yaml @@ -89,6 +89,7 @@ body: - extension/headerssetter - extension/healthcheck - extension/httpforwarder + - extension/httpforwarder - extension/jaegerremotesampling - extension/oauth2clientauth - extension/observer diff --git a/cmd/otelcontribcol/builder-config.yaml b/cmd/otelcontribcol/builder-config.yaml index 8e74fb2dba62d..796546126f4fc 100644 --- a/cmd/otelcontribcol/builder-config.yaml +++ b/cmd/otelcontribcol/builder-config.yaml @@ -14,7 +14,7 @@ extensions: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/bearertokenauthextension v0.94.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension v0.94.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.94.0 - - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarder v0.94.0 + - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension v0.94.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/jaegerremotesampling v0.94.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/oauth2clientauthextension v0.94.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/ecsobserver v0.94.0 @@ -379,7 +379,7 @@ replaces: - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/expvarreceiver => ../../receiver/expvarreceiver - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/apachereceiver => ../../receiver/apachereceiver - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/apachesparkreceiver => ../../receiver/apachesparkreceiver - - github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarder => ../../extension/httpforwarder + - github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension => ../../extension/httpforwarderextension - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/elasticsearchexporter => ../../exporter/elasticsearchexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/awscloudwatchlogsexporter => ../../exporter/awscloudwatchlogsexporter - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googlecloudspannerreceiver => ../../receiver/googlecloudspannerreceiver diff --git a/cmd/otelcontribcol/components.go b/cmd/otelcontribcol/components.go index b5049ad1c8079..705ff37b967b8 100644 --- a/cmd/otelcontribcol/components.go +++ b/cmd/otelcontribcol/components.go @@ -80,7 +80,7 @@ import ( zipkinencodingextension "github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/zipkinencodingextension" headerssetterextension "github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension" healthcheckextension "github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension" - httpforwarder "github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarder" + httpforwarderextension "github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension" jaegerremotesampling "github.com/open-telemetry/opentelemetry-collector-contrib/extension/jaegerremotesampling" oauth2clientauthextension "github.com/open-telemetry/opentelemetry-collector-contrib/extension/oauth2clientauthextension" dockerobserver "github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/dockerobserver" @@ -218,7 +218,7 @@ func components() (otelcol.Factories, error) { bearertokenauthextension.NewFactory(), headerssetterextension.NewFactory(), healthcheckextension.NewFactory(), - httpforwarder.NewFactory(), + httpforwarderextension.NewFactory(), jaegerremotesampling.NewFactory(), oauth2clientauthextension.NewFactory(), ecsobserver.NewFactory(), diff --git a/cmd/otelcontribcol/extensions_test.go b/cmd/otelcontribcol/extensions_test.go index da336d91292b0..fc943100b82f4 100644 --- a/cmd/otelcontribcol/extensions_test.go +++ b/cmd/otelcontribcol/extensions_test.go @@ -25,7 +25,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/extension/bearertokenauthextension" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension" - "github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarder" + "github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/jaegerremotesampling" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/oauth2clientauthextension" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/ecstaskobserver" @@ -149,7 +149,7 @@ func TestDefaultExtensions(t *testing.T) { { extension: "http_forwarder", getConfigFn: func() component.Config { - cfg := extFactories["http_forwarder"].CreateDefaultConfig().(*httpforwarder.Config) + cfg := extFactories["http_forwarder"].CreateDefaultConfig().(*httpforwarderextension.Config) cfg.Egress.Endpoint = "http://" + endpoint cfg.Ingress.Endpoint = testutil.GetAvailableLocalAddress(t) return cfg diff --git a/cmd/otelcontribcol/go.mod b/cmd/otelcontribcol/go.mod index c9578fe10b32f..6f62dcaa9478d 100644 --- a/cmd/otelcontribcol/go.mod +++ b/cmd/otelcontribcol/go.mod @@ -68,7 +68,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/zipkinencodingextension v0.94.0 github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension v0.94.0 github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.94.0 - github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarder v0.94.0 + github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension v0.94.0 github.com/open-telemetry/opentelemetry-collector-contrib/extension/jaegerremotesampling v0.94.0 github.com/open-telemetry/opentelemetry-collector-contrib/extension/oauth2clientauthextension v0.94.0 github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/dockerobserver v0.94.0 @@ -1059,7 +1059,7 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/apach replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/apachesparkreceiver => ../../receiver/apachesparkreceiver -replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarder => ../../extension/httpforwarder +replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension => ../../extension/httpforwarderextension replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/elasticsearchexporter => ../../exporter/elasticsearchexporter diff --git a/extension/httpforwarder/README.md b/extension/httpforwarder/README.md index 16960febdc812..fa96b07790d15 100644 --- a/extension/httpforwarder/README.md +++ b/extension/httpforwarder/README.md @@ -1,13 +1,16 @@ # HTTP Forwarder Extension + +**This extension is deprecated. Please use [httpforwarderextension](../httpforwarderextension) instead.** + | Status | | | ------------- |-----------| -| Stability | [beta] | +| Stability | [deprecated] | | Distributions | [contrib], [splunk], [sumo] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aextension%2Fhttpforwarder%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aextension%2Fhttpforwarder) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aextension%2Fhttpforwarder%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aextension%2Fhttpforwarder) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@atoulme](https://www.github.com/atoulme), [@rmfitzpatrick](https://www.github.com/rmfitzpatrick) | -[beta]: https://github.com/open-telemetry/opentelemetry-collector#beta +[deprecated]: https://github.com/open-telemetry/opentelemetry-collector#deprecated [contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib [splunk]: https://github.com/signalfx/splunk-otel-collector [sumo]: https://github.com/SumoLogic/sumologic-otel-collector diff --git a/extension/httpforwarder/doc.go b/extension/httpforwarder/doc.go index bbef5feebb63c..8eb8a22efc4e0 100644 --- a/extension/httpforwarder/doc.go +++ b/extension/httpforwarder/doc.go @@ -4,4 +4,5 @@ //go:generate mdatagen metadata.yaml // Package httpforwarder accepts HTTP requests, optionally adds headers to them and forwards them. +// Deprecated: use httpforwarderextension instead package httpforwarder // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarder" diff --git a/extension/httpforwarder/go.mod b/extension/httpforwarder/go.mod index e3c7c941d484f..f62668a634c6c 100644 --- a/extension/httpforwarder/go.mod +++ b/extension/httpforwarder/go.mod @@ -1,3 +1,4 @@ +// Deprecated: use httpforwarderextension instead module github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarder go 1.21 diff --git a/extension/httpforwarder/internal/metadata/generated_status.go b/extension/httpforwarder/internal/metadata/generated_status.go index 21c69ce627d3d..1b40a9c329810 100644 --- a/extension/httpforwarder/internal/metadata/generated_status.go +++ b/extension/httpforwarder/internal/metadata/generated_status.go @@ -13,7 +13,7 @@ var ( ) const ( - ExtensionStability = component.StabilityLevelBeta + ExtensionStability = component.StabilityLevelDeprecated ) func Meter(settings component.TelemetrySettings) metric.Meter { diff --git a/extension/httpforwarder/metadata.yaml b/extension/httpforwarder/metadata.yaml index 0b8eebc2cbbe7..8c8a5712b9209 100644 --- a/extension/httpforwarder/metadata.yaml +++ b/extension/httpforwarder/metadata.yaml @@ -3,7 +3,7 @@ type: http_forwarder status: class: extension stability: - beta: [extension] + deprecated: [extension] distributions: [contrib, splunk, sumo] codeowners: active: [atoulme, rmfitzpatrick] diff --git a/extension/httpforwarderextension/Makefile b/extension/httpforwarderextension/Makefile new file mode 100644 index 0000000000000..c1496226e5905 --- /dev/null +++ b/extension/httpforwarderextension/Makefile @@ -0,0 +1 @@ +include ../../Makefile.Common \ No newline at end of file diff --git a/extension/httpforwarderextension/README.md b/extension/httpforwarderextension/README.md new file mode 100644 index 0000000000000..bde8f0f080db9 --- /dev/null +++ b/extension/httpforwarderextension/README.md @@ -0,0 +1,45 @@ +# HTTP Forwarder Extension + +| Status | | +| ------------- |-----------| +| Stability | [beta] | +| Distributions | [] | +| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aextension%2Fhttpforwarder%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aextension%2Fhttpforwarder) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aextension%2Fhttpforwarder%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aextension%2Fhttpforwarder) | +| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@atoulme](https://www.github.com/atoulme), [@rmfitzpatrick](https://www.github.com/rmfitzpatrick) | + +[beta]: https://github.com/open-telemetry/opentelemetry-collector#beta + + +This extension accepts HTTP requests, optionally adds headers to them and forwards them. +The RequestURIs of the original requests are preserved by the extension. + +## Configuration + +The following settings are required: + +- `egress`: HTTP config settings to use for forwarding requests. + - `endpoint` (no default): The target to which requests should be forwarded to. + +The following settings can be optionally configured: + +- `ingress`: HTTP config settings for HTTP server listening to requests. + - `endpoint` (default = `0.0.0.0:6060`): The host to which requests should be forwarded to. +- `egress`: HTTP config settings to use for forwarding requests. + - `headers` (default = `nil`): Additional headers to be added to all requests passing through the extension. + - `timeout` (default = `10s`): How long to wait for each request to complete. + +### Example + +```yaml + http_forwarder: + ingress: + endpoint: localhost:7070 + egress: + endpoint: http://target/ + headers: + otel_http_forwarder: dev + timeout: 5s +``` + +The full list of settings exposed for this exporter are documented [here](config.go) +with detailed sample configurations [here](testdata/config.yaml). diff --git a/extension/httpforwarderextension/config.go b/extension/httpforwarderextension/config.go new file mode 100644 index 0000000000000..96d5b3f0a1551 --- /dev/null +++ b/extension/httpforwarderextension/config.go @@ -0,0 +1,18 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package httpforwarderextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension" + +import ( + "go.opentelemetry.io/collector/config/confighttp" +) + +// Config defines configuration for http forwarder extension. +type Config struct { + + // Ingress holds config settings for HTTP server listening for requests. + Ingress confighttp.ServerConfig `mapstructure:"ingress"` + + // Egress holds config settings to use for forwarded requests. + Egress confighttp.ClientConfig `mapstructure:"egress"` +} diff --git a/extension/httpforwarderextension/config_test.go b/extension/httpforwarderextension/config_test.go new file mode 100644 index 0000000000000..9837e27f84bcb --- /dev/null +++ b/extension/httpforwarderextension/config_test.go @@ -0,0 +1,65 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package httpforwarderextension + +import ( + "path/filepath" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/config/configopaque" + "go.opentelemetry.io/collector/confmap/confmaptest" + + "github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension/internal/metadata" +) + +func TestLoadConfig(t *testing.T) { + t.Parallel() + maxIdleConns := 42 + idleConnTimeout := 80 * time.Second + + tests := []struct { + id component.ID + expected component.Config + }{ + { + id: component.NewID(metadata.Type), + expected: NewFactory().CreateDefaultConfig(), + }, + { + id: component.NewIDWithName(metadata.Type, "1"), + expected: &Config{ + Ingress: confighttp.ServerConfig{ + Endpoint: "http://localhost:7070", + }, + Egress: confighttp.ClientConfig{ + Endpoint: "http://target/", + Headers: map[string]configopaque.String{ + "otel_http_forwarder": "dev", + }, + MaxIdleConns: &maxIdleConns, + IdleConnTimeout: &idleConnTimeout, + Timeout: 5 * time.Second, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.id.String(), func(t *testing.T) { + cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) + require.NoError(t, err) + factory := NewFactory() + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub(tt.id.String()) + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + assert.NoError(t, component.ValidateConfig(cfg)) + assert.Equal(t, tt.expected, cfg) + }) + } +} diff --git a/extension/httpforwarderextension/doc.go b/extension/httpforwarderextension/doc.go new file mode 100644 index 0000000000000..0e6f5dcb5d864 --- /dev/null +++ b/extension/httpforwarderextension/doc.go @@ -0,0 +1,7 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +//go:generate mdatagen metadata.yaml + +// Package httpforwarderextension accepts HTTP requests, optionally adds headers to them and forwards them. +package httpforwarderextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension" diff --git a/extension/httpforwarderextension/extension.go b/extension/httpforwarderextension/extension.go new file mode 100644 index 0000000000000..82250ba564871 --- /dev/null +++ b/extension/httpforwarderextension/extension.go @@ -0,0 +1,130 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package httpforwarderextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension" + +import ( + "context" + "errors" + "fmt" + "io" + "net/http" + "net/url" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/extension" + "go.uber.org/zap" +) + +type httpForwarder struct { + forwardTo *url.URL + httpClient *http.Client + server *http.Server + settings component.TelemetrySettings + config *Config +} + +var _ extension.Extension = (*httpForwarder)(nil) + +func (h *httpForwarder) Start(_ context.Context, host component.Host) error { + listener, err := h.config.Ingress.ToListener() + if err != nil { + return fmt.Errorf("failed to bind to address %s: %w", h.config.Ingress.Endpoint, err) + } + + httpClient, err := h.config.Egress.ToClient(host, h.settings) + if err != nil { + return fmt.Errorf("failed to create HTTP Client: %w", err) + } + h.httpClient = httpClient + + handler := http.NewServeMux() + handler.HandleFunc("/", h.forwardRequest) + + h.server, err = h.config.Ingress.ToServer(host, h.settings, handler) + if err != nil { + return fmt.Errorf("failed to create HTTP Client: %w", err) + } + + go func() { + if errHTTP := h.server.Serve(listener); !errors.Is(errHTTP, http.ErrServerClosed) && errHTTP != nil { + h.settings.ReportStatus(component.NewFatalErrorEvent(errHTTP)) + } + }() + + return nil +} + +func (h *httpForwarder) Shutdown(_ context.Context) error { + if h.server == nil { + return nil + } + return h.server.Close() +} + +func (h *httpForwarder) forwardRequest(writer http.ResponseWriter, request *http.Request) { + forwarderRequest := request.Clone(request.Context()) + forwarderRequest.URL.Host = h.forwardTo.Host + forwarderRequest.URL.Scheme = h.forwardTo.Scheme + forwarderRequest.Host = h.forwardTo.Host + // Clear RequestURI to avoid getting "http: Request.RequestURI can't be set in client requests" error. + forwarderRequest.RequestURI = "" + + // Add additional headers. + for k, v := range h.config.Egress.Headers { + forwarderRequest.Header.Add(k, string(v)) + } + + // Add "Via" header for tracking purposes on both the outgoing requests and responses. + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Via. + addViaHeader(forwarderRequest.Header, request.Proto, request.Host) + + response, err := h.httpClient.Do(forwarderRequest) + if err != nil { + http.Error(writer, err.Error(), http.StatusBadGateway) + } + + if response == nil { + return + } + defer response.Body.Close() + + // Copy over response from the final destination. + for k := range response.Header { + writer.Header().Set(k, response.Header.Get(k)) + } + addViaHeader(writer.Header(), response.Proto, request.Host) + + writer.WriteHeader(response.StatusCode) + written, err := io.Copy(writer, response.Body) + if err != nil { + h.settings.Logger.Warn("Error writing HTTP response message", zap.Error(err)) + } + + if response.ContentLength != written { + h.settings.Logger.Warn("Response from target not fully copied, body might be corrupted") + } +} + +func addViaHeader(header http.Header, protocol string, host string) { + header.Add("Via", fmt.Sprintf("%s %s", protocol, host)) +} + +func newHTTPForwarder(config *Config, settings component.TelemetrySettings) (extension.Extension, error) { + if config.Egress.Endpoint == "" { + return nil, errors.New("'egress.endpoint' config option cannot be empty") + } + + var url, err = url.Parse(config.Egress.Endpoint) + if err != nil { + return nil, fmt.Errorf("enter a valid URL for 'egress.endpoint': %w", err) + } + + h := &httpForwarder{ + config: config, + forwardTo: url, + settings: settings, + } + + return h, nil +} diff --git a/extension/httpforwarderextension/extension_test.go b/extension/httpforwarderextension/extension_test.go new file mode 100644 index 0000000000000..352fe7b331dd1 --- /dev/null +++ b/extension/httpforwarderextension/extension_test.go @@ -0,0 +1,272 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package httpforwarderextension + +import ( + "context" + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/url" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/config/configopaque" + "go.opentelemetry.io/collector/config/configtls" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/testutil" +) + +type clientRequestArgs struct { + method string + url string + headers map[string]string + body string +} + +func TestExtension(t *testing.T) { + listenAt := testutil.GetAvailableLocalAddress(t) + tests := []struct { + name string + config *Config + expectedbackendStatusCode int + expectedBackendResponseBody []byte + expectedHeaders map[string]configopaque.String + httpErrorFromBackend bool + requestErrorAtForwarder bool + clientRequestArgs clientRequestArgs + startUpError bool + startUpErrorMessage string + }{ + { + name: "No additional headers", + config: &Config{ + Ingress: confighttp.ServerConfig{ + Endpoint: listenAt, + }, + }, + expectedbackendStatusCode: http.StatusAccepted, + expectedBackendResponseBody: []byte("hello world"), + expectedHeaders: map[string]configopaque.String{ + "header": "value", + }, + clientRequestArgs: clientRequestArgs{ + method: "GET", + url: fmt.Sprintf("http://%s/api/dosomething", listenAt), + headers: map[string]string{ + "client_header": "val1", + }, + body: "client_body", + }, + }, + { + name: "With additional headers", + config: &Config{ + Ingress: confighttp.ServerConfig{ + Endpoint: listenAt, + }, + Egress: confighttp.ClientConfig{ + Headers: map[string]configopaque.String{ + "key": "value", + }, + }, + }, + expectedbackendStatusCode: http.StatusAccepted, + expectedBackendResponseBody: []byte("hello world with additional headers"), + expectedHeaders: map[string]configopaque.String{ + "header": "value", + }, + clientRequestArgs: clientRequestArgs{ + method: "PUT", + url: fmt.Sprintf("http://%s/api/dosomething", listenAt), + }, + }, + { + name: "Error code from backend", + config: &Config{ + Ingress: confighttp.ServerConfig{ + Endpoint: listenAt, + }, + Egress: confighttp.ClientConfig{ + Headers: map[string]configopaque.String{ + "key": "value", + }, + }, + }, + expectedbackendStatusCode: http.StatusInternalServerError, + expectedBackendResponseBody: []byte("\n"), + httpErrorFromBackend: true, + clientRequestArgs: clientRequestArgs{ + method: "PATCH", + url: fmt.Sprintf("http://%s/api/dosomething", listenAt), + }, + }, + { + name: "Error making request at forwarder", + config: &Config{ + Ingress: confighttp.ServerConfig{ + Endpoint: listenAt, + }, + Egress: confighttp.ClientConfig{ + Headers: map[string]configopaque.String{ + "key": "value", + }, + }, + }, + expectedbackendStatusCode: http.StatusBadGateway, + expectedBackendResponseBody: []byte("\n"), + requestErrorAtForwarder: true, + clientRequestArgs: clientRequestArgs{ + method: "GET", + url: fmt.Sprintf("http://%s/api/dosomething", listenAt), + }, + }, + { + name: "Invalid config - HTTP Client creation fails", + config: &Config{ + Egress: confighttp.ClientConfig{ + Endpoint: "localhost:9090", + TLSSetting: configtls.TLSClientSetting{ + TLSSetting: configtls.TLSSetting{ + CAFile: "/non/existent", + }, + }, + }, + }, + startUpError: true, + startUpErrorMessage: "failed to create HTTP Client: ", + }, + { + name: "Error on Startup", + config: &Config{ + Ingress: confighttp.ServerConfig{ + Endpoint: "invalid", // to mock error setting up listener. + }, + }, + startUpError: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if test.httpErrorFromBackend { + http.Error(w, "", http.StatusInternalServerError) + return + } + + assert.Equal(t, getParsedURL(t, test.clientRequestArgs.url).RequestURI(), r.RequestURI) + assert.Equal(t, test.clientRequestArgs.method, r.Method) + assert.Equal(t, test.clientRequestArgs.body, string(readBody(r.Body))) + + // Assert headers originating from client. + for k, v := range test.clientRequestArgs.headers { + got := r.Header.Get(k) + assert.Equal(t, v, got) + } + + // Assert additional headers added by forwarder. + for k, v := range test.config.Egress.Headers { + got := r.Header.Get(k) + assert.Equal(t, string(v), got) + } + + // Assert Via header added by the forwarder on all requests. + assert.Equal(t, fmt.Sprintf("%s %s", r.Proto, listenAt), r.Header.Get("Via")) + + for k, v := range test.expectedHeaders { + w.Header().Set(k, string(v)) + } + w.WriteHeader(test.expectedbackendStatusCode) + _, err := w.Write(test.expectedBackendResponseBody) + assert.NoError(t, err) + })) + defer backend.Close() + + // Fill in final destination URL. + backendURL, _ := url.Parse(backend.URL) + test.config.Egress.Endpoint = backendURL.String() + + // Setup forwarder with wrong final address to mock failures. + if test.requestErrorAtForwarder { + test.config.Egress.Endpoint = "http://" + testutil.GetAvailableLocalAddress(t) + } + + hf, err := newHTTPForwarder(test.config, componenttest.NewNopTelemetrySettings()) + require.NoError(t, err) + + ctx := context.Background() + if test.startUpError { + err = hf.Start(ctx, componenttest.NewNopHost()) + if test.startUpErrorMessage != "" { + require.True(t, strings.Contains(err.Error(), test.startUpErrorMessage)) + } + require.Error(t, err) + + return + } + require.NoError(t, hf.Start(ctx, componenttest.NewNopHost())) + + // Mock a client trying to talk to backend using the forwarder. + httpClient := http.Client{} + + // Assert responses received by client. + response, err := httpClient.Do(httpRequest(t, test.clientRequestArgs)) + require.NoError(t, err) + require.NotNil(t, response) + defer response.Body.Close() + + assert.Equal(t, test.expectedbackendStatusCode, response.StatusCode) + if !test.requestErrorAtForwarder { + assert.Equal(t, string(test.expectedBackendResponseBody), string(readBody(response.Body))) + assert.Equal(t, fmt.Sprintf("%s %s", response.Proto, listenAt), response.Header.Get("Via")) + } + + for k := range response.Header { + got := response.Header.Get(k) + header := strings.ToLower(k) + if want, ok := test.expectedHeaders[header]; ok { + assert.Equal(t, want, configopaque.String(got)) + continue + } + + if k == "Content-Length" || k == "Content-Type" || k == "X-Content-Type-Options" || k == "Date" || k == "Via" { + // Content-Length, Content-Type, X-Content-Type-Options and Date are certain headers added by default. + // Assertion for Via is done above. + continue + } + t.Error("unexpected header found in response: ", k) + } + + require.NoError(t, hf.Shutdown(ctx)) + }) + } +} + +func httpRequest(t *testing.T, args clientRequestArgs) *http.Request { + r, err := http.NewRequest(args.method, args.url, io.NopCloser(strings.NewReader(args.body))) + require.NoError(t, err) + + for k, v := range args.headers { + r.Header.Set(k, v) + } + + return r +} + +func readBody(body io.ReadCloser) []byte { + out, _ := io.ReadAll(body) + return out +} + +func getParsedURL(t *testing.T, rawURL string) *url.URL { + var url, err = url.Parse(rawURL) + require.NoError(t, err) + return url +} diff --git a/extension/httpforwarderextension/factory.go b/extension/httpforwarderextension/factory.go new file mode 100644 index 0000000000000..57ce1eb3a576a --- /dev/null +++ b/extension/httpforwarderextension/factory.go @@ -0,0 +1,48 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package httpforwarderextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension" + +import ( + "context" + "time" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/extension" + + "github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension/internal/metadata" +) + +const ( + // Default endpoints to bind to. + defaultEndpoint = ":6060" +) + +// NewFactory creates a factory for HostObserver extension. +func NewFactory() extension.Factory { + return extension.NewFactory( + metadata.Type, + createDefaultConfig, + createExtension, + metadata.ExtensionStability) +} + +func createDefaultConfig() component.Config { + httpClientSettings := confighttp.NewDefaultClientConfig() + httpClientSettings.Timeout = 10 * time.Second + return &Config{ + Ingress: confighttp.ServerConfig{ + Endpoint: defaultEndpoint, + }, + Egress: httpClientSettings, + } +} + +func createExtension( + _ context.Context, + params extension.CreateSettings, + cfg component.Config, +) (extension.Extension, error) { + return newHTTPForwarder(cfg.(*Config), params.TelemetrySettings) +} diff --git a/extension/httpforwarderextension/factory_test.go b/extension/httpforwarderextension/factory_test.go new file mode 100644 index 0000000000000..3eef3c3330f26 --- /dev/null +++ b/extension/httpforwarderextension/factory_test.go @@ -0,0 +1,73 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package httpforwarderextension + +import ( + "context" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/extension/extensiontest" +) + +func TestFactory(t *testing.T) { + f := NewFactory() + expectType := component.MustNewType("http_forwarder") + require.Equal(t, expectType, f.Type()) + + cfg := f.CreateDefaultConfig().(*Config) + require.Equal(t, ":6060", cfg.Ingress.Endpoint) + require.Equal(t, 10*time.Second, cfg.Egress.Timeout) + + tests := []struct { + name string + config *Config + wantErr bool + wantErrMessage string + }{ + { + name: "Default config", + config: cfg, + wantErr: true, + wantErrMessage: "'egress.endpoint' config option cannot be empty", + }, + { + name: "Invalid config", + config: &Config{Egress: confighttp.ClientConfig{Endpoint: "123.456.7.89:9090"}}, + wantErr: true, + wantErrMessage: "enter a valid URL for 'egress.endpoint': parse \"123.456.7.89:9090\": first path segment in URL cannot", + }, + { + name: "Valid config", + config: &Config{Egress: confighttp.ClientConfig{Endpoint: "localhost:9090"}}, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + e, err := f.CreateExtension( + context.Background(), + extensiontest.NewNopCreateSettings(), + test.config, + ) + if test.wantErr { + if test.wantErrMessage != "" { + require.True(t, strings.Contains(err.Error(), test.wantErrMessage)) + } + require.Error(t, err) + require.Nil(t, e) + } else { + require.NoError(t, err) + require.NotNil(t, e) + ctx := context.Background() + require.NoError(t, e.Start(ctx, componenttest.NewNopHost())) + require.NoError(t, e.Shutdown(ctx)) + } + }) + } +} diff --git a/extension/httpforwarderextension/go.mod b/extension/httpforwarderextension/go.mod new file mode 100644 index 0000000000000..5e18865f91849 --- /dev/null +++ b/extension/httpforwarderextension/go.mod @@ -0,0 +1,69 @@ +module github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension + +go 1.21 + +require ( + github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.93.0 + github.com/stretchr/testify v1.8.4 + go.opentelemetry.io/collector/component v0.94.1 + go.opentelemetry.io/collector/config/confighttp v0.94.1 + go.opentelemetry.io/collector/config/configopaque v0.94.1 + go.opentelemetry.io/collector/config/configtls v0.94.1 + go.opentelemetry.io/collector/confmap v0.94.1 + go.opentelemetry.io/collector/extension v0.94.1 + go.opentelemetry.io/otel/metric v1.23.0 + go.opentelemetry.io/otel/trace v1.23.0 + go.uber.org/goleak v1.3.0 + go.uber.org/zap v1.26.0 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/klauspost/compress v1.17.5 // indirect + github.com/knadh/koanf/maps v0.1.1 // indirect + github.com/knadh/koanf/providers/confmap v0.1.0 // indirect + github.com/knadh/koanf/v2 v2.0.2 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.46.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/rs/cors v1.10.1 // indirect + go.opentelemetry.io/collector v0.94.1 // indirect + go.opentelemetry.io/collector/config/configauth v0.94.1 // indirect + go.opentelemetry.io/collector/config/configcompression v0.94.1 // indirect + go.opentelemetry.io/collector/config/configtelemetry v0.94.1 // indirect + go.opentelemetry.io/collector/config/internal v0.94.1 // indirect + go.opentelemetry.io/collector/extension/auth v0.94.1 // indirect + go.opentelemetry.io/collector/featuregate v1.1.0 // indirect + go.opentelemetry.io/collector/pdata v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect + go.opentelemetry.io/otel v1.23.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.45.1 // indirect + go.opentelemetry.io/otel/sdk v1.23.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.23.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect + google.golang.org/grpc v1.61.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/common => ../../internal/common diff --git a/extension/httpforwarderextension/go.sum b/extension/httpforwarderextension/go.sum new file mode 100644 index 0000000000000..52a9055983cb5 --- /dev/null +++ b/extension/httpforwarderextension/go.sum @@ -0,0 +1,167 @@ +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/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/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c= +github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +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.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +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/klauspost/compress v1.17.5 h1:d4vBd+7CHydUqpFBgUEKkSdtSugf9YFmSkvUYPquI5E= +github.com/klauspost/compress v1.17.5/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= +github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= +github.com/knadh/koanf/providers/confmap v0.1.0 h1:gOkxhHkemwG4LezxxN8DMOFopOPghxRVp7JbIvdvqzU= +github.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC7+fyHFdQkd697K4MdLnIU= +github.com/knadh/koanf/v2 v2.0.2 h1:sEZzPW2rVWSahcYILNq/syJdEyRafZIG0l9aWwL86HA= +github.com/knadh/koanf/v2 v2.0.2/go.mod h1:HN9uZ+qFAejH1e4G41gnoffIanINWQuONLXiV7kir6k= +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/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE= +github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +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/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y= +github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= +github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +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= +go.opentelemetry.io/collector v0.94.1 h1:bGHW5NKmh34oMflMEyNCHpes6vtiQNXpgea4GiscAOs= +go.opentelemetry.io/collector v0.94.1/go.mod h1:5ACZXRo6O23gBkRrHSxYs1sLaP4pZ8w+flZNE7pvoNg= +go.opentelemetry.io/collector/component v0.94.1 h1:j4peKsWb+QVBKPs2RJeIj5EoQW7yp2ZVGrd8Bu9HU9M= +go.opentelemetry.io/collector/component v0.94.1/go.mod h1:vg+kAH81C3YS0SPzUXkSFWLPC1WH7zx70dAtUWWIHcE= +go.opentelemetry.io/collector/config/configauth v0.94.1 h1:VwmxDZRZVihvfwlP+BIM4DHVYqwx3oFUl6Fat1u3UnM= +go.opentelemetry.io/collector/config/configauth v0.94.1/go.mod h1:AgftrmblBdbNE6T3P7EkCHdO/Ibh/AvPwCy3OR0ZftA= +go.opentelemetry.io/collector/config/configcompression v0.94.1 h1:uZ+uh+Ods+FTIaXmf2T9Euq0srCHa7ChPApuwP/Dd98= +go.opentelemetry.io/collector/config/configcompression v0.94.1/go.mod h1:fA36AZC/Qcyl+HvMnvFZuV/iUWGQJrchimmk+qYWuMM= +go.opentelemetry.io/collector/config/confighttp v0.94.1 h1:2G/bOzREhgIEoKGLE3tOeuiAjveB4o24n/oaIm3E5Rs= +go.opentelemetry.io/collector/config/confighttp v0.94.1/go.mod h1:zJopIf0pWZtczVf6k7FECHkH4QVZJ75I1Lq1PmWZfNQ= +go.opentelemetry.io/collector/config/configopaque v0.94.1 h1:Jq0pF0DPaFnBNKrBN9V2AV0Yk5T+YTm9pYhmG/ipZJs= +go.opentelemetry.io/collector/config/configopaque v0.94.1/go.mod h1:3T6t2PN2/Tl1122CYO+isudwCbSuElqXG/yqRh+SX8U= +go.opentelemetry.io/collector/config/configtelemetry v0.94.1 h1:ztYpBEBlvhcoxMiDKNmQ2SS+A41JZ4M19GfcxjCo8Zs= +go.opentelemetry.io/collector/config/configtelemetry v0.94.1/go.mod h1:2XLhyR/GVpWeZ2K044vCmrvH/d4Ewt0aD/y46avZyMU= +go.opentelemetry.io/collector/config/configtls v0.94.1 h1:potTWvF7ssMva7MlrrbXBB4UhXYh9Fg8TZp1noLEPpo= +go.opentelemetry.io/collector/config/configtls v0.94.1/go.mod h1:8/27C8CKCyZTb9T1Y9972BEDr7iPFc7u3H1/GSC4lYU= +go.opentelemetry.io/collector/config/internal v0.94.1 h1:qmGX6ZGYmGOiDa5kDBCmCEnd+qZO3uOwzzcQxtQRnvs= +go.opentelemetry.io/collector/config/internal v0.94.1/go.mod h1:Dj6qq+HPOIUbd2EsQgIsSA5uDiXOLc4DI6nZ3NcDGkg= +go.opentelemetry.io/collector/confmap v0.94.1 h1:O69bkeyR1YPAFz+jMd45aDZc1DtYnwb3Skgr2yALPqQ= +go.opentelemetry.io/collector/confmap v0.94.1/go.mod h1:pCT5UtcHaHVJ5BIILv1Z2VQyjZzmT9uTdBmC9+Z0AgA= +go.opentelemetry.io/collector/consumer v0.94.1 h1:l/9h5L71xr/d93snQ9fdxgz64C4UuB8mEDxpp456X8o= +go.opentelemetry.io/collector/consumer v0.94.1/go.mod h1:BIPWmw8wES6jlPTPC+acJxLvUzIdOm6uh/p/X85ALsY= +go.opentelemetry.io/collector/extension v0.94.1 h1:f0yyW2lmLg+PI1FjNWJaGcKVQV6TRgLqqbMA/4S5dA4= +go.opentelemetry.io/collector/extension v0.94.1/go.mod h1:fxQXkLkFcea3uJ3hlImBs5kQ/pWjeDIC2OylnDYIA4g= +go.opentelemetry.io/collector/extension/auth v0.94.1 h1:r9YPcI5KpSzMS4/JEWfRJGMQTnToWb+/tT/WZxXRIJk= +go.opentelemetry.io/collector/extension/auth v0.94.1/go.mod h1:r/C9S2Y+s+9Ter7VnGFuo9QOMIWOPuTBp0I6lQInWgg= +go.opentelemetry.io/collector/featuregate v1.1.0 h1:W+/FKvRxHMFC6MuTTEgrHINCf1vFBvLH7stSOEar6zU= +go.opentelemetry.io/collector/featuregate v1.1.0/go.mod h1:QQXjP4etmJQhkQ20j4P/rapWuItYxoFozg/iIwuKnYg= +go.opentelemetry.io/collector/pdata v1.1.0 h1:cE6Al1rQieUjMHro6p6cKwcu3sjHXGG59BZ3kRVUvsM= +go.opentelemetry.io/collector/pdata v1.1.0/go.mod h1:IDkDj+B4Fp4wWOclBELN97zcb98HugJ8Q2gA4ZFsN8Q= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= +go.opentelemetry.io/otel v1.23.0 h1:Df0pqjqExIywbMCMTxkAwzjLZtRf+bBKLbUcpxO2C9E= +go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0= +go.opentelemetry.io/otel/exporters/prometheus v0.45.1 h1:R/bW3afad6q6VGU+MFYpnEdo0stEARMCdhWu6+JI6aI= +go.opentelemetry.io/otel/exporters/prometheus v0.45.1/go.mod h1:wnHAfKRav5Dfp4iZhyWZ7SzQfT+rDZpEpYG7To+qJ1k= +go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo= +go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= +go.opentelemetry.io/otel/sdk v1.23.0 h1:0KM9Zl2esnl+WSukEmlaAEjVY5HDZANOHferLq36BPc= +go.opentelemetry.io/otel/sdk v1.23.0/go.mod h1:wUscup7byToqyKJSilEtMf34FgdCAsFpFOjXnAwFfO0= +go.opentelemetry.io/otel/sdk/metric v1.23.0 h1:u81lMvmK6GMgN4Fty7K7S6cSKOZhMKJMK2TB+KaTs0I= +go.opentelemetry.io/otel/sdk/metric v1.23.0/go.mod h1:2LUOToN/FdX6wtfpHybOnCZjoZ6ViYajJYMiJ1LKDtQ= +go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI= +go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= +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.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +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.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +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.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +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-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= +google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +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.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +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/httpforwarderextension/internal/metadata/generated_status.go b/extension/httpforwarderextension/internal/metadata/generated_status.go new file mode 100644 index 0000000000000..973a3a3135ed4 --- /dev/null +++ b/extension/httpforwarderextension/internal/metadata/generated_status.go @@ -0,0 +1,25 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" +) + +var ( + Type = component.MustNewType("http_forwarder") +) + +const ( + ExtensionStability = component.StabilityLevelBeta +) + +func Meter(settings component.TelemetrySettings) metric.Meter { + return settings.MeterProvider.Meter("otelcol/httpforwarder") +} + +func Tracer(settings component.TelemetrySettings) trace.Tracer { + return settings.TracerProvider.Tracer("otelcol/httpforwarder") +} diff --git a/extension/httpforwarderextension/metadata.yaml b/extension/httpforwarderextension/metadata.yaml new file mode 100644 index 0000000000000..d41a2ea7e4d9a --- /dev/null +++ b/extension/httpforwarderextension/metadata.yaml @@ -0,0 +1,9 @@ +type: http_forwarder + +status: + class: extension + stability: + beta: [extension] + distributions: [] + codeowners: + active: [atoulme, rmfitzpatrick] diff --git a/extension/httpforwarderextension/package_test.go b/extension/httpforwarderextension/package_test.go new file mode 100644 index 0000000000000..0a8c3ea182f16 --- /dev/null +++ b/extension/httpforwarderextension/package_test.go @@ -0,0 +1,14 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package httpforwarderextension + +import ( + "testing" + + "go.uber.org/goleak" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/extension/httpforwarderextension/testdata/config.yaml b/extension/httpforwarderextension/testdata/config.yaml new file mode 100644 index 0000000000000..2d6e17e95d9ab --- /dev/null +++ b/extension/httpforwarderextension/testdata/config.yaml @@ -0,0 +1,11 @@ +http_forwarder: +http_forwarder/1: + ingress: + endpoint: http://localhost:7070 + egress: + endpoint: http://target/ + headers: + otel_http_forwarder: dev + idle_conn_timeout: 80s + max_idle_conns: 42 + timeout: 5s diff --git a/versions.yaml b/versions.yaml index a04e504211dca..08ed9f9d1aeb6 100644 --- a/versions.yaml +++ b/versions.yaml @@ -83,6 +83,7 @@ module-sets: - github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension - github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension - github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarder + - github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension - github.com/open-telemetry/opentelemetry-collector-contrib/extension/jaegerremotesampling - github.com/open-telemetry/opentelemetry-collector-contrib/extension/oauth2clientauthextension - github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer