From 36ca50eaece2310194f45f5d86d5a84fce8bbfe2 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Tue, 7 Dec 2021 14:52:43 -0800 Subject: [PATCH 1/6] Fix per-signal endpoint parsing in otlptrace --- .../internal/otlpconfig/envconfig.go | 74 +++++++++++++------ .../internal/otlpconfig/options_test.go | 42 ++++------- .../otlp/otlptrace/otlptracehttp/client.go | 5 +- 3 files changed, 71 insertions(+), 50 deletions(-) diff --git a/exporters/otlp/otlptrace/internal/otlpconfig/envconfig.go b/exporters/otlp/otlptrace/internal/otlpconfig/envconfig.go index 352a88206da..027592fbd3b 100644 --- a/exporters/otlp/otlptrace/internal/otlpconfig/envconfig.go +++ b/exporters/otlp/otlptrace/internal/otlpconfig/envconfig.go @@ -20,7 +20,7 @@ import ( "io/ioutil" "net/url" "os" - "regexp" + "path" "strconv" "strings" "time" @@ -28,8 +28,6 @@ import ( "go.opentelemetry.io/otel" ) -var httpSchemeRegexp = regexp.MustCompile(`(?i)^(http://|https://)`) - func ApplyGRPCEnvConfigs(cfg *Config) { e := EnvOptionsReader{ GetEnv: os.Getenv, @@ -72,22 +70,55 @@ func (e *EnvOptionsReader) GetOptionsFromEnv() []GenericOption { // Endpoint if v, ok := e.getEnvValue("ENDPOINT"); ok { - if isInsecureEndpoint(v) { - opts = append(opts, WithInsecure()) - } else { - opts = append(opts, WithSecure()) + u, err := url.Parse(v) + // Ignore invalid values. + if err == nil { + // This is used to set the scheme for OTLP/HTTP. + if insecureSchema(u.Scheme) { + opts = append(opts, WithInsecure()) + } else { + opts = append(opts, WithSecure()) + } + opts = append(opts, newSplitOption(func(cfg *Config) { + cfg.Traces.Endpoint = u.Host + // For OTLP/HTTP endpoint URLs without a per-signal + // configuration, the passed endpoint is used as a base URL + // and the signals are sent to these paths relative to that. + cfg.Traces.URLPath = path.Join(u.Path, DefaultTracesPath) + }, func(cfg *Config) { + // For OTLP/gRPC endpoints, this is the target to which the + // exporter is going to send telemetry. + cfg.Traces.Endpoint = path.Join(u.Host, u.Path) + })) } - - opts = append(opts, WithEndpoint(trimSchema(v))) } if v, ok := e.getEnvValue("TRACES_ENDPOINT"); ok { - if isInsecureEndpoint(v) { - opts = append(opts, WithInsecure()) - } else { - opts = append(opts, WithSecure()) + u, err := url.Parse(v) + // Ignore invalid values. + if err == nil { + // This is used to set the scheme for OTLP/HTTP. + if insecureSchema(u.Scheme) { + opts = append(opts, WithInsecure()) + } else { + opts = append(opts, WithSecure()) + } + opts = append(opts, newSplitOption(func(cfg *Config) { + cfg.Traces.Endpoint = u.Host + // For endpoint URLs for OTLP/HTTP per-signal variables, the + // URL MUST be used as-is without any modification. The only + // exception is that if an URL contains no path part, the root + // path / MUST be used. + path := u.Path + if path == "" { + path = "/" + } + cfg.Traces.URLPath = path + }, func(cfg *Config) { + // For OTLP/gRPC endpoints, this is the target to which the + // exporter is going to send telemetry. + cfg.Traces.Endpoint = path.Join(u.Host, u.Path) + })) } - - opts = append(opts, WithEndpoint(trimSchema(v))) } // Certificate File @@ -136,12 +167,13 @@ func (e *EnvOptionsReader) GetOptionsFromEnv() []GenericOption { return opts } -func isInsecureEndpoint(endpoint string) bool { - return strings.HasPrefix(strings.ToLower(endpoint), "http://") || strings.HasPrefix(strings.ToLower(endpoint), "unix://") -} - -func trimSchema(endpoint string) string { - return httpSchemeRegexp.ReplaceAllString(endpoint, "") +func insecureSchema(schema string) bool { + switch strings.ToLower(schema) { + case "http", "unix": + return true + default: + return false + } } // getEnvValue gets an OTLP environment variable value of the specified key using the GetEnv function. diff --git a/exporters/otlp/otlptrace/internal/otlpconfig/options_test.go b/exporters/otlp/otlptrace/internal/otlpconfig/options_test.go index ad25efdac04..63b5cdbb8c5 100644 --- a/exporters/otlp/otlptrace/internal/otlpconfig/options_test.go +++ b/exporters/otlp/otlptrace/internal/otlpconfig/options_test.go @@ -96,20 +96,30 @@ func TestConfigs(t *testing.T) { { name: "Test Environment Endpoint", env: map[string]string{ - "OTEL_EXPORTER_OTLP_ENDPOINT": "env_endpoint", + "OTEL_EXPORTER_OTLP_ENDPOINT": "https://env.endpoint/prefix", }, asserts: func(t *testing.T, c *otlpconfig.Config, grpcOption bool) { - assert.Equal(t, "env_endpoint", c.Traces.Endpoint) + assert.False(t, c.Traces.Insecure) + if grpcOption { + assert.Equal(t, "env.endpoint/prefix", c.Traces.Endpoint) + } else { + assert.Equal(t, "env.endpoint", c.Traces.Endpoint) + assert.Equal(t, "/prefix/v1/traces", c.Traces.URLPath) + } }, }, { name: "Test Environment Signal Specific Endpoint", env: map[string]string{ - "OTEL_EXPORTER_OTLP_ENDPOINT": "overrode_by_signal_specific", - "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "env_traces_endpoint", + "OTEL_EXPORTER_OTLP_ENDPOINT": "https://overrode.by.signal.specific/env/var", + "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "http://env.traces.endpoint", }, asserts: func(t *testing.T, c *otlpconfig.Config, grpcOption bool) { - assert.Equal(t, "env_traces_endpoint", c.Traces.Endpoint) + assert.True(t, c.Traces.Insecure) + assert.Equal(t, "env.traces.endpoint", c.Traces.Endpoint) + if !grpcOption { + assert.Equal(t, "/", c.Traces.URLPath) + } }, }, { @@ -154,28 +164,6 @@ func TestConfigs(t *testing.T) { assert.Equal(t, false, c.Traces.Insecure) }, }, - { - name: "Test Environment Signal Specific Endpoint", - env: map[string]string{ - "OTEL_EXPORTER_OTLP_ENDPOINT": "http://overrode_by_signal_specific", - "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "http://env_traces_endpoint", - }, - asserts: func(t *testing.T, c *otlpconfig.Config, grpcOption bool) { - assert.Equal(t, "env_traces_endpoint", c.Traces.Endpoint) - assert.Equal(t, true, c.Traces.Insecure) - }, - }, - { - name: "Test Environment Signal Specific Endpoint #2", - env: map[string]string{ - "OTEL_EXPORTER_OTLP_ENDPOINT": "http://overrode_by_signal_specific", - "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "http://env_traces_endpoint", - }, - asserts: func(t *testing.T, c *otlpconfig.Config, grpcOption bool) { - assert.Equal(t, "env_traces_endpoint", c.Traces.Endpoint) - assert.Equal(t, true, c.Traces.Insecure) - }, - }, { name: "Test Environment Signal Specific Endpoint with uppercase scheme", env: map[string]string{ diff --git a/exporters/otlp/otlptrace/otlptracehttp/client.go b/exporters/otlp/otlptrace/otlptracehttp/client.go index 93a7e4a7e86..dbc6c5ba785 100644 --- a/exporters/otlp/otlptrace/otlptracehttp/client.go +++ b/exporters/otlp/otlptrace/otlptracehttp/client.go @@ -23,6 +23,7 @@ import ( "io/ioutil" "net" "net/http" + "net/url" "path" "strconv" "strings" @@ -201,8 +202,8 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc } func (d *client) newRequest(body []byte) (request, error) { - address := fmt.Sprintf("%s://%s%s", d.getScheme(), d.cfg.Endpoint, d.cfg.URLPath) - r, err := http.NewRequest(http.MethodPost, address, nil) + u := url.URL{Scheme: d.getScheme(), Host: d.cfg.Endpoint, Path: d.cfg.URLPath} + r, err := http.NewRequest(http.MethodPost, u.String(), nil) if err != nil { return request{Request: r}, err } From 60165a86d24ca86e93d9c7b63908484f57d49126 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Tue, 7 Dec 2021 15:05:47 -0800 Subject: [PATCH 2/6] Add distinguishing non-per-signal env var value --- exporters/otlp/otlptrace/internal/otlpconfig/options_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporters/otlp/otlptrace/internal/otlpconfig/options_test.go b/exporters/otlp/otlptrace/internal/otlpconfig/options_test.go index 63b5cdbb8c5..e038261f141 100644 --- a/exporters/otlp/otlptrace/internal/otlpconfig/options_test.go +++ b/exporters/otlp/otlptrace/internal/otlpconfig/options_test.go @@ -167,7 +167,7 @@ func TestConfigs(t *testing.T) { { name: "Test Environment Signal Specific Endpoint with uppercase scheme", env: map[string]string{ - "OTEL_EXPORTER_OTLP_ENDPOINT": "HTTP://overrode_by_signal_specific", + "OTEL_EXPORTER_OTLP_ENDPOINT": "HTTPS://overrode_by_signal_specific", "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "HtTp://env_traces_endpoint", }, asserts: func(t *testing.T, c *otlpconfig.Config, grpcOption bool) { From 523447e4618423010415512c76b2a34d70dbfc78 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Tue, 7 Dec 2021 15:09:30 -0800 Subject: [PATCH 3/6] Fix per-signal endpoint parsing in otlpmetric --- .../internal/otlpconfig/envconfig.go | 74 +++++++++++++------ .../internal/otlpconfig/options_test.go | 48 +++++------- .../otlp/otlpmetric/otlpmetrichttp/client.go | 5 +- 3 files changed, 74 insertions(+), 53 deletions(-) diff --git a/exporters/otlp/otlpmetric/internal/otlpconfig/envconfig.go b/exporters/otlp/otlpmetric/internal/otlpconfig/envconfig.go index 17d0e71bc97..95eec75dd27 100644 --- a/exporters/otlp/otlpmetric/internal/otlpconfig/envconfig.go +++ b/exporters/otlp/otlpmetric/internal/otlpconfig/envconfig.go @@ -20,7 +20,7 @@ import ( "io/ioutil" "net/url" "os" - "regexp" + "path" "strconv" "strings" "time" @@ -28,8 +28,6 @@ import ( "go.opentelemetry.io/otel" ) -var httpSchemeRegexp = regexp.MustCompile(`(?i)^http://|https://`) - func ApplyGRPCEnvConfigs(cfg *Config) { e := EnvOptionsReader{ GetEnv: os.Getenv, @@ -72,22 +70,55 @@ func (e *EnvOptionsReader) GetOptionsFromEnv() []GenericOption { // Endpoint if v, ok := e.getEnvValue("ENDPOINT"); ok { - if isInsecureEndpoint(v) { - opts = append(opts, WithInsecure()) - } else { - opts = append(opts, WithSecure()) + u, err := url.Parse(v) + // Ignore invalid values. + if err == nil { + // This is used to set the scheme for OTLP/HTTP. + if insecureSchema(u.Scheme) { + opts = append(opts, WithInsecure()) + } else { + opts = append(opts, WithSecure()) + } + opts = append(opts, newSplitOption(func(cfg *Config) { + cfg.Metrics.Endpoint = u.Host + // For OTLP/HTTP endpoint URLs without a per-signal + // configuration, the passed endpoint is used as a base URL + // and the signals are sent to these paths relative to that. + cfg.Metrics.URLPath = path.Join(u.Path, DefaultMetricsPath) + }, func(cfg *Config) { + // For OTLP/gRPC endpoints, this is the target to which the + // exporter is going to send telemetry. + cfg.Metrics.Endpoint = path.Join(u.Host, u.Path) + })) } - - opts = append(opts, WithEndpoint(trimSchema(v))) } if v, ok := e.getEnvValue("METRICS_ENDPOINT"); ok { - if isInsecureEndpoint(v) { - opts = append(opts, WithInsecure()) - } else { - opts = append(opts, WithSecure()) + u, err := url.Parse(v) + // Ignore invalid values. + if err == nil { + // This is used to set the scheme for OTLP/HTTP. + if insecureSchema(u.Scheme) { + opts = append(opts, WithInsecure()) + } else { + opts = append(opts, WithSecure()) + } + opts = append(opts, newSplitOption(func(cfg *Config) { + cfg.Metrics.Endpoint = u.Host + // For endpoint URLs for OTLP/HTTP per-signal variables, the + // URL MUST be used as-is without any modification. The only + // exception is that if an URL contains no path part, the root + // path / MUST be used. + path := u.Path + if path == "" { + path = "/" + } + cfg.Metrics.URLPath = path + }, func(cfg *Config) { + // For OTLP/gRPC endpoints, this is the target to which the + // exporter is going to send telemetry. + cfg.Metrics.Endpoint = path.Join(u.Host, u.Path) + })) } - - opts = append(opts, WithEndpoint(trimSchema(v))) } // Certificate File @@ -137,12 +168,13 @@ func (e *EnvOptionsReader) GetOptionsFromEnv() []GenericOption { return opts } -func isInsecureEndpoint(endpoint string) bool { - return strings.HasPrefix(strings.ToLower(endpoint), "http://") || strings.HasPrefix(strings.ToLower(endpoint), "unix://") -} - -func trimSchema(endpoint string) string { - return httpSchemeRegexp.ReplaceAllString(endpoint, "") +func insecureSchema(schema string) bool { + switch strings.ToLower(schema) { + case "http", "unix": + return true + default: + return false + } } // getEnvValue gets an OTLP environment variable value of the specified key using the GetEnv function. diff --git a/exporters/otlp/otlpmetric/internal/otlpconfig/options_test.go b/exporters/otlp/otlpmetric/internal/otlpconfig/options_test.go index 2d47e7c285f..acba5bd120d 100644 --- a/exporters/otlp/otlpmetric/internal/otlpconfig/options_test.go +++ b/exporters/otlp/otlpmetric/internal/otlpconfig/options_test.go @@ -96,20 +96,30 @@ func TestConfigs(t *testing.T) { { name: "Test Environment Endpoint", env: map[string]string{ - "OTEL_EXPORTER_OTLP_ENDPOINT": "env_endpoint", + "OTEL_EXPORTER_OTLP_ENDPOINT": "https://env.endpoint/prefix", }, asserts: func(t *testing.T, c *otlpconfig.Config, grpcOption bool) { - assert.Equal(t, "env_endpoint", c.Metrics.Endpoint) + assert.False(t, c.Metrics.Insecure) + if grpcOption { + assert.Equal(t, "env.endpoint/prefix", c.Metrics.Endpoint) + } else { + assert.Equal(t, "env.endpoint", c.Metrics.Endpoint) + assert.Equal(t, "/prefix/v1/metrics", c.Metrics.URLPath) + } }, }, { name: "Test Environment Signal Specific Endpoint", env: map[string]string{ - "OTEL_EXPORTER_OTLP_ENDPOINT": "overrode_by_signal_specific", - "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT": "env_metrics_endpoint", + "OTEL_EXPORTER_OTLP_ENDPOINT": "https://overrode.by.signal.specific/env/var", + "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT": "http://env.metrics.endpoint", }, asserts: func(t *testing.T, c *otlpconfig.Config, grpcOption bool) { - assert.Equal(t, "env_metrics_endpoint", c.Metrics.Endpoint) + assert.True(t, c.Metrics.Insecure) + assert.Equal(t, "env.metrics.endpoint", c.Metrics.Endpoint) + if !grpcOption { + assert.Equal(t, "/", c.Metrics.URLPath) + } }, }, { @@ -154,37 +164,15 @@ func TestConfigs(t *testing.T) { assert.Equal(t, false, c.Metrics.Insecure) }, }, - { - name: "Test Environment Signal Specific Endpoint", - env: map[string]string{ - "OTEL_EXPORTER_OTLP_ENDPOINT": "http://overrode_by_signal_specific", - "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT": "https://env_metrics_endpoint", - }, - asserts: func(t *testing.T, c *otlpconfig.Config, grpcOption bool) { - assert.Equal(t, "env_metrics_endpoint", c.Metrics.Endpoint) - assert.Equal(t, false, c.Metrics.Insecure) - }, - }, - { - name: "Test Environment Signal Specific Endpoint #2", - env: map[string]string{ - "OTEL_EXPORTER_OTLP_ENDPOINT": "http://overrode_by_signal_specific", - "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT": "env_metrics_endpoint", - }, - asserts: func(t *testing.T, c *otlpconfig.Config, grpcOption bool) { - assert.Equal(t, "env_metrics_endpoint", c.Metrics.Endpoint) - assert.Equal(t, false, c.Metrics.Insecure) - }, - }, { name: "Test Environment Signal Specific Endpoint with uppercase scheme", env: map[string]string{ - "OTEL_EXPORTER_OTLP_ENDPOINT": "HTTP://overrode_by_signal_specific", - "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT": "env_metrics_endpoint", + "OTEL_EXPORTER_OTLP_ENDPOINT": "HTTPS://overrode_by_signal_specific", + "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT": "HtTp://env_metrics_endpoint", }, asserts: func(t *testing.T, c *otlpconfig.Config, grpcOption bool) { assert.Equal(t, "env_metrics_endpoint", c.Metrics.Endpoint) - assert.Equal(t, false, c.Metrics.Insecure) + assert.Equal(t, true, c.Metrics.Insecure) }, }, diff --git a/exporters/otlp/otlpmetric/otlpmetrichttp/client.go b/exporters/otlp/otlpmetric/otlpmetrichttp/client.go index b78067dc075..55334a221c6 100644 --- a/exporters/otlp/otlpmetric/otlpmetrichttp/client.go +++ b/exporters/otlp/otlpmetric/otlpmetrichttp/client.go @@ -23,6 +23,7 @@ import ( "io/ioutil" "net" "net/http" + "net/url" "path" "strconv" "strings" @@ -199,8 +200,8 @@ func (d *client) UploadMetrics(ctx context.Context, protoMetrics []*metricpb.Res } func (d *client) newRequest(body []byte) (request, error) { - address := fmt.Sprintf("%s://%s%s", d.getScheme(), d.cfg.Endpoint, d.cfg.URLPath) - r, err := http.NewRequest(http.MethodPost, address, nil) + u := url.URL{Scheme: d.getScheme(), Host: d.cfg.Endpoint, Path: d.cfg.URLPath} + r, err := http.NewRequest(http.MethodPost, u.String(), nil) if err != nil { return request{Request: r}, err } From 96c3636d053de9ba9fbac1070faccc5ce5854634 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Tue, 7 Dec 2021 15:13:38 -0800 Subject: [PATCH 4/6] Add changes to changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f204165297..c4c10c7be09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,12 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - The `"go.opentelemetry.io/otel/exporter/otel/otlpmetric/otlpmetricgrpc".Client` now uses the underlying gRPC `ClientConn` to handle name resolution, TCP connection establishment (with retries and backoff) and TLS handshakes, and handling errors on established connections by re-resolving the name and reconnecting. (#2425) - The `"go.opentelemetry.io/otel/exporter/otel/otlpmetric/otlpmetricgrpc".RetrySettings` type is renamed to `RetryConfig`. (#2425) +### Fixed + +- The `go.opentelemetry.io/otel/exporter/otel/*` exporters are updated to handle per-signal and universal endpoints according to the OpenTelemetry specification. + Any per-signal endpoint set via an `OTEL_EXPORTER_OTLP__ENDPOINT` environment variable is now used without modification of the path. + When `OTEL_EXPORTER_OTLP_ENDPOINT` is set, if it contains a path, that path is used as a base path which per-signal paths are appended to. (#2338 #2433) + ### Deprecated - Deprecated the `"go.opentelemetry.io/otel/exporter/otel/otlpmetric/otlpmetrichttp".WithMaxAttempts` `Option`, use the new `WithRetry` `Option` instead. (#2425) From 8fea8674920841521389835d6ac797e96cf8c0ea Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Tue, 7 Dec 2021 15:16:43 -0800 Subject: [PATCH 5/6] Use else if to prevent unnecessary work --- .../internal/otlpconfig/envconfig.go | 31 +++++++++---------- .../internal/otlpconfig/envconfig.go | 31 +++++++++---------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/exporters/otlp/otlpmetric/internal/otlpconfig/envconfig.go b/exporters/otlp/otlpmetric/internal/otlpconfig/envconfig.go index 95eec75dd27..2a577450958 100644 --- a/exporters/otlp/otlpmetric/internal/otlpconfig/envconfig.go +++ b/exporters/otlp/otlpmetric/internal/otlpconfig/envconfig.go @@ -69,7 +69,7 @@ func (e *EnvOptionsReader) GetOptionsFromEnv() []GenericOption { var opts []GenericOption // Endpoint - if v, ok := e.getEnvValue("ENDPOINT"); ok { + if v, ok := e.getEnvValue("METRICS_ENDPOINT"); ok { u, err := url.Parse(v) // Ignore invalid values. if err == nil { @@ -81,18 +81,22 @@ func (e *EnvOptionsReader) GetOptionsFromEnv() []GenericOption { } opts = append(opts, newSplitOption(func(cfg *Config) { cfg.Metrics.Endpoint = u.Host - // For OTLP/HTTP endpoint URLs without a per-signal - // configuration, the passed endpoint is used as a base URL - // and the signals are sent to these paths relative to that. - cfg.Metrics.URLPath = path.Join(u.Path, DefaultMetricsPath) + // For endpoint URLs for OTLP/HTTP per-signal variables, the + // URL MUST be used as-is without any modification. The only + // exception is that if an URL contains no path part, the root + // path / MUST be used. + path := u.Path + if path == "" { + path = "/" + } + cfg.Metrics.URLPath = path }, func(cfg *Config) { // For OTLP/gRPC endpoints, this is the target to which the // exporter is going to send telemetry. cfg.Metrics.Endpoint = path.Join(u.Host, u.Path) })) } - } - if v, ok := e.getEnvValue("METRICS_ENDPOINT"); ok { + } else if v, ok = e.getEnvValue("ENDPOINT"); ok { u, err := url.Parse(v) // Ignore invalid values. if err == nil { @@ -104,15 +108,10 @@ func (e *EnvOptionsReader) GetOptionsFromEnv() []GenericOption { } opts = append(opts, newSplitOption(func(cfg *Config) { cfg.Metrics.Endpoint = u.Host - // For endpoint URLs for OTLP/HTTP per-signal variables, the - // URL MUST be used as-is without any modification. The only - // exception is that if an URL contains no path part, the root - // path / MUST be used. - path := u.Path - if path == "" { - path = "/" - } - cfg.Metrics.URLPath = path + // For OTLP/HTTP endpoint URLs without a per-signal + // configuration, the passed endpoint is used as a base URL + // and the signals are sent to these paths relative to that. + cfg.Metrics.URLPath = path.Join(u.Path, DefaultMetricsPath) }, func(cfg *Config) { // For OTLP/gRPC endpoints, this is the target to which the // exporter is going to send telemetry. diff --git a/exporters/otlp/otlptrace/internal/otlpconfig/envconfig.go b/exporters/otlp/otlptrace/internal/otlpconfig/envconfig.go index 027592fbd3b..f5bf08bd3db 100644 --- a/exporters/otlp/otlptrace/internal/otlpconfig/envconfig.go +++ b/exporters/otlp/otlptrace/internal/otlpconfig/envconfig.go @@ -69,7 +69,7 @@ func (e *EnvOptionsReader) GetOptionsFromEnv() []GenericOption { var opts []GenericOption // Endpoint - if v, ok := e.getEnvValue("ENDPOINT"); ok { + if v, ok := e.getEnvValue("TRACES_ENDPOINT"); ok { u, err := url.Parse(v) // Ignore invalid values. if err == nil { @@ -81,18 +81,22 @@ func (e *EnvOptionsReader) GetOptionsFromEnv() []GenericOption { } opts = append(opts, newSplitOption(func(cfg *Config) { cfg.Traces.Endpoint = u.Host - // For OTLP/HTTP endpoint URLs without a per-signal - // configuration, the passed endpoint is used as a base URL - // and the signals are sent to these paths relative to that. - cfg.Traces.URLPath = path.Join(u.Path, DefaultTracesPath) + // For endpoint URLs for OTLP/HTTP per-signal variables, the + // URL MUST be used as-is without any modification. The only + // exception is that if an URL contains no path part, the root + // path / MUST be used. + path := u.Path + if path == "" { + path = "/" + } + cfg.Traces.URLPath = path }, func(cfg *Config) { // For OTLP/gRPC endpoints, this is the target to which the // exporter is going to send telemetry. cfg.Traces.Endpoint = path.Join(u.Host, u.Path) })) } - } - if v, ok := e.getEnvValue("TRACES_ENDPOINT"); ok { + } else if v, ok = e.getEnvValue("ENDPOINT"); ok { u, err := url.Parse(v) // Ignore invalid values. if err == nil { @@ -104,15 +108,10 @@ func (e *EnvOptionsReader) GetOptionsFromEnv() []GenericOption { } opts = append(opts, newSplitOption(func(cfg *Config) { cfg.Traces.Endpoint = u.Host - // For endpoint URLs for OTLP/HTTP per-signal variables, the - // URL MUST be used as-is without any modification. The only - // exception is that if an URL contains no path part, the root - // path / MUST be used. - path := u.Path - if path == "" { - path = "/" - } - cfg.Traces.URLPath = path + // For OTLP/HTTP endpoint URLs without a per-signal + // configuration, the passed endpoint is used as a base URL + // and the signals are sent to these paths relative to that. + cfg.Traces.URLPath = path.Join(u.Path, DefaultTracesPath) }, func(cfg *Config) { // For OTLP/gRPC endpoints, this is the target to which the // exporter is going to send telemetry. From 69770919321834f1d7d2e9373caa3f4abb11848a Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Thu, 9 Dec 2021 10:14:07 -0800 Subject: [PATCH 6/6] Add spec link to otlptrace README --- exporters/otlp/otlptrace/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/exporters/otlp/otlptrace/README.md b/exporters/otlp/otlptrace/README.md index 451ad6dc4df..8a40a86a246 100644 --- a/exporters/otlp/otlptrace/README.md +++ b/exporters/otlp/otlptrace/README.md @@ -33,8 +33,10 @@ The `otlptracehttp` package implements a client for the span exporter that sends ### Environment Variables -The following environment variables can be used -(instead of options objects) to override the default configuration. +The following environment variables can be used (instead of options objects) to +override the default configuration. For more information about how each of +these environment variables is interpreted, see [the OpenTelemetry +specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/protocol/exporter.md). | Environment variable | Option | Default value | | ------------------------------------------------------------------------ |------------------------------ | ----------------------------------- |