1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2024-12-26 21:05:00 +02:00

Support OTEL_EXPORTER_OTLP_LOGS_INSECURE and OTEL_EXPORTER_OTLP_INSECURE environments in grpc exporter (#5739)

Closes https://github.com/open-telemetry/opentelemetry-go/issues/5719

In this commit I add OTEL_EXPORTER_OTLP_LOGS_INSECURE and
OTEL_EXPORTER_OTLP_INSECURE env options to `otlploggrpc.Exporter`.

Now insecure option is fetched from env endpoint value
(OTEL_EXPORTER_OTLP_LOGS_ENDPOINT/OTEL_EXPORTER_OTLP_ENDPOINT).
According to
[spec](https://opentelemetry.io/docs/specs/otel/protocol/exporter/):
> Insecure: Whether to enable client transport security for the
exporter’s gRPC connection. This option only applies to OTLP/gRPC when
an endpoint is provided without the http or https scheme - OTLP/HTTP
always uses the scheme provided for the endpoint.

So with current behavior we have several problems:
- If default endpoint is used, we can't use insecure connection (with
setting OTEL_EXPORTER_OTLP_INSECURE).
- If endpoint provided with option without scheme (e.g. `WithEndpoint`)
we can't use insecure connection with env settings.
- If endpoint provided with env variable without scheme (e.g.
`//env.endpoint:8080/`) we can't use insecure connection.

This commit fixes this.

The same problem with `otlploghttp.Exporter`, and probably it should be
fixed there too.
I'm open to suggestions on how to fix the current behavior in a more
elegant way.

---------

Co-authored-by: Sam Xie <sam@samxie.me>
Co-authored-by: Damien Mathieu <42@dmathieu.com>
This commit is contained in:
Anton Manakin 2024-09-06 16:48:45 +03:00 committed by GitHub
parent fb7cc020f2
commit 8dca9cc0fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 137 additions and 13 deletions

View File

@ -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)

View File

@ -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 {

View File

@ -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 {

View File

@ -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],