diff --git a/CHANGELOG.md b/CHANGELOG.md index c8c72034500..b4c6c5535ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Added + +- Support `OTEL_EXPORTER_OTLP_LOGS_INSECURE` and `OTEL_EXPORTER_OTLP_INSECURE` environments in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`. (#5739) + ### Fixed - Fix memory leak in the global `MeterProvider` when identical instruments are repeatedly created. (#5754) diff --git a/exporters/otlp/otlplog/otlploggrpc/config.go b/exporters/otlp/otlplog/otlploggrpc/config.go index 52e8c256c6c..8b2c0f584b2 100644 --- a/exporters/otlp/otlplog/otlploggrpc/config.go +++ b/exporters/otlp/otlplog/otlploggrpc/config.go @@ -35,7 +35,10 @@ var ( "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT", "OTEL_EXPORTER_OTLP_ENDPOINT", } - envInsecure = envEndpoint + envInsecure = []string{ + "OTEL_EXPORTER_OTLP_LOGS_INSECURE", + "OTEL_EXPORTER_OTLP_INSECURE", + } envHeaders = []string{ "OTEL_EXPORTER_OTLP_LOGS_HEADERS", @@ -109,6 +112,7 @@ func newConfig(options []Option) config { fallback[string](defaultEndpoint), ) c.insecure = c.insecure.Resolve( + loadInsecureFromEnvEndpoint(envEndpoint), getEnv[bool](envInsecure, convInsecure), ) c.tlsCfg = c.tlsCfg.Resolve( @@ -204,11 +208,7 @@ func WithEndpointURL(rawURL string) Option { } return fnOpt(func(c config) config { c.endpoint = newSetting(u.Host) - if u.Scheme != "https" { - c.insecure = newSetting(true) - } else { - c.insecure = newSetting(false) - } + c.insecure = insecureFromScheme(c.insecure, u.Scheme) return c }) } @@ -394,15 +394,39 @@ func convEndpoint(s string) (string, error) { return u.Host, nil } -// convInsecure parses s as a URL string and returns if the connection should -// use client transport security or not. If s is an invalid URL, false and an -// error are returned. +// convInsecure converts s from string to bool without case sensitivity. +// If s is not valid returns error. func convInsecure(s string) (bool, error) { - u, err := url.Parse(s) - if err != nil { - return false, err + s = strings.ToLower(s) + if s != "true" && s != "false" { + return false, fmt.Errorf("can't convert %q to bool", s) + } + + return s == "true", nil +} + +// loadInsecureFromEnvEndpoint returns a resolver that fetches +// insecure setting from envEndpoint is it possible. +func loadInsecureFromEnvEndpoint(envEndpoint []string) resolver[bool] { + return func(s setting[bool]) setting[bool] { + if s.Set { + // Passed, valid, options have precedence. + return s + } + + for _, key := range envEndpoint { + if vStr := os.Getenv(key); vStr != "" { + u, err := url.Parse(vStr) + if err != nil { + otel.Handle(fmt.Errorf("invalid %s value %s: %w", key, vStr, err)) + continue + } + + return insecureFromScheme(s, u.Scheme) + } + } + return s } - return u.Scheme != "https", nil } // convHeaders converts the OTel environment variable header value s into a @@ -529,6 +553,19 @@ func loadCertificates(certPath, keyPath string) ([]tls.Certificate, error) { return []tls.Certificate{crt}, nil } +// insecureFromScheme return setting if the connection should +// use client transport security or not. +// Empty scheme doesn't force insecure setting. +func insecureFromScheme(prev setting[bool], scheme string) setting[bool] { + if scheme == "https" { + return newSetting(false) + } else if len(scheme) > 0 { + return newSetting(true) + } + + return prev +} + func compressorToCompression(compressor string) Compression { c, err := convCompression(compressor) if err != nil { diff --git a/exporters/otlp/otlplog/otlploggrpc/config_test.go b/exporters/otlp/otlplog/otlploggrpc/config_test.go index 02817476f5c..40c74cb72b4 100644 --- a/exporters/otlp/otlplog/otlploggrpc/config_test.go +++ b/exporters/otlp/otlplog/otlploggrpc/config_test.go @@ -333,6 +333,83 @@ func TestNewConfig(t *testing.T) { `invalid OTEL_EXPORTER_OTLP_LOGS_TIMEOUT value 100 seconds: strconv.Atoi: parsing "100 seconds": invalid syntax`, }, }, + { + name: "OptionEndpointURLWithoutScheme", + options: []Option{ + WithEndpointURL("//env.endpoint:8080/prefix"), + }, + want: config{ + endpoint: newSetting("env.endpoint:8080"), + retryCfg: newSetting(defaultRetryCfg), + timeout: newSetting(defaultTimeout), + }, + }, + { + name: "EnvEndpointWithoutScheme", + envars: map[string]string{ + "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT": "//env.endpoint:8080/prefix", + }, + want: config{ + endpoint: newSetting("env.endpoint:8080"), + retryCfg: newSetting(defaultRetryCfg), + timeout: newSetting(defaultTimeout), + }, + }, + { + name: "DefaultEndpointWithEnvInsecure", + envars: map[string]string{ + "OTEL_EXPORTER_OTLP_LOGS_INSECURE": "true", + }, + want: config{ + endpoint: newSetting(defaultEndpoint), + insecure: newSetting(true), + retryCfg: newSetting(defaultRetryCfg), + timeout: newSetting(defaultTimeout), + }, + }, + { + name: "EnvEndpointWithoutSchemeWithEnvInsecure", + envars: map[string]string{ + "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT": "//env.endpoint:8080/prefix", + "OTEL_EXPORTER_OTLP_LOGS_INSECURE": "true", + }, + want: config{ + endpoint: newSetting("env.endpoint:8080"), + insecure: newSetting(true), + retryCfg: newSetting(defaultRetryCfg), + timeout: newSetting(defaultTimeout), + }, + }, + { + name: "OptionEndpointURLWithoutSchemeWithEnvInsecure", + options: []Option{ + WithEndpointURL("//env.endpoint:8080/prefix"), + }, + envars: map[string]string{ + "OTEL_EXPORTER_OTLP_LOGS_INSECURE": "true", + }, + want: config{ + endpoint: newSetting("env.endpoint:8080"), + insecure: newSetting(true), + retryCfg: newSetting(defaultRetryCfg), + timeout: newSetting(defaultTimeout), + }, + }, + { + name: "OptionEndpointWithEnvInsecure", + options: []Option{ + WithEndpoint("env.endpoint:8080"), + }, + envars: map[string]string{ + "OTEL_EXPORTER_OTLP_LOGS_INSECURE": "true", + }, + want: config{ + endpoint: newSetting("env.endpoint:8080"), + insecure: newSetting(true), + retryCfg: newSetting(defaultRetryCfg), + timeout: newSetting(defaultTimeout), + }, + }, } for _, tc := range testcases { diff --git a/exporters/otlp/otlplog/otlploggrpc/doc.go b/exporters/otlp/otlplog/otlploggrpc/doc.go index 2b15f34bd75..67cb814342d 100644 --- a/exporters/otlp/otlplog/otlploggrpc/doc.go +++ b/exporters/otlp/otlplog/otlploggrpc/doc.go @@ -18,6 +18,12 @@ The value should not contain a query string or fragment. OTEL_EXPORTER_OTLP_LOGS_ENDPOINT takes precedence over OTEL_EXPORTER_OTLP_ENDPOINT. The configuration can be overridden by [WithEndpoint], [WithEndpointURL], [WithInsecure], and [WithGRPCConn] options. +OTEL_EXPORTER_OTLP_INSECURE, OTEL_EXPORTER_OTLP_LOGS_INSECURE (default: "false") - +setting "true" disables client transport security for the exporter's gRPC connection. +You can use this only when an endpoint is provided without scheme. +OTEL_EXPORTER_OTLP_LOGS_INSECURE takes precedence over OTEL_EXPORTER_OTLP_INSECURE. +The configuration can be overridden by [WithInsecure], [WithGRPCConn] options. + OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_LOGS_HEADERS (default: none) - key-value pairs used as gRPC metadata associated with gRPC requests. The value is expected to be represented in a format matching the [W3C Baggage HTTP Header Content Format],