Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
The package contains semantic conventions from the `v1.31.0` version of the OpenTelemetry Semantic Conventions.
See the [migration documentation](./semconv/v1.31.0/MIGRATION.md) for information on how to upgrade from `go.opentelemetry.io/otel/semconv/v1.30.0`(#6479)
- Add `Recording`, `Scope`, and `Record` types in `go.opentelemetry.io/otel/log/logtest`. (#6507)
- Add `WithHTTPClient` option allowing to set `http.Client` to be used by `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#6688)

### Removed

Expand Down
27 changes: 15 additions & 12 deletions exporters/otlp/otlplog/otlploghttp/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,23 @@ func newNoopClient() *client {

// newHTTPClient creates a new HTTP log client.
func newHTTPClient(cfg config) (*client, error) {
hc := &http.Client{
Transport: ourTransport,
Timeout: cfg.timeout.Value,
}
hc := cfg.httpClient
if hc == nil {
hc = &http.Client{
Transport: ourTransport,
Timeout: cfg.timeout.Value,
}

if cfg.tlsCfg.Value != nil || cfg.proxy.Value != nil {
clonedTransport := ourTransport.Clone()
hc.Transport = clonedTransport
if cfg.tlsCfg.Value != nil || cfg.proxy.Value != nil {
clonedTransport := ourTransport.Clone()
hc.Transport = clonedTransport

if cfg.tlsCfg.Value != nil {
clonedTransport.TLSClientConfig = cfg.tlsCfg.Value
}
if cfg.proxy.Value != nil {
clonedTransport.Proxy = cfg.proxy.Value
if cfg.tlsCfg.Value != nil {
clonedTransport.TLSClientConfig = cfg.tlsCfg.Value
}
if cfg.proxy.Value != nil {
clonedTransport.Proxy = cfg.proxy.Value
}
}
}

Expand Down
22 changes: 22 additions & 0 deletions exporters/otlp/otlplog/otlploghttp/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,28 @@ func TestConfig(t *testing.T) {
assert.Equal(t, []string{headerValueSetInProxy}, got[headerKeySetInProxy])
})

t.Run("WithHTTPClient", func(t *testing.T) {
headerKeySetInProxy := http.CanonicalHeaderKey("X-Using-Proxy")
headerValueSetInProxy := "true"
exp, coll := factoryFunc("", nil, WithHTTPClient(&http.Client{
Transport: &http.Transport{
Proxy: 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, make([]log.Record, 1)))
// Ensure everything is flushed.
require.NoError(t, exp.Shutdown(ctx))

got := coll.Headers()
require.Contains(t, got, headerKeySetInProxy)
assert.Equal(t, []string{headerValueSetInProxy}, got[headerKeySetInProxy])
})

t.Run("non-retryable errors are propagated", func(t *testing.T) {
exporterErr := errors.New("missing required attribute aaaa")
rCh := make(chan exportResult, 1)
Expand Down
18 changes: 18 additions & 0 deletions exporters/otlp/otlplog/otlploghttp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ type config struct {
timeout setting[time.Duration]
proxy setting[HTTPTransportProxyFunc]
retryCfg setting[retry.Config]
httpClient *http.Client
}

func newConfig(options []Option) config {
Expand Down Expand Up @@ -344,6 +345,23 @@ func WithProxy(pf HTTPTransportProxyFunc) Option {
})
}

// WithHTTPClient sets the HTTP client to used by the exporter.
//
// This option will take precedence over [WithProxy], [WithTimeout],
// [WithTLSClientConfig] options as well as OTEL_EXPORTER_OTLP_CERTIFICATE,
// OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE, OTEL_EXPORTER_OTLP_TIMEOUT,
// OTEL_EXPORTER_OTLP_LOGS_TIMEOUT environment variables.
//
// Be aware that passing an HTTP client with transport like
// [go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp.NewTransport] can
// cause the client to be instrumented twice and cause infinite recursion.
func WithHTTPClient(c *http.Client) Option {
return fnOpt(func(cfg config) config {
cfg.httpClient = c
return cfg
})
}

// setting is a configuration setting value.
type setting[T any] struct {
Value T
Expand Down
Loading