Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WithEndpointURL option to OTLP over HTTP exporters #4808

Merged
merged 10 commits into from
Jan 19, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add `WithResourceAsConstantLabels` option to apply resource attributes for every metric emitted by the Prometheus exporter. (#4733)
- Experimental cardinality limiting is added to the metric SDK.
See [metric documentation](./sdk/metric/EXPERIMENTAL.md#cardinality-limit) for more information about this feature and how to enable it. (#4457)
- Add `WithEndpointURL` option to the `exporters/otlp/otlpmetric/otlpmetricgrpc`, `exporters/otlp/otlpmetric/otlpmetrichttp`, `exporters/otlp/otlptrace/otlptracegrpc` and `exporters/otlp/otlptrace/otlptracehttp` packages. (#4808)

### Changed

Expand Down
14 changes: 14 additions & 0 deletions exporters/otlp/otlpmetric/otlpmetricgrpc/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,20 @@ func TestConfig(t *testing.T) {
return exp, coll
}

t.Run("WithEndpointURL", func(t *testing.T) {
coll, err := otest.NewGRPCCollector("", nil)
require.NoError(t, err)
t.Cleanup(coll.Shutdown)

ctx := context.Background()
exp, err := New(ctx, WithEndpointURL("http://"+coll.Addr().String()))
require.NoError(t, err)
t.Cleanup(func() { require.NoError(t, exp.Shutdown(ctx)) })

assert.NoError(t, exp.Export(ctx, &metricdata.ResourceMetrics{}))
assert.Len(t, coll.Collect().Dump(), 1)
})

t.Run("WithHeaders", func(t *testing.T) {
key := "my-custom-header"
headers := map[string]string{key: "custom-value"}
Expand Down
23 changes: 23 additions & 0 deletions exporters/otlp/otlpmetric/otlpmetricgrpc/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ func WithInsecure() Option {
// value will be used. If both are set, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
// will take precedence.
//
// If both this option and WithEndpointURL are used, the last used option will
// take precedence.
//
// By default, if an environment variable is not set, and this option is not
// passed, "localhost:4317" will be used.
//
Expand All @@ -88,6 +91,26 @@ func WithEndpoint(endpoint string) Option {
return wrappedOption{oconf.WithEndpoint(endpoint)}
}

// WithEndpointURL sets the target endpoint URL the Exporter will connect to.
//
// If the OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
// environment variable is set, and this option is not passed, that variable
// value will be used. If both are set, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
// will take precedence.
//
// If both this option and WithEndpoint are used, the last used option will
// take precedence.
//
// If an invalid URL is provided, the default value will be kept.
//
// By default, if an environment variable is not set, and this option is not
// passed, "localhost:4317" will be used.
//
// This option has no effect if WithGRPCConn is used.
func WithEndpointURL(u string) Option {
return wrappedOption{oconf.WithEndpointURL(u)}
}

// WithReconnectionPeriod set the minimum amount of time between connection
// attempts to the target endpoint.
//
Expand Down
2 changes: 1 addition & 1 deletion exporters/otlp/otlpmetric/otlpmetricgrpc/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The value may additionally a port, a scheme, and a path.
The value accepts "http" and "https" scheme.
The value should not contain a query string or fragment.
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT takes precedence over OTEL_EXPORTER_OTLP_ENDPOINT.
The configuration can be overridden by [WithEndpoint], [WithInsecure], [WithGRPCConn] options.
The configuration can be overridden by [WithEndpoint], [WithEndpointURL], [WithInsecure], and [WithGRPCConn] options.

OTEL_EXPORTER_OTLP_INSECURE, OTEL_EXPORTER_OTLP_METRICS_INSECURE (default: "false") -
setting "true" disables client transport security for the exporter's gRPC connection.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlp
import (
"crypto/tls"
"fmt"
"net/url"
"path"
"strings"
"time"
Expand All @@ -31,6 +32,7 @@ import (
"google.golang.org/grpc/encoding/gzip"

"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/sdk/metric"
)

Expand Down Expand Up @@ -279,6 +281,24 @@ func WithEndpoint(endpoint string) GenericOption {
})
}

func WithEndpointURL(v string) GenericOption {
return newGenericOption(func(cfg Config) Config {
u, err := url.Parse(v)
if err != nil {
global.Error(err, "otlpmetric: parse endpoint url", "url", v)
return cfg
}

cfg.Metrics.Endpoint = u.Host
cfg.Metrics.URLPath = u.Path
if u.Scheme != "https" {
cfg.Metrics.Insecure = true
}

return cfg
})
}

func WithCompression(compression Compression) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Metrics.Compression = compression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,42 @@ func TestConfigs(t *testing.T) {
assert.Equal(t, "someendpoint", c.Metrics.Endpoint)
},
},
{
name: "Test With Endpoint URL",
opts: []GenericOption{
WithEndpointURL("http://someendpoint/somepath"),
},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
assert.Equal(t, "someendpoint", c.Metrics.Endpoint)
assert.Equal(t, "/somepath", c.Metrics.URLPath)
assert.Equal(t, true, c.Metrics.Insecure)
},
},
{
name: "Test With Secure Endpoint URL",
opts: []GenericOption{
WithEndpointURL("https://someendpoint/somepath"),
},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
assert.Equal(t, "someendpoint", c.Metrics.Endpoint)
assert.Equal(t, "/somepath", c.Metrics.URLPath)
assert.Equal(t, false, c.Metrics.Insecure)
},
},
{
name: "Test With Invalid Endpoint URL",
opts: []GenericOption{
WithEndpointURL("%invalid"),
},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
if grpcOption {
assert.Equal(t, "localhost:4317", c.Metrics.Endpoint)
} else {
assert.Equal(t, "localhost:4318", c.Metrics.Endpoint)
}
assert.Equal(t, "/v1/metrics", c.Metrics.URLPath)
},
},
{
name: "Test Environment Endpoint",
env: map[string]string{
Expand Down
14 changes: 14 additions & 0 deletions exporters/otlp/otlpmetric/otlpmetrichttp/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,20 @@ func TestConfig(t *testing.T) {
return exp, coll
}

t.Run("WithEndpointURL", func(t *testing.T) {
coll, err := otest.NewHTTPCollector("", nil)
require.NoError(t, err)
ctx := context.Background()

exp, err := New(ctx, WithEndpointURL("http://"+coll.Addr().String()))
require.NoError(t, err)
t.Cleanup(func() { require.NoError(t, coll.Shutdown(ctx)) })
t.Cleanup(func() { require.NoError(t, exp.Shutdown(ctx)) })

assert.NoError(t, exp.Export(ctx, &metricdata.ResourceMetrics{}))
assert.Len(t, coll.Collect().Dump(), 1)
})

t.Run("WithHeaders", func(t *testing.T) {
key := http.CanonicalHeaderKey("my-custom-header")
headers := map[string]string{key: "custom-value"}
Expand Down
20 changes: 20 additions & 0 deletions exporters/otlp/otlpmetric/otlpmetrichttp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,26 @@ func WithEndpoint(endpoint string) Option {
return wrappedOption{oconf.WithEndpoint(endpoint)}
}

// WithEndpointURL sets the target endpoint URL the Exporter will connect to.
//
// If the OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
// environment variable is set, and this option is not passed, that variable
// value will be used. If both are set, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
// will take precedence.
//
// If both this option and WithEndpoint are used, the last used option will
// take precedence.
//
// If an invalid URL is provided, the default value will be kept.
//
// By default, if an environment variable is not set, and this option is not
// passed, "localhost:4317" will be used.
//
// This option has no effect if WithGRPCConn is used.
func WithEndpointURL(u string) Option {
return wrappedOption{oconf.WithEndpointURL(u)}
}

// WithCompression sets the compression strategy the Exporter will use to
// compress the HTTP body.
//
Expand Down
4 changes: 2 additions & 2 deletions exporters/otlp/otlpmetric/otlpmetrichttp/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ The value must contain a scheme ("http" or "https") and host.
The value may additionally contain a port and a path.
The value should not contain a query string or fragment.
The configuration can be overridden by OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
environment variable and by [WithEndpoint], [WithInsecure] options.
environment variable and by [WithEndpoint], [WithEndpointURL], and [WithInsecure] options.

OTEL_EXPORTER_OTLP_METRICS_ENDPOINT (default: "https://localhost:4318/v1/metrics") -
target URL to which the exporter sends telemetry.
The value must contain a scheme ("http" or "https") and host.
The value may additionally contain a port and a path.
The value should not contain a query string or fragment.
The configuration can be overridden by [WithEndpoint], [WitnInsecure], [WithURLPath] options.
The configuration can be overridden by [WithEndpoint], [WithEndpointURL], [WitnInsecure], and [WithURLPath] options.

OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_METRICS_HEADERS (default: none) -
key-value pairs used as headers associated with HTTP requests.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlp
import (
"crypto/tls"
"fmt"
"net/url"
"path"
"strings"
"time"
Expand All @@ -31,6 +32,7 @@ import (
"google.golang.org/grpc/encoding/gzip"

"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/sdk/metric"
)

Expand Down Expand Up @@ -279,6 +281,24 @@ func WithEndpoint(endpoint string) GenericOption {
})
}

func WithEndpointURL(v string) GenericOption {
return newGenericOption(func(cfg Config) Config {
u, err := url.Parse(v)
if err != nil {
global.Error(err, "otlpmetric: parse endpoint url", "url", v)
return cfg
}

cfg.Metrics.Endpoint = u.Host
cfg.Metrics.URLPath = u.Path
if u.Scheme != "https" {
cfg.Metrics.Insecure = true
}

return cfg
})
}

func WithCompression(compression Compression) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Metrics.Compression = compression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,42 @@ func TestConfigs(t *testing.T) {
assert.Equal(t, "someendpoint", c.Metrics.Endpoint)
},
},
{
name: "Test With Endpoint URL",
opts: []GenericOption{
WithEndpointURL("http://someendpoint/somepath"),
},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
assert.Equal(t, "someendpoint", c.Metrics.Endpoint)
assert.Equal(t, "/somepath", c.Metrics.URLPath)
assert.Equal(t, true, c.Metrics.Insecure)
},
},
{
name: "Test With Secure Endpoint URL",
opts: []GenericOption{
WithEndpointURL("https://someendpoint/somepath"),
},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
assert.Equal(t, "someendpoint", c.Metrics.Endpoint)
assert.Equal(t, "/somepath", c.Metrics.URLPath)
assert.Equal(t, false, c.Metrics.Insecure)
},
},
{
name: "Test With Invalid Endpoint URL",
opts: []GenericOption{
WithEndpointURL("%invalid"),
},
asserts: func(t *testing.T, c *Config, grpcOption bool) {
if grpcOption {
assert.Equal(t, "localhost:4317", c.Metrics.Endpoint)
} else {
assert.Equal(t, "localhost:4318", c.Metrics.Endpoint)
}
assert.Equal(t, "/v1/metrics", c.Metrics.URLPath)
},
},
{
name: "Test Environment Endpoint",
env: map[string]string{
Expand Down
18 changes: 18 additions & 0 deletions exporters/otlp/otlptrace/otlptracegrpc/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,24 @@ func TestNewEndToEnd(t *testing.T) {
}
}

func TestWithEndpointURL(t *testing.T) {
mc := runMockCollector(t)

ctx := context.Background()
exp := newGRPCExporter(t, ctx, "", []otlptracegrpc.Option{
otlptracegrpc.WithEndpointURL("http://" + mc.endpoint),
}...)
t.Cleanup(func() {
ctx, cancel := contextWithTimeout(ctx, t, 10*time.Second)
defer cancel()

require.NoError(t, exp.Shutdown(ctx))
})

// RunEndToEndTest closes mc.
otlptracetest.RunEndToEndTest(ctx, t, exp, mc)
}

func newGRPCExporter(t *testing.T, ctx context.Context, endpoint string, additionalOpts ...otlptracegrpc.Option) *otlptrace.Exporter {
opts := []otlptracegrpc.Option{
otlptracegrpc.WithInsecure(),
Expand Down
2 changes: 1 addition & 1 deletion exporters/otlp/otlptrace/otlptracegrpc/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The value may additionally a port, a scheme, and a path.
The value accepts "http" and "https" scheme.
The value should not contain a query string or fragment.
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT takes precedence over OTEL_EXPORTER_OTLP_ENDPOINT.
The configuration can be overridden by [WithEndpoint], [WithInsecure], [WithGRPCConn] options.
The configuration can be overridden by [WithEndpoint], [WithEndpointURL], [WithInsecure], and [WithGRPCConn] options.

OTEL_EXPORTER_OTLP_INSECURE, OTEL_EXPORTER_OTLP_TRACES_INSECURE (default: "false") -
setting "true" disables client transport security for the exporter's gRPC connection.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package otlpconfig // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/
import (
"crypto/tls"
"fmt"
"net/url"
"path"
"strings"
"time"
Expand All @@ -32,6 +33,7 @@ import (

"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/retry"
"go.opentelemetry.io/otel/internal/global"
)

const (
Expand Down Expand Up @@ -265,6 +267,24 @@ func WithEndpoint(endpoint string) GenericOption {
})
}

func WithEndpointURL(v string) GenericOption {
return newGenericOption(func(cfg Config) Config {
u, err := url.Parse(v)
if err != nil {
global.Error(err, "otlptrace: parse endpoint url", "url", v)
return cfg
}

cfg.Traces.Endpoint = u.Host
cfg.Traces.URLPath = u.Path
if u.Scheme != "https" {
cfg.Traces.Insecure = true
}

return cfg
})
}

func WithCompression(compression Compression) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Traces.Compression = compression
Expand Down