Skip to content

Commit

Permalink
otlptracehttp, otlpmetrichttp: Add WithProxy option (#4906)
Browse files Browse the repository at this point in the history
  • Loading branch information
MickaelAlliel authored and q-cheng committed Mar 12, 2024
1 parent 277b2f3 commit daf7fc0
Show file tree
Hide file tree
Showing 19 changed files with 327 additions and 8 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased]

### Added

- Add `WithProxy` option in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4906)
- Add `WithProxy` option in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlptracehttp`. (#4906)

### Changed

- `SpanFromContext` and `SpanContextFromContext` in `go.opentelemetry.io/otel/trace` no longer make a heap allocation when the passed context has no span. (#5049)
Expand Down
14 changes: 14 additions & 0 deletions exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlp
import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"path"
"strings"
Expand Down Expand Up @@ -42,6 +43,10 @@ const (
)

type (
// HTTPTransportProxyFunc is a function that resolves which URL to use as proxy for a given request.
// This type is compatible with `http.Transport.Proxy` and can be used to set a custom proxy function to the OTLP HTTP client.
HTTPTransportProxyFunc func(*http.Request) (*url.URL, error)

SignalConfig struct {
Endpoint string
Insecure bool
Expand All @@ -56,6 +61,8 @@ type (

TemporalitySelector metric.TemporalitySelector
AggregationSelector metric.AggregationSelector

Proxy HTTPTransportProxyFunc
}

Config struct {
Expand Down Expand Up @@ -360,3 +367,10 @@ func WithAggregationSelector(selector metric.AggregationSelector) GenericOption
return cfg
})
}

func WithProxy(pf HTTPTransportProxyFunc) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Metrics.Proxy = pf
return cfg
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ package oconf

import (
"errors"
"net/http"
"net/url"
"testing"
"time"

Expand Down Expand Up @@ -444,6 +446,29 @@ func TestConfigs(t *testing.T) {
assert.Equal(t, metric.AggregationDrop{}, got(undefinedKind))
},
},

// Proxy Tests
{
name: "Test With Proxy",
opts: []GenericOption{
WithProxy(func(r *http.Request) (*url.URL, error) {
return url.Parse("http://proxy.com")
}),
},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
assert.NotNil(t, c.Metrics.Proxy)
proxyURL, err := c.Metrics.Proxy(&http.Request{})
assert.NoError(t, err)
assert.Equal(t, "http://proxy.com", proxyURL.String())
},
},
{
name: "Test Without Proxy",
opts: []GenericOption{},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
assert.Nil(t, c.Metrics.Proxy)
},
},
}

for _, tt := range tests {
Expand Down
15 changes: 11 additions & 4 deletions exporters/otlp/otlpmetric/otlpmetrichttp/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,17 @@ func newClient(cfg oconf.Config) (*client, error) {
Transport: ourTransport,
Timeout: cfg.Metrics.Timeout,
}
if cfg.Metrics.TLSCfg != nil {
transport := ourTransport.Clone()
transport.TLSClientConfig = cfg.Metrics.TLSCfg
httpClient.Transport = transport

if cfg.Metrics.TLSCfg != nil || cfg.Metrics.Proxy != nil {
clonedTransport := ourTransport.Clone()
httpClient.Transport = clonedTransport

if cfg.Metrics.TLSCfg != nil {
clonedTransport.TLSClientConfig = cfg.Metrics.TLSCfg
}
if cfg.Metrics.Proxy != nil {
clonedTransport.Proxy = cfg.Metrics.Proxy
}
}

u := &url.URL{
Expand Down
19 changes: 19 additions & 0 deletions exporters/otlp/otlpmetric/otlpmetrichttp/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -227,4 +228,22 @@ func TestConfig(t *testing.T) {
require.Contains(t, got, key)
assert.Equal(t, got[key], []string{headers[key]})
})

t.Run("WithProxy", func(t *testing.T) {
headerKeySetInProxy := http.CanonicalHeaderKey("X-Using-Proxy")
headerValueSetInProxy := "true"
exp, coll := factoryFunc("", nil, WithProxy(func(r *http.Request) (*url.URL, error) {
r.Header.Set(headerKeySetInProxy, headerValueSetInProxy)
return r.URL, nil
}))
ctx := context.Background()
t.Cleanup(func() { require.NoError(t, coll.Shutdown(ctx)) })
require.NoError(t, exp.Export(ctx, &metricdata.ResourceMetrics{}))
// Ensure everything is flushed.
require.NoError(t, exp.Shutdown(ctx))

got := coll.Headers()
require.Contains(t, got, headerKeySetInProxy)
assert.Equal(t, got[headerKeySetInProxy], []string{headerValueSetInProxy})
})
}
14 changes: 14 additions & 0 deletions exporters/otlp/otlpmetric/otlpmetrichttp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package otlpmetrichttp // import "go.opentelemetry.io/otel/exporters/otlp/otlpme

import (
"crypto/tls"
"net/http"
"net/url"
"time"

"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf"
Expand All @@ -16,6 +18,11 @@ import (
// collector.
type Compression oconf.Compression

// HTTPTransportProxyFunc is a function that resolves which URL to use as proxy for a given request.
// This type is compatible with http.Transport.Proxy and can be used to set a custom proxy function
// to the OTLP HTTP client.
type HTTPTransportProxyFunc func(*http.Request) (*url.URL, error)

const (
// NoCompression tells the driver to send payloads without
// compression.
Expand Down Expand Up @@ -206,3 +213,10 @@ func WithTemporalitySelector(selector metric.TemporalitySelector) Option {
func WithAggregationSelector(selector metric.AggregationSelector) Option {
return wrappedOption{oconf.WithAggregationSelector(selector)}
}

// WithProxy sets the Proxy function the client will use to determine the
// proxy to use for an HTTP request. If this option is not used, the client
// will use [http.ProxyFromEnvironment].
func WithProxy(pf HTTPTransportProxyFunc) Option {
return wrappedOption{oconf.WithProxy(oconf.HTTPTransportProxyFunc(pf))}
}
14 changes: 14 additions & 0 deletions exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlp
import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"path"
"strings"
Expand Down Expand Up @@ -42,6 +43,10 @@ const (
)

type (
// HTTPTransportProxyFunc is a function that resolves which URL to use as proxy for a given request.
// This type is compatible with `http.Transport.Proxy` and can be used to set a custom proxy function to the OTLP HTTP client.
HTTPTransportProxyFunc func(*http.Request) (*url.URL, error)

SignalConfig struct {
Endpoint string
Insecure bool
Expand All @@ -56,6 +61,8 @@ type (

TemporalitySelector metric.TemporalitySelector
AggregationSelector metric.AggregationSelector

Proxy HTTPTransportProxyFunc
}

Config struct {
Expand Down Expand Up @@ -360,3 +367,10 @@ func WithAggregationSelector(selector metric.AggregationSelector) GenericOption
return cfg
})
}

func WithProxy(pf HTTPTransportProxyFunc) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Metrics.Proxy = pf
return cfg
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ package oconf

import (
"errors"
"net/http"
"net/url"
"testing"
"time"

Expand Down Expand Up @@ -444,6 +446,29 @@ func TestConfigs(t *testing.T) {
assert.Equal(t, metric.AggregationDrop{}, got(undefinedKind))
},
},

// Proxy Tests
{
name: "Test With Proxy",
opts: []GenericOption{
WithProxy(func(r *http.Request) (*url.URL, error) {
return url.Parse("http://proxy.com")
}),
},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
assert.NotNil(t, c.Metrics.Proxy)
proxyURL, err := c.Metrics.Proxy(&http.Request{})
assert.NoError(t, err)
assert.Equal(t, "http://proxy.com", proxyURL.String())
},
},
{
name: "Test Without Proxy",
opts: []GenericOption{},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
assert.Nil(t, c.Metrics.Proxy)
},
},
}

for _, tt := range tests {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package otlpconfig // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/
import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"path"
"strings"
Expand All @@ -35,6 +36,10 @@ const (
)

type (
// HTTPTransportProxyFunc is a function that resolves which URL to use as proxy for a given request.
// This type is compatible with `http.Transport.Proxy` and can be used to set a custom proxy function to the OTLP HTTP client.
HTTPTransportProxyFunc func(*http.Request) (*url.URL, error)

SignalConfig struct {
Endpoint string
Insecure bool
Expand All @@ -46,6 +51,8 @@ type (

// gRPC configurations
GRPCCredentials credentials.TransportCredentials

Proxy HTTPTransportProxyFunc
}

Config struct {
Expand Down Expand Up @@ -332,3 +339,10 @@ func WithTimeout(duration time.Duration) GenericOption {
return cfg
})
}

func WithProxy(pf HTTPTransportProxyFunc) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Traces.Proxy = pf
return cfg
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ package otlpconfig

import (
"errors"
"net/http"
"net/url"
"testing"
"time"

Expand Down Expand Up @@ -408,6 +410,29 @@ func TestConfigs(t *testing.T) {
assert.Equal(t, c.Traces.Timeout, 5*time.Second)
},
},

// Proxy Tests
{
name: "Test With Proxy",
opts: []GenericOption{
WithProxy(func(r *http.Request) (*url.URL, error) {
return url.Parse("http://proxy.com")
}),
},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
assert.NotNil(t, c.Traces.Proxy)
proxyURL, err := c.Traces.Proxy(&http.Request{})
assert.NoError(t, err)
assert.Equal(t, "http://proxy.com", proxyURL.String())
},
},
{
name: "Test Without Proxy",
opts: []GenericOption{},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
assert.Nil(t, c.Traces.Proxy)
},
},
}

for _, tt := range tests {
Expand Down
15 changes: 11 additions & 4 deletions exporters/otlp/otlptrace/otlptracehttp/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,17 @@ func NewClient(opts ...Option) otlptrace.Client {
Transport: ourTransport,
Timeout: cfg.Traces.Timeout,
}
if cfg.Traces.TLSCfg != nil {
transport := ourTransport.Clone()
transport.TLSClientConfig = cfg.Traces.TLSCfg
httpClient.Transport = transport

if cfg.Traces.TLSCfg != nil || cfg.Traces.Proxy != nil {
clonedTransport := ourTransport.Clone()
httpClient.Transport = clonedTransport

if cfg.Traces.TLSCfg != nil {
clonedTransport.TLSClientConfig = cfg.Traces.TLSCfg
}
if cfg.Traces.Proxy != nil {
clonedTransport.Proxy = cfg.Traces.Proxy
}
}

stopCh := make(chan struct{})
Expand Down
19 changes: 19 additions & 0 deletions exporters/otlp/otlptrace/otlptracehttp/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -36,6 +37,10 @@ var (
customUserAgentHeader = map[string]string{
"user-agent": "custome-user-agent",
}

customProxyHeader = map[string]string{
"header-added-via-proxy": "proxy-value",
}
)

func TestEndToEnd(t *testing.T) {
Expand Down Expand Up @@ -150,6 +155,20 @@ func TestEndToEnd(t *testing.T) {
ExpectedHeaders: customUserAgentHeader,
},
},
{
name: "with custom proxy",
opts: []otlptracehttp.Option{
otlptracehttp.WithProxy(func(r *http.Request) (*url.URL, error) {
for k, v := range customProxyHeader {
r.Header.Set(k, v)
}
return r.URL, nil
}),
},
mcCfg: mockCollectorConfig{
ExpectedHeaders: customProxyHeader,
},
},
}

for _, tc := range tests {
Expand Down

0 comments on commit daf7fc0

Please sign in to comment.