Skip to content

Commit

Permalink
config: add support for parsing env variables in configuration
Browse files Browse the repository at this point in the history
This replaces the last bit of functionality that was opened in open-telemetry#4826 to
support env variable replacement. Pulled the envprovider.go code from https://github.com/open-telemetry/opentelemetry-collector/blob/main/confmap/provider/envprovider/provider.go

Signed-off-by: Alex Boten <[email protected]>
  • Loading branch information
codeboten committed Nov 5, 2024
1 parent 488f482 commit 4eecb36
Show file tree
Hide file tree
Showing 4 changed files with 515 additions and 0 deletions.
15 changes: 15 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package config // import "go.opentelemetry.io/contrib/config"
import (
"context"
"errors"
"regexp"

"gopkg.in/yaml.v3"

Expand Down Expand Up @@ -139,6 +140,20 @@ func WithOpenTelemetryConfiguration(cfg OpenTelemetryConfiguration) Configuratio

// ParseYAML parses a YAML configuration file into an OpenTelemetryConfiguration.
func ParseYAML(file []byte) (*OpenTelemetryConfiguration, error) {
re := regexp.MustCompile(`\$\{([a-zA-Z_][a-zA-Z0-9_]*[-]?.*)\}`)

replaceEnvVars := func(input []byte) []byte {
return re.ReplaceAllFunc(input, func(s []byte) []byte {
match := re.FindSubmatch(s)
if len(match) < 2 {
return s
}
return replaceEnvVar(string(match[1]))
})
}

file = replaceEnvVars(file)

var cfg OpenTelemetryConfiguration
err := yaml.Unmarshal(file, &cfg)
if err != nil {
Expand Down
34 changes: 34 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,40 @@ func TestParseYAML(t *testing.T) {
}
}

func TestParseYAMLWithEnvironmentVariables(t *testing.T) {
tests := []struct {
name string
input string
wantErr error
wantType interface{}
}{
{
name: "valid v0.2 config with env vars",
input: "v0.2-env-var.yaml",
wantType: &v02OpenTelemetryConfig,
},
}

t.Setenv("OTEL_SDK_DISABLED", "false")
t.Setenv("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", "4096")
t.Setenv("OTEL_EXPORTER_OTLP_PROTOCOL", "http/protobuf")

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b, err := os.ReadFile(filepath.Join("testdata", tt.input))
require.NoError(t, err)

got, err := ParseYAML(b)
if tt.wantErr != nil {
require.Equal(t, tt.wantErr.Error(), err.Error())
} else {
require.NoError(t, err)
assert.Equal(t, tt.wantType, got)
}
})
}
}

func TestSerializeJSON(t *testing.T) {
tests := []struct {
name string
Expand Down
38 changes: 38 additions & 0 deletions config/envprovider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package config // import "go.opentelemetry.io/contrib/config"

import (
"os"
"regexp"
"strings"
)

const ValidationPattern = `^[a-zA-Z_][a-zA-Z0-9_]*$`

var validationRegexp = regexp.MustCompile(ValidationPattern)

func replaceEnvVar(uri string) []byte {
envVarName, defaultValuePtr := parseEnvVarURI(uri)
if !validationRegexp.MatchString(envVarName) {
return nil
}

val, exists := os.LookupEnv(envVarName)
if !exists {
if defaultValuePtr != nil {
val = *defaultValuePtr
}
}
return []byte(val)
}

func parseEnvVarURI(uri string) (string, *string) {
const defaultSuffix = ":-"
if strings.Contains(uri, defaultSuffix) {
parts := strings.SplitN(uri, defaultSuffix, 2)
return parts[0], &parts[1]
}
return uri, nil
}
Loading

0 comments on commit 4eecb36

Please sign in to comment.