From a2ae360d115888cf3ad4d056c01957651d466c5a Mon Sep 17 00:00:00 2001 From: Ben Carr Date: Mon, 15 Jan 2024 14:00:53 -0800 Subject: [PATCH 1/4] WIP: adds yaml parser and broken/WIP tests --- config/config.go | 12 +++++++++++- config/config_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 71daed46034..f94f28435c2 100644 --- a/config/config.go +++ b/config/config.go @@ -6,9 +6,11 @@ package config // import "go.opentelemetry.io/contrib/config" import ( "context" "errors" + "io" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" + "gopkg.in/yaml.v3" ) type configOptions struct { @@ -95,8 +97,16 @@ func WithOpenTelemetryConfiguration(cfg OpenTelemetryConfiguration) Configuratio }) } +func ParseYAML(r io.Reader) (*OpenTelemetryConfiguration, error) { + var cfg OpenTelemetryConfiguration + dec := yaml.NewDecoder(r) + if err := dec.Decode(&cfg); err != nil { + return nil, err + } + return &cfg, nil +} + // TODO: implement parsing functionality: -// - https://github.com/open-telemetry/opentelemetry-go-contrib/issues/4373 // - https://github.com/open-telemetry/opentelemetry-go-contrib/issues/4412 // TODO: create SDK from the model: diff --git a/config/config_test.go b/config/config_test.go index bbddf46d1da..c7d5ec02faa 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -5,6 +5,8 @@ package config import ( "context" + "fmt" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -51,3 +53,44 @@ func TestNewSDK(t *testing.T) { require.Equal(t, tt.wantShutdownErr, sdk.Shutdown(context.Background())) } } + +func TestParseYAML(t *testing.T) { + tests := []struct { + name string + input string + wantErr error + wantType interface{} + }{ + { + name: "valid YAML", + input: "file_format: yaml\ndisabled: false\n", + wantErr: nil, + wantType: &OpenTelemetryConfiguration{}, + }, + { + name: "invalid YAML", + input: "file_format: json\ndisabled:", + wantErr: yaml.ErrSyntax, + wantType: nil, + }, + { + name: "missing required field", + input: "foo: bar\n", + wantErr: fmt.Errorf("field file_format in OpenTelemetryConfiguration: required"), + wantType: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := strings.NewReader(tt.input) + got, err := ParseYAML(r) + if err != nil { + fmt.Println(err) + require.Equal(t, tt.wantErr.Error(), err.Error()) + } else { + assert.IsType(t, tt.wantType, got) + } + }) + } +} From 506e25015b643337d39863566ec1c5822cb1563e Mon Sep 17 00:00:00 2001 From: Ben Carr Date: Wed, 17 Jan 2024 17:50:28 -0800 Subject: [PATCH 2/4] Add regex to substitute environment variables --- config/config.go | 27 +++++++++++++++++++++++---- config/config_test.go | 15 +-------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/config/config.go b/config/config.go index f94f28435c2..fae44a426e7 100644 --- a/config/config.go +++ b/config/config.go @@ -6,7 +6,8 @@ package config // import "go.opentelemetry.io/contrib/config" import ( "context" "errors" - "io" + "os" + "regexp" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" @@ -97,12 +98,30 @@ func WithOpenTelemetryConfiguration(cfg OpenTelemetryConfiguration) Configuratio }) } -func ParseYAML(r io.Reader) (*OpenTelemetryConfiguration, error) { +// 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 + } + envVarName := string(match[1]) + envVarValue := os.Getenv(envVarName) + return []byte(envVarValue) + }) + } + + file = replaceEnvVars(file) + var cfg OpenTelemetryConfiguration - dec := yaml.NewDecoder(r) - if err := dec.Decode(&cfg); err != nil { + err := yaml.Unmarshal(file, &cfg) + if err != nil { return nil, err } + return &cfg, nil } diff --git a/config/config_test.go b/config/config_test.go index c7d5ec02faa..d32bf058709 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -6,7 +6,6 @@ package config import ( "context" "fmt" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -67,23 +66,11 @@ func TestParseYAML(t *testing.T) { wantErr: nil, wantType: &OpenTelemetryConfiguration{}, }, - { - name: "invalid YAML", - input: "file_format: json\ndisabled:", - wantErr: yaml.ErrSyntax, - wantType: nil, - }, - { - name: "missing required field", - input: "foo: bar\n", - wantErr: fmt.Errorf("field file_format in OpenTelemetryConfiguration: required"), - wantType: nil, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := strings.NewReader(tt.input) + r := ([]byte)(tt.input) got, err := ParseYAML(r) if err != nil { fmt.Println(err) From 5768acf7f55d163186944f6c8a31d0b9f586d638 Mon Sep 17 00:00:00 2001 From: Ben Carr Date: Mon, 15 Jan 2024 14:00:53 -0800 Subject: [PATCH 3/4] rebase fresh main --- config/config.go | 12 +++++++++++- config/config_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 9c182e0ff30..6a6dc8e0c98 100644 --- a/config/config.go +++ b/config/config.go @@ -6,11 +6,13 @@ package config // import "go.opentelemetry.io/contrib/config" import ( "context" "errors" + "io" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "go.opentelemetry.io/otel/trace" + "gopkg.in/yaml.v3" ) const ( @@ -113,8 +115,16 @@ func WithOpenTelemetryConfiguration(cfg OpenTelemetryConfiguration) Configuratio }) } +func ParseYAML(r io.Reader) (*OpenTelemetryConfiguration, error) { + var cfg OpenTelemetryConfiguration + dec := yaml.NewDecoder(r) + if err := dec.Decode(&cfg); err != nil { + return nil, err + } + return &cfg, nil +} + // TODO: implement parsing functionality: -// - https://github.com/open-telemetry/opentelemetry-go-contrib/issues/4373 // - https://github.com/open-telemetry/opentelemetry-go-contrib/issues/4412 // TODO: create SDK from the model: diff --git a/config/config_test.go b/config/config_test.go index f11917bddc6..338bacee4c5 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -5,6 +5,8 @@ package config import ( "context" + "fmt" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -55,3 +57,44 @@ func TestNewSDK(t *testing.T) { func ptr[T any](v T) *T { return &v } + +func TestParseYAML(t *testing.T) { + tests := []struct { + name string + input string + wantErr error + wantType interface{} + }{ + { + name: "valid YAML", + input: "file_format: yaml\ndisabled: false\n", + wantErr: nil, + wantType: &OpenTelemetryConfiguration{}, + }, + { + name: "invalid YAML", + input: "file_format: json\ndisabled:", + wantErr: yaml.ErrSyntax, + wantType: nil, + }, + { + name: "missing required field", + input: "foo: bar\n", + wantErr: fmt.Errorf("field file_format in OpenTelemetryConfiguration: required"), + wantType: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := strings.NewReader(tt.input) + got, err := ParseYAML(r) + if err != nil { + fmt.Println(err) + require.Equal(t, tt.wantErr.Error(), err.Error()) + } else { + assert.IsType(t, tt.wantType, got) + } + }) + } +} From 2ab60ecb8795dd35b30904c1d3eee5374a6350da Mon Sep 17 00:00:00 2001 From: Ben Carr Date: Wed, 17 Jan 2024 17:50:28 -0800 Subject: [PATCH 4/4] Add regex to substitute environment variables --- config/config.go | 27 +++++++++++++++++++++++---- config/config_test.go | 15 +-------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/config/config.go b/config/config.go index 6a6dc8e0c98..06fc372ccaf 100644 --- a/config/config.go +++ b/config/config.go @@ -6,7 +6,8 @@ package config // import "go.opentelemetry.io/contrib/config" import ( "context" "errors" - "io" + "os" + "regexp" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/sdk/resource" @@ -115,12 +116,30 @@ func WithOpenTelemetryConfiguration(cfg OpenTelemetryConfiguration) Configuratio }) } -func ParseYAML(r io.Reader) (*OpenTelemetryConfiguration, error) { +// 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 + } + envVarName := string(match[1]) + envVarValue := os.Getenv(envVarName) + return []byte(envVarValue) + }) + } + + file = replaceEnvVars(file) + var cfg OpenTelemetryConfiguration - dec := yaml.NewDecoder(r) - if err := dec.Decode(&cfg); err != nil { + err := yaml.Unmarshal(file, &cfg) + if err != nil { return nil, err } + return &cfg, nil } diff --git a/config/config_test.go b/config/config_test.go index 338bacee4c5..ad16764a2bc 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -6,7 +6,6 @@ package config import ( "context" "fmt" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -71,23 +70,11 @@ func TestParseYAML(t *testing.T) { wantErr: nil, wantType: &OpenTelemetryConfiguration{}, }, - { - name: "invalid YAML", - input: "file_format: json\ndisabled:", - wantErr: yaml.ErrSyntax, - wantType: nil, - }, - { - name: "missing required field", - input: "foo: bar\n", - wantErr: fmt.Errorf("field file_format in OpenTelemetryConfiguration: required"), - wantType: nil, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := strings.NewReader(tt.input) + r := ([]byte)(tt.input) got, err := ParseYAML(r) if err != nil { fmt.Println(err)