From 65dd4cdae2c15010aacf813d1894687d5f551348 Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Fri, 31 Jan 2025 11:51:15 -0500 Subject: [PATCH 1/8] [confmap] Add validation facilities from `component` --- .chloggen/create-confmap-validate.yaml | 25 ++ .chloggen/deprecate-component-validate.yaml | 25 ++ component/config.go | 6 +- confmap/config.go | 206 +++++++++++++ confmap/config_test.go | 321 ++++++++++++++++++++ confmap/confmap.go | 12 +- exporter/otlpexporter/config_test.go | 2 +- exporter/otlphttpexporter/config_test.go | 3 +- otelcol/collector.go | 4 +- otelcol/config_test.go | 3 +- otelcol/otelcoltest/config.go | 3 +- receiver/otlpreceiver/config_test.go | 4 +- service/config_test.go | 3 +- service/pipelines/config_test.go | 5 +- 14 files changed, 604 insertions(+), 18 deletions(-) create mode 100644 .chloggen/create-confmap-validate.yaml create mode 100644 .chloggen/deprecate-component-validate.yaml create mode 100644 confmap/config.go create mode 100644 confmap/config_test.go diff --git a/.chloggen/create-confmap-validate.yaml b/.chloggen/create-confmap-validate.yaml new file mode 100644 index 00000000000..4f7db5d142f --- /dev/null +++ b/.chloggen/create-confmap-validate.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: confmap + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Create the `Validator` interface and `Validate` function to facilitate config validation + +# One or more tracking issues or pull requests related to the change +issues: [11524] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/.chloggen/deprecate-component-validate.yaml b/.chloggen/deprecate-component-validate.yaml new file mode 100644 index 00000000000..33dcedbf2d5 --- /dev/null +++ b/.chloggen/deprecate-component-validate.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: deprecation + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: component + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Deprecate `ConfigValidator` and `ValidateConfig` + +# One or more tracking issues or pull requests related to the change +issues: [11524] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: Please use `Validator` and `Validate` respectively from `confmap`. + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/component/config.go b/component/config.go index a5862798fdd..f1517f031b8 100644 --- a/component/config.go +++ b/component/config.go @@ -14,7 +14,7 @@ import ( // Config defines the configuration for a component.Component. // // Implementations and/or any sub-configs (other types embedded or included in the Config implementation) -// MUST implement the ConfigValidator if any validation is required for that part of the configuration +// MUST implement confmap.Validator if any validation is required for that part of the configuration // (e.g. check if a required field is present). // // A valid implementation MUST pass the check componenttest.CheckConfigStruct (return nil error). @@ -25,6 +25,8 @@ type Config any var configValidatorType = reflect.TypeOf((*ConfigValidator)(nil)).Elem() // ConfigValidator defines an optional interface for configurations to implement to do validation. +// +// Deprecated: [v0.121.0] use confmap.Validator. type ConfigValidator interface { // Validate the configuration and returns an error if invalid. Validate() error @@ -32,6 +34,8 @@ type ConfigValidator interface { // ValidateConfig validates a config, by doing this: // - Call Validate on the config itself if the config implements ConfigValidator. +// +// Deprecated: [v0.121.0] use confmap.Validate. func ValidateConfig(cfg Config) error { var err error diff --git a/confmap/config.go b/confmap/config.go new file mode 100644 index 00000000000..9c8dec59fad --- /dev/null +++ b/confmap/config.go @@ -0,0 +1,206 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package confmap // import "go.opentelemetry.io/collector/confmap" + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "strings" +) + +// Config represents an interface for a configuration struct. +// +// Implementations and/or any sub-configs (other types embedded or included in the Config implementation) +// MUST implement the Validator if any validation is required for that part of the configuration +// (e.g. check if a required field is present). +// +// A valid implementation MUST pass the check componenttest.CheckConfigStruct (return nil error). +type Config any + +// As interface types are only used for static typing, a common idiom to find the reflection Type +// for an interface type Foo is to use a *Foo value. +var configValidatorType = reflect.TypeOf((*Validator)(nil)).Elem() + +// Validator defines an optional interface for configurations to implement to do validation. +type Validator interface { + // Validate the configuration and returns an error if invalid. + Validate() error +} + +// Validate validates a config, by doing this: +// - Call Validate on the config itself if the config implements ConfigValidator. +func Validate(cfg Config) error { + var err error + + for _, validationErr := range validate(reflect.ValueOf(cfg)) { + err = errors.Join(err, validationErr) + } + + return err +} + +type pathError struct { + err error + path []string +} + +func (pe pathError) Error() string { + if len(pe.path) > 0 { + var path string + sb := strings.Builder{} + + _, _ = sb.WriteString(pe.path[len(pe.path)-1]) + for i := len(pe.path) - 2; i >= 0; i-- { + _, _ = sb.WriteString(KeyDelimiter) + _, _ = sb.WriteString(pe.path[i]) + } + path = sb.String() + + return fmt.Sprintf("%s: %s", path, pe.err) + } + + return pe.err.Error() +} + +func (pe pathError) Unwrap() error { + return pe.err +} + +func validate(v reflect.Value) []pathError { + errs := []pathError{} + // Validate the value itself. + switch v.Kind() { + case reflect.Invalid: + return nil + case reflect.Ptr, reflect.Interface: + return validate(v.Elem()) + case reflect.Struct: + err := callValidateIfPossible(v) + if err != nil { + errs = append(errs, pathError{err: err}) + } + + // Reflect on the pointed data and check each of its fields. + for i := 0; i < v.NumField(); i++ { + if !v.Type().Field(i).IsExported() { + continue + } + field := v.Type().Field(i) + path := fieldName(field) + + subpathErrs := validate(v.Field(i)) + for _, err := range subpathErrs { + errs = append(errs, pathError{ + err: err.err, + path: append(err.path, path), + }) + } + } + return errs + case reflect.Slice, reflect.Array: + err := callValidateIfPossible(v) + if err != nil { + errs = append(errs, pathError{err: err}) + } + + // Reflect on the pointed data and check each of its fields. + for i := 0; i < v.Len(); i++ { + subPathErrs := validate(v.Index(i)) + + for _, err := range subPathErrs { + errs = append(errs, pathError{ + err: err.err, + path: append(err.path, strconv.Itoa(i)), + }) + } + } + return errs + case reflect.Map: + err := callValidateIfPossible(v) + if err != nil { + errs = append(errs, pathError{err: err}) + } + + iter := v.MapRange() + for iter.Next() { + keyErrs := validate(iter.Key()) + valueErrs := validate(iter.Value()) + key := stringifyMapKey(iter.Key()) + + for _, err := range keyErrs { + errs = append(errs, pathError{err: err.err, path: append(err.path, key)}) + } + + for _, err := range valueErrs { + errs = append(errs, pathError{err: err.err, path: append(err.path, key)}) + } + } + return errs + default: + err := callValidateIfPossible(v) + if err != nil { + return []pathError{{err: err}} + } + + return nil + } +} + +func callValidateIfPossible(v reflect.Value) error { + // If the value type implements ConfigValidator just call Validate + if v.Type().Implements(configValidatorType) { + return v.Interface().(Validator).Validate() + } + + // If the pointer type implements ConfigValidator call Validate on the pointer to the current value. + if reflect.PointerTo(v.Type()).Implements(configValidatorType) { + // If not addressable, then create a new *V pointer and set the value to current v. + if !v.CanAddr() { + pv := reflect.New(reflect.PointerTo(v.Type()).Elem()) + pv.Elem().Set(v) + v = pv.Elem() + } + return v.Addr().Interface().(Validator).Validate() + } + + return nil +} + +func fieldName(field reflect.StructField) string { + var fieldName string + if tag, ok := field.Tag.Lookup(mapstructureTag); ok { + tags := strings.Split(tag, ",") + if len(tags) > 0 { + fieldName = tags[0] + } + } + // Even if the mapstructure tag exists, the field name may not + // be available, so set it if it is still blank. + if len(fieldName) == 0 { + fieldName = strings.ToLower(field.Name) + } + + return fieldName +} + +func stringifyMapKey(val reflect.Value) string { + var key string + + if str, ok := val.Interface().(string); ok { + key = str + } else if stringer, ok := val.Interface().(fmt.Stringer); ok { + key = stringer.String() + } else { + switch val.Kind() { + case reflect.Ptr, reflect.Interface, reflect.Struct, reflect.Slice, reflect.Array, reflect.Map: + key = fmt.Sprintf("[%T key]", val.Interface()) + default: + key = fmt.Sprintf("%v", val.Interface()) + } + } + + return key +} diff --git a/confmap/config_test.go b/confmap/config_test.go new file mode 100644 index 00000000000..b830dbe65d6 --- /dev/null +++ b/confmap/config_test.go @@ -0,0 +1,321 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package confmap + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +type configChildStruct struct { + Child errValidateConfig + ChildPtr *errValidateConfig +} + +type configChildSlice struct { + Child []errValidateConfig + ChildPtr []*errValidateConfig +} + +type configChildMapValue struct { + Child map[string]errValidateConfig + ChildPtr map[string]*errValidateConfig +} + +type configChildMapKey struct { + Child map[errType]string + ChildPtr map[*errType]string +} + +type configChildTypeDef struct { + Child errType + ChildPtr *errType +} + +type configChildInterface struct { + Child Config +} + +type errValidateConfig struct { + err error +} + +func (e *errValidateConfig) Validate() error { + return e.err +} + +type errType string + +func (e errType) Validate() error { + if e == "" { + return nil + } + return errors.New(string(e)) +} + +func newErrType(etStr string) *errType { + et := errType(etStr) + return &et +} + +type errMapType map[string]string + +func (e errMapType) Validate() error { + return errors.New(e["err"]) +} + +type structKey struct { + k string + e error +} + +func (s structKey) String() string { + return s.k +} + +func (s structKey) Validate() error { + return s.e +} + +type configChildMapCustomKey struct { + Child map[structKey]errValidateConfig +} + +func newErrMapType() *errMapType { + et := errMapType(nil) + return &et +} + +type configMapstructure struct { + Valid *errValidateConfig `mapstructure:"validtag,omitempty"` + NoData *errValidateConfig `mapstructure:""` + NoName *errValidateConfig `mapstructure:",remain"` +} + +type configDeeplyNested struct { + MapKeyChild map[configChildStruct]string + MapValueChild map[string]configChildStruct + SliceChild []configChildSlice + MapIntKey map[int]errValidateConfig + MapFloatKey map[float64]errValidateConfig +} + +type sliceTypeAlias []configChildSlice + +func (sliceTypeAlias) Validate() error { + return errors.New("sliceTypeAlias error") +} + +func TestValidateConfig(t *testing.T) { + tests := []struct { + name string + cfg any + expected error + }{ + { + name: "struct", + cfg: errValidateConfig{err: errors.New("struct")}, + expected: errors.New("struct"), + }, + { + name: "pointer struct", + cfg: &errValidateConfig{err: errors.New("pointer struct")}, + expected: errors.New("pointer struct"), + }, + { + name: "type", + cfg: errType("type"), + expected: errors.New("type"), + }, + { + name: "pointer child", + cfg: newErrType("pointer type"), + expected: errors.New("pointer type"), + }, + { + name: "child interface with nil", + cfg: configChildInterface{}, + expected: nil, + }, + { + name: "pointer to child interface with nil", + cfg: &configChildInterface{}, + expected: nil, + }, + { + name: "nil", + cfg: nil, + expected: nil, + }, + { + name: "nil map type", + cfg: errMapType(nil), + expected: errors.New(""), + }, + { + name: "nil pointer map type", + cfg: newErrMapType(), + expected: errors.New(""), + }, + { + name: "child struct", + cfg: configChildStruct{Child: errValidateConfig{err: errors.New("child struct")}}, + expected: errors.New("child: child struct"), + }, + { + name: "pointer child struct", + cfg: &configChildStruct{Child: errValidateConfig{err: errors.New("pointer child struct")}}, + expected: errors.New("child: pointer child struct"), + }, + { + name: "child struct pointer", + cfg: &configChildStruct{ChildPtr: &errValidateConfig{err: errors.New("child struct pointer")}}, + expected: errors.New("childptr: child struct pointer"), + }, + { + name: "child interface", + cfg: configChildInterface{Child: errValidateConfig{err: errors.New("child interface")}}, + expected: errors.New("child: child interface"), + }, + { + name: "pointer to child interface", + cfg: &configChildInterface{Child: errValidateConfig{err: errors.New("pointer to child interface")}}, + expected: errors.New("child: pointer to child interface"), + }, + { + name: "child interface with pointer", + cfg: configChildInterface{Child: &errValidateConfig{err: errors.New("child interface with pointer")}}, + expected: errors.New("child: child interface with pointer"), + }, + { + name: "pointer to child interface with pointer", + cfg: &configChildInterface{Child: &errValidateConfig{err: errors.New("pointer to child interface with pointer")}}, + expected: errors.New("child: pointer to child interface with pointer"), + }, + { + name: "child slice", + cfg: configChildSlice{Child: []errValidateConfig{{}, {err: errors.New("child slice")}}}, + expected: errors.New("child::1: child slice"), + }, + { + name: "pointer child slice", + cfg: &configChildSlice{Child: []errValidateConfig{{}, {err: errors.New("pointer child slice")}}}, + expected: errors.New("child::1: pointer child slice"), + }, + { + name: "child slice pointer", + cfg: &configChildSlice{ChildPtr: []*errValidateConfig{{}, {err: errors.New("child slice pointer")}}}, + expected: errors.New("childptr::1: child slice pointer"), + }, + { + name: "child map value", + cfg: configChildMapValue{Child: map[string]errValidateConfig{"test": {err: errors.New("child map")}}}, + expected: errors.New("child::test: child map"), + }, + { + name: "pointer child map value", + cfg: &configChildMapValue{Child: map[string]errValidateConfig{"test": {err: errors.New("pointer child map")}}}, + expected: errors.New("child::test: pointer child map"), + }, + { + name: "child map value pointer", + cfg: &configChildMapValue{ChildPtr: map[string]*errValidateConfig{"test": {err: errors.New("child map pointer")}}}, + expected: errors.New("childptr::test: child map pointer"), + }, + { + name: "child map key", + cfg: configChildMapKey{Child: map[errType]string{"child_map_key": ""}}, + expected: errors.New("child::child_map_key: child_map_key"), + }, + { + name: "pointer child map key", + cfg: &configChildMapKey{Child: map[errType]string{"pointer_child_map_key": ""}}, + expected: errors.New("child::pointer_child_map_key: pointer_child_map_key"), + }, + { + name: "child map key pointer", + cfg: &configChildMapKey{ChildPtr: map[*errType]string{newErrType("child map key pointer"): ""}}, + expected: errors.New("childptr::[*confmap.errType key]: child map key pointer"), + }, + { + name: "map with stringified non-string key type", + cfg: &configChildMapCustomKey{Child: map[structKey]errValidateConfig{{k: "struct_key", e: errors.New("custom key error")}: {err: errors.New("value error")}}}, + expected: errors.New("child::struct_key: custom key error\nchild::struct_key: value error"), + }, + { + name: "child type", + cfg: configChildTypeDef{Child: "child type"}, + expected: errors.New("child: child type"), + }, + { + name: "pointer child type", + cfg: &configChildTypeDef{Child: "pointer child type"}, + expected: errors.New("child: pointer child type"), + }, + { + name: "child type pointer", + cfg: &configChildTypeDef{ChildPtr: newErrType("child type pointer")}, + expected: errors.New("childptr: child type pointer"), + }, + { + name: "valid mapstructure tag", + cfg: configMapstructure{Valid: &errValidateConfig{errors.New("test")}}, + expected: errors.New("validtag: test"), + }, + { + name: "zero-length mapstructure tag", + cfg: configMapstructure{NoData: &errValidateConfig{errors.New("test")}}, + expected: errors.New("nodata: test"), + }, + { + name: "no field name in mapstructure tag", + cfg: configMapstructure{NoName: &errValidateConfig{errors.New("test")}}, + expected: errors.New("noname: test"), + }, + { + name: "nested map key error", + cfg: configDeeplyNested{MapKeyChild: map[configChildStruct]string{{Child: errValidateConfig{err: errors.New("child key error")}}: "val"}}, + expected: errors.New("mapkeychild::[confmap.configChildStruct key]::child: child key error"), + }, + { + name: "nested map value error", + cfg: configDeeplyNested{MapValueChild: map[string]configChildStruct{"key": {Child: errValidateConfig{err: errors.New("child key error")}}}}, + expected: errors.New("mapvaluechild::key::child: child key error"), + }, + { + name: "nested slice value error", + cfg: configDeeplyNested{SliceChild: []configChildSlice{{Child: []errValidateConfig{{err: errors.New("child key error")}}}}}, + expected: errors.New("slicechild::0::child::0: child key error"), + }, + { + name: "nested map with int key", + cfg: configDeeplyNested{MapIntKey: map[int]errValidateConfig{1: {err: errors.New("int key error")}}}, + expected: errors.New("mapintkey::1: int key error"), + }, + { + name: "nested map with float key", + cfg: configDeeplyNested{MapFloatKey: map[float64]errValidateConfig{1.2: {err: errors.New("float key error")}}}, + expected: errors.New("mapfloatkey::1.2: float key error"), + }, + { + name: "slice type alias", + cfg: sliceTypeAlias{}, + expected: errors.New("sliceTypeAlias error"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := Validate(tt.cfg) + + if tt.expected != nil { + assert.EqualError(t, err, tt.expected.Error()) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/confmap/confmap.go b/confmap/confmap.go index aab1730687b..4481f77ec1e 100644 --- a/confmap/confmap.go +++ b/confmap/confmap.go @@ -24,6 +24,10 @@ const ( KeyDelimiter = "::" ) +const ( + mapstructureTag = "mapstructure" +) + // New creates a new empty confmap.Conf instance. func New() *Conf { return &Conf{k: koanf.New(KeyDelimiter)} @@ -79,7 +83,7 @@ func (fn unmarshalOptionFunc) apply(set *unmarshalOption) { // Unmarshal unmarshalls the config into a struct using the given options. // Tags on the fields of the structure must be properly set. -func (l *Conf) Unmarshal(result any, opts ...UnmarshalOption) error { +func (l *Conf) Unmarshal(result Config, opts ...UnmarshalOption) error { set := unmarshalOption{} for _, opt := range opts { opt.apply(&set) @@ -94,7 +98,7 @@ type MarshalOption interface { } // Marshal encodes the config and merges it into the Conf. -func (l *Conf) Marshal(rawVal any, _ ...MarshalOption) error { +func (l *Conf) Marshal(rawVal Config, _ ...MarshalOption) error { enc := encoder.New(encoderConfig(rawVal)) data, err := enc.Encode(rawVal) if err != nil { @@ -205,7 +209,7 @@ func decodeConfig(m *Conf, result any, errorUnused bool, skipTopLevelUnmarshaler dc := &mapstructure.DecoderConfig{ ErrorUnused: errorUnused, Result: result, - TagName: "mapstructure", + TagName: mapstructureTag, WeaklyTypedInput: false, MatchName: caseSensitiveMatchName, DecodeHook: mapstructure.ComposeDecodeHookFunc( @@ -407,7 +411,7 @@ func unmarshalerEmbeddedStructsHookFunc() mapstructure.DecodeHookFuncValue { for i := 0; i < to.Type().NumField(); i++ { // embedded structs passed in via `squash` cannot be pointers. We just check if they are structs: f := to.Type().Field(i) - if f.IsExported() && slices.Contains(strings.Split(f.Tag.Get("mapstructure"), ","), "squash") { + if f.IsExported() && slices.Contains(strings.Split(f.Tag.Get(mapstructureTag), ","), "squash") { if unmarshaler, ok := to.Field(i).Addr().Interface().(Unmarshaler); ok { c := NewFromStringMap(fromAsMap) c.skipTopLevelUnmarshaler = true diff --git a/exporter/otlpexporter/config_test.go b/exporter/otlpexporter/config_test.go index ae351535df8..c093c42aa96 100644 --- a/exporter/otlpexporter/config_test.go +++ b/exporter/otlpexporter/config_test.go @@ -136,7 +136,7 @@ func TestUnmarshalInvalidConfig(t *testing.T) { sub, err := cm.Sub(tt.name) require.NoError(t, err) assert.NoError(t, sub.Unmarshal(&cfg)) - assert.ErrorContains(t, component.ValidateConfig(cfg), tt.errorMsg) + assert.ErrorContains(t, confmap.Validate(cfg), tt.errorMsg) }) } } diff --git a/exporter/otlphttpexporter/config_test.go b/exporter/otlphttpexporter/config_test.go index e10f198960d..542f29e1299 100644 --- a/exporter/otlphttpexporter/config_test.go +++ b/exporter/otlphttpexporter/config_test.go @@ -12,7 +12,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configretry" @@ -28,7 +27,7 @@ func TestUnmarshalDefaultConfig(t *testing.T) { require.NoError(t, confmap.New().Unmarshal(&cfg)) assert.Equal(t, factory.CreateDefaultConfig(), cfg) // Default/Empty config is invalid. - assert.Error(t, component.ValidateConfig(cfg)) + assert.Error(t, confmap.Validate(cfg)) } func TestUnmarshalConfig(t *testing.T) { diff --git a/otelcol/collector.go b/otelcol/collector.go index a0b191053a1..e21b9966297 100644 --- a/otelcol/collector.go +++ b/otelcol/collector.go @@ -171,7 +171,7 @@ func (col *Collector) setupConfigurationComponents(ctx context.Context) error { return fmt.Errorf("failed to get config: %w", err) } - if err = component.ValidateConfig(cfg); err != nil { + if err = confmap.Validate(cfg); err != nil { return fmt.Errorf("invalid configuration: %w", err) } @@ -261,7 +261,7 @@ func (col *Collector) DryRun(ctx context.Context) error { return fmt.Errorf("failed to get config: %w", err) } - return component.ValidateConfig(cfg) + return confmap.Validate(cfg) } func newFallbackLogger(options []zap.Option) (*zap.Logger, error) { diff --git a/otelcol/config_test.go b/otelcol/config_test.go index e9c766fca0a..08b95a5f208 100644 --- a/otelcol/config_test.go +++ b/otelcol/config_test.go @@ -14,6 +14,7 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" + "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/service" "go.opentelemetry.io/collector/service/pipelines" @@ -241,7 +242,7 @@ func TestConfigValidate(t *testing.T) { for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfg := tt.cfgFn() - err := component.ValidateConfig(cfg) + err := confmap.Validate(cfg) if tt.expected != nil { assert.EqualError(t, err, tt.expected.Error()) } else { diff --git a/otelcol/otelcoltest/config.go b/otelcol/otelcoltest/config.go index 8e414829266..c2d549145cd 100644 --- a/otelcol/otelcoltest/config.go +++ b/otelcol/otelcoltest/config.go @@ -6,7 +6,6 @@ package otelcoltest // import "go.opentelemetry.io/collector/otelcol/otelcoltest import ( "context" - "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/provider/envprovider" "go.opentelemetry.io/collector/confmap/provider/fileprovider" @@ -41,5 +40,5 @@ func LoadConfigAndValidate(fileName string, factories otelcol.Factories) (*otelc if err != nil { return nil, err } - return cfg, component.ValidateConfig(cfg) + return cfg, confmap.Validate(cfg) } diff --git a/receiver/otlpreceiver/config_test.go b/receiver/otlpreceiver/config_test.go index dc00872dd29..b3bae8f6656 100644 --- a/receiver/otlpreceiver/config_test.go +++ b/receiver/otlpreceiver/config_test.go @@ -193,7 +193,7 @@ func TestUnmarshalConfigEmptyProtocols(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) - assert.EqualError(t, component.ValidateConfig(cfg), "must specify at least one protocol when using the OTLP receiver") + assert.EqualError(t, confmap.Validate(cfg), "must specify at least one protocol when using the OTLP receiver") } func TestUnmarshalConfigInvalidSignalPath(t *testing.T) { @@ -230,5 +230,5 @@ func TestUnmarshalConfigEmpty(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, confmap.New().Unmarshal(&cfg)) - assert.EqualError(t, component.ValidateConfig(cfg), "must specify at least one protocol when using the OTLP receiver") + assert.EqualError(t, confmap.Validate(cfg), "must specify at least one protocol when using the OTLP receiver") } diff --git a/service/config_test.go b/service/config_test.go index 8ce13a7ec33..d1ecc5f0aa0 100644 --- a/service/config_test.go +++ b/service/config_test.go @@ -13,6 +13,7 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" + "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/service/extensions" "go.opentelemetry.io/collector/service/pipelines" @@ -77,7 +78,7 @@ func TestConfigValidate(t *testing.T) { for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfg := tt.cfgFn() - err := component.ValidateConfig(cfg) + err := confmap.Validate(cfg) if tt.expected != nil { assert.ErrorContains(t, err, tt.expected.Error()) } else { diff --git a/service/pipelines/config_test.go b/service/pipelines/config_test.go index 19ca0be6d4a..3a535979df8 100644 --- a/service/pipelines/config_test.go +++ b/service/pipelines/config_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" @@ -108,9 +109,9 @@ func TestConfigValidate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { cfg := tt.cfgFn(t) if tt.expected != nil { - require.ErrorContains(t, component.ValidateConfig(cfg), tt.expected.Error()) + require.ErrorContains(t, confmap.Validate(cfg), tt.expected.Error()) } else { - require.NoError(t, component.ValidateConfig(cfg)) + require.NoError(t, confmap.Validate(cfg)) } // Clean up the profiles support gate, which may have been enabled in `cfgFn`. From 5a3cd5c75ded56ed4be20a6b33fb44cdbc11afa0 Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Tue, 4 Feb 2025 09:05:05 -0500 Subject: [PATCH 2/8] Address 2025-02-03 stability WG discussion --- .chloggen/create-confmap-validate.yaml | 6 ++--- component/config.go | 4 +-- confmap/confmap.go | 12 +++++---- confmap/{ => xconfmap}/config.go | 19 +++++-------- confmap/{ => xconfmap}/config_test.go | 6 +++-- confmap/xconfmap/go.mod | 24 +++++++++++++++++ confmap/xconfmap/go.sum | 37 ++++++++++++++++++++++++++ versions.yaml | 1 + 8 files changed, 84 insertions(+), 25 deletions(-) rename confmap/{ => xconfmap}/config.go (88%) rename confmap/{ => xconfmap}/config_test.go (99%) create mode 100644 confmap/xconfmap/go.mod create mode 100644 confmap/xconfmap/go.sum diff --git a/.chloggen/create-confmap-validate.yaml b/.chloggen/create-confmap-validate.yaml index 4f7db5d142f..b549b0cf984 100644 --- a/.chloggen/create-confmap-validate.yaml +++ b/.chloggen/create-confmap-validate.yaml @@ -1,13 +1,13 @@ # Use this changelog template to create an entry for release notes. # One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' -change_type: enhancement +change_type: new_component # The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) -component: confmap +component: xconfmap # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). -note: Create the `Validator` interface and `Validate` function to facilitate config validation +note: Create the xconfmap module and add the `Validator` interface and `Validate` function to facilitate config validation # One or more tracking issues or pull requests related to the change issues: [11524] diff --git a/component/config.go b/component/config.go index f1517f031b8..7d456d052be 100644 --- a/component/config.go +++ b/component/config.go @@ -26,7 +26,7 @@ var configValidatorType = reflect.TypeOf((*ConfigValidator)(nil)).Elem() // ConfigValidator defines an optional interface for configurations to implement to do validation. // -// Deprecated: [v0.121.0] use confmap.Validator. +// Deprecated: [v0.120.0] use xconfmap.Validator. type ConfigValidator interface { // Validate the configuration and returns an error if invalid. Validate() error @@ -35,7 +35,7 @@ type ConfigValidator interface { // ValidateConfig validates a config, by doing this: // - Call Validate on the config itself if the config implements ConfigValidator. // -// Deprecated: [v0.121.0] use confmap.Validate. +// Deprecated: [v0.120.0] use xconfmap.Validate. func ValidateConfig(cfg Config) error { var err error diff --git a/confmap/confmap.go b/confmap/confmap.go index 4481f77ec1e..b60634ade65 100644 --- a/confmap/confmap.go +++ b/confmap/confmap.go @@ -25,7 +25,9 @@ const ( ) const ( - mapstructureTag = "mapstructure" + // MapstructureTag is the struct field tag used to record marshaling/unmarshaling settings. + // See https://pkg.go.dev/github.com/go-viper/mapstructure/v2 for supported values. + MapstructureTag = "mapstructure" ) // New creates a new empty confmap.Conf instance. @@ -83,7 +85,7 @@ func (fn unmarshalOptionFunc) apply(set *unmarshalOption) { // Unmarshal unmarshalls the config into a struct using the given options. // Tags on the fields of the structure must be properly set. -func (l *Conf) Unmarshal(result Config, opts ...UnmarshalOption) error { +func (l *Conf) Unmarshal(result any, opts ...UnmarshalOption) error { set := unmarshalOption{} for _, opt := range opts { opt.apply(&set) @@ -98,7 +100,7 @@ type MarshalOption interface { } // Marshal encodes the config and merges it into the Conf. -func (l *Conf) Marshal(rawVal Config, _ ...MarshalOption) error { +func (l *Conf) Marshal(rawVal any, _ ...MarshalOption) error { enc := encoder.New(encoderConfig(rawVal)) data, err := enc.Encode(rawVal) if err != nil { @@ -209,7 +211,7 @@ func decodeConfig(m *Conf, result any, errorUnused bool, skipTopLevelUnmarshaler dc := &mapstructure.DecoderConfig{ ErrorUnused: errorUnused, Result: result, - TagName: mapstructureTag, + TagName: MapstructureTag, WeaklyTypedInput: false, MatchName: caseSensitiveMatchName, DecodeHook: mapstructure.ComposeDecodeHookFunc( @@ -411,7 +413,7 @@ func unmarshalerEmbeddedStructsHookFunc() mapstructure.DecodeHookFuncValue { for i := 0; i < to.Type().NumField(); i++ { // embedded structs passed in via `squash` cannot be pointers. We just check if they are structs: f := to.Type().Field(i) - if f.IsExported() && slices.Contains(strings.Split(f.Tag.Get(mapstructureTag), ","), "squash") { + if f.IsExported() && slices.Contains(strings.Split(f.Tag.Get(MapstructureTag), ","), "squash") { if unmarshaler, ok := to.Field(i).Addr().Interface().(Unmarshaler); ok { c := NewFromStringMap(fromAsMap) c.skipTopLevelUnmarshaler = true diff --git a/confmap/config.go b/confmap/xconfmap/config.go similarity index 88% rename from confmap/config.go rename to confmap/xconfmap/config.go index 9c8dec59fad..b9e8edbbaa5 100644 --- a/confmap/config.go +++ b/confmap/xconfmap/config.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package confmap // import "go.opentelemetry.io/collector/confmap" +package xconfmap // import "go.opentelemetry.io/collector/confmap/xconfmap" import ( "errors" @@ -9,16 +9,9 @@ import ( "reflect" "strconv" "strings" -) -// Config represents an interface for a configuration struct. -// -// Implementations and/or any sub-configs (other types embedded or included in the Config implementation) -// MUST implement the Validator if any validation is required for that part of the configuration -// (e.g. check if a required field is present). -// -// A valid implementation MUST pass the check componenttest.CheckConfigStruct (return nil error). -type Config any + "go.opentelemetry.io/collector/confmap" +) // As interface types are only used for static typing, a common idiom to find the reflection Type // for an interface type Foo is to use a *Foo value. @@ -32,7 +25,7 @@ type Validator interface { // Validate validates a config, by doing this: // - Call Validate on the config itself if the config implements ConfigValidator. -func Validate(cfg Config) error { +func Validate(cfg any) error { var err error for _, validationErr := range validate(reflect.ValueOf(cfg)) { @@ -54,7 +47,7 @@ func (pe pathError) Error() string { _, _ = sb.WriteString(pe.path[len(pe.path)-1]) for i := len(pe.path) - 2; i >= 0; i-- { - _, _ = sb.WriteString(KeyDelimiter) + _, _ = sb.WriteString(confmap.KeyDelimiter) _, _ = sb.WriteString(pe.path[i]) } path = sb.String() @@ -171,7 +164,7 @@ func callValidateIfPossible(v reflect.Value) error { func fieldName(field reflect.StructField) string { var fieldName string - if tag, ok := field.Tag.Lookup(mapstructureTag); ok { + if tag, ok := field.Tag.Lookup(confmap.MapstructureTag); ok { tags := strings.Split(tag, ",") if len(tags) > 0 { fieldName = tags[0] diff --git a/confmap/config_test.go b/confmap/xconfmap/config_test.go similarity index 99% rename from confmap/config_test.go rename to confmap/xconfmap/config_test.go index b830dbe65d6..7959608a581 100644 --- a/confmap/config_test.go +++ b/confmap/xconfmap/config_test.go @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -package confmap +package xconfmap import ( "errors" @@ -35,8 +35,10 @@ type configChildTypeDef struct { ChildPtr *errType } +type config any + type configChildInterface struct { - Child Config + Child config } type errValidateConfig struct { diff --git a/confmap/xconfmap/go.mod b/confmap/xconfmap/go.mod new file mode 100644 index 00000000000..4233d6c8f13 --- /dev/null +++ b/confmap/xconfmap/go.mod @@ -0,0 +1,24 @@ +module go.opentelemetry.io/collector/confmap/xconfmap + +go 1.23.3 + +require ( + github.com/stretchr/testify v1.10.0 + go.opentelemetry.io/collector/confmap v1.25.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/knadh/koanf/maps v0.1.1 // indirect + github.com/knadh/koanf/providers/confmap v0.1.0 // indirect + github.com/knadh/koanf/v2 v2.1.2 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace go.opentelemetry.io/collector/confmap => ../ diff --git a/confmap/xconfmap/go.sum b/confmap/xconfmap/go.sum new file mode 100644 index 00000000000..b05eacddb55 --- /dev/null +++ b/confmap/xconfmap/go.sum @@ -0,0 +1,37 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= +github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= +github.com/knadh/koanf/providers/confmap v0.1.0 h1:gOkxhHkemwG4LezxxN8DMOFopOPghxRVp7JbIvdvqzU= +github.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC7+fyHFdQkd697K4MdLnIU= +github.com/knadh/koanf/v2 v2.1.2 h1:I2rtLRqXRy1p01m/utEtpZSSA6dcJbgGVuE27kW2PzQ= +github.com/knadh/koanf/v2 v2.1.2/go.mod h1:Gphfaen0q1Fc1HTgJgSTC4oRX9R2R5ErYMZJy8fLJBo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/collector/confmap v1.25.0 h1:dLqd6hF4JqcDHl5GWWhc2jXsHs3hkq3KPvU/2Nw5aN4= +go.opentelemetry.io/collector/confmap v1.25.0/go.mod h1:Rrhs+MWoaP6AswZp+ReQ2VO9dfOfcUjdjiSHBsG+nec= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/versions.yaml b/versions.yaml index f75ea5c8c7a..b2482f5a1aa 100644 --- a/versions.yaml +++ b/versions.yaml @@ -32,6 +32,7 @@ module-sets: - go.opentelemetry.io/collector/component - go.opentelemetry.io/collector/component/componenttest - go.opentelemetry.io/collector/component/componentstatus + - go.opentelemetry.io/collector/confmap/xconfmap - go.opentelemetry.io/collector/config/configauth - go.opentelemetry.io/collector/config/configgrpc - go.opentelemetry.io/collector/config/confighttp From ceac11b30c220d7288cc11b9846752222c467c85 Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Tue, 4 Feb 2025 09:07:43 -0500 Subject: [PATCH 3/8] New module scaffolding --- confmap/xconfmap/Makefile | 1 + 1 file changed, 1 insertion(+) create mode 100644 confmap/xconfmap/Makefile diff --git a/confmap/xconfmap/Makefile b/confmap/xconfmap/Makefile new file mode 100644 index 00000000000..ded7a36092d --- /dev/null +++ b/confmap/xconfmap/Makefile @@ -0,0 +1 @@ +include ../../Makefile.Common From a1242777e5ebba659fed362cc0157d9bd5934628 Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Tue, 4 Feb 2025 09:09:08 -0500 Subject: [PATCH 4/8] Update changelogs --- .chloggen/create-confmap-validate.yaml | 2 +- .chloggen/deprecate-component-validate.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.chloggen/create-confmap-validate.yaml b/.chloggen/create-confmap-validate.yaml index b549b0cf984..bd195645a89 100644 --- a/.chloggen/create-confmap-validate.yaml +++ b/.chloggen/create-confmap-validate.yaml @@ -22,4 +22,4 @@ subtext: # Include 'user' if the change is relevant to end users. # Include 'api' if there is a change to a library API. # Default: '[user]' -change_logs: [] +change_logs: [api] diff --git a/.chloggen/deprecate-component-validate.yaml b/.chloggen/deprecate-component-validate.yaml index 33dcedbf2d5..d2da4e05266 100644 --- a/.chloggen/deprecate-component-validate.yaml +++ b/.chloggen/deprecate-component-validate.yaml @@ -15,11 +15,11 @@ issues: [11524] # (Optional) One or more lines of additional information to render under the primary note. # These lines will be padded with 2 spaces and then inserted directly into the document. # Use pipe (|) for multiline entries. -subtext: Please use `Validator` and `Validate` respectively from `confmap`. +subtext: Please use `Validator` and `Validate` respectively from `xconfmap`. # Optional: The change log or logs in which this entry should be included. # e.g. '[user]' or '[user, api]' # Include 'user' if the change is relevant to end users. # Include 'api' if there is a change to a library API. # Default: '[user]' -change_logs: [] +change_logs: [api] From a08428b56fcea7399d82d8bae5a5f41be366fe05 Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Tue, 4 Feb 2025 09:31:30 -0500 Subject: [PATCH 5/8] More new module changes --- cmd/builder/internal/builder/main_test.go | 1 + cmd/otelcorecol/builder-config.yaml | 1 + cmd/otelcorecol/go.mod | 3 +++ component/config.go | 2 +- confmap/xconfmap/go.mod | 2 +- confmap/xconfmap/go.sum | 2 -- exporter/otlpexporter/config_test.go | 3 ++- exporter/otlpexporter/go.mod | 3 +++ exporter/otlphttpexporter/config_test.go | 3 ++- exporter/otlphttpexporter/go.mod | 3 +++ internal/e2e/go.mod | 2 ++ otelcol/collector.go | 5 +++-- otelcol/config_test.go | 4 ++-- otelcol/go.mod | 3 +++ otelcol/otelcoltest/config.go | 2 +- otelcol/otelcoltest/go.mod | 3 +++ receiver/otlpreceiver/config_test.go | 5 +++-- receiver/otlpreceiver/go.mod | 3 +++ service/config_test.go | 4 ++-- service/go.mod | 3 +++ service/pipelines/config_test.go | 4 ++-- 21 files changed, 44 insertions(+), 17 deletions(-) diff --git a/cmd/builder/internal/builder/main_test.go b/cmd/builder/internal/builder/main_test.go index 41c06fea3bb..19cf5b2edc1 100644 --- a/cmd/builder/internal/builder/main_test.go +++ b/cmd/builder/internal/builder/main_test.go @@ -53,6 +53,7 @@ var replaceModules = []string{ "/config/configtelemetry", "/config/configtls", "/confmap", + "/confmap/xconfmap", "/confmap/provider/envprovider", "/confmap/provider/fileprovider", "/confmap/provider/httpprovider", diff --git a/cmd/otelcorecol/builder-config.yaml b/cmd/otelcorecol/builder-config.yaml index f98ba9eae43..cbb282e19eb 100644 --- a/cmd/otelcorecol/builder-config.yaml +++ b/cmd/otelcorecol/builder-config.yaml @@ -52,6 +52,7 @@ replaces: - go.opentelemetry.io/collector/config/configtelemetry => ../../config/configtelemetry - go.opentelemetry.io/collector/config/configtls => ../../config/configtls - go.opentelemetry.io/collector/confmap => ../../confmap + - go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap - go.opentelemetry.io/collector/confmap/provider/envprovider => ../../confmap/provider/envprovider - go.opentelemetry.io/collector/confmap/provider/fileprovider => ../../confmap/provider/fileprovider - go.opentelemetry.io/collector/confmap/provider/httpprovider => ../../confmap/provider/httpprovider diff --git a/cmd/otelcorecol/go.mod b/cmd/otelcorecol/go.mod index c06fb37dd90..faff81af7ef 100644 --- a/cmd/otelcorecol/go.mod +++ b/cmd/otelcorecol/go.mod @@ -93,6 +93,7 @@ require ( go.opentelemetry.io/collector/config/configretry v1.25.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.119.0 // indirect go.opentelemetry.io/collector/config/configtls v1.25.0 // indirect + go.opentelemetry.io/collector/confmap/xconfmap v0.0.0-00010101000000-000000000000 // indirect go.opentelemetry.io/collector/connector/connectortest v0.119.0 // indirect go.opentelemetry.io/collector/connector/xconnector v0.119.0 // indirect go.opentelemetry.io/collector/consumer v1.25.0 // indirect @@ -190,6 +191,8 @@ replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/confmap => ../../confmap +replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap + replace go.opentelemetry.io/collector/confmap/provider/envprovider => ../../confmap/provider/envprovider replace go.opentelemetry.io/collector/confmap/provider/fileprovider => ../../confmap/provider/fileprovider diff --git a/component/config.go b/component/config.go index 7d456d052be..6e5a785c349 100644 --- a/component/config.go +++ b/component/config.go @@ -14,7 +14,7 @@ import ( // Config defines the configuration for a component.Component. // // Implementations and/or any sub-configs (other types embedded or included in the Config implementation) -// MUST implement confmap.Validator if any validation is required for that part of the configuration +// MUST implement xconfmap.Validator if any validation is required for that part of the configuration // (e.g. check if a required field is present). // // A valid implementation MUST pass the check componenttest.CheckConfigStruct (return nil error). diff --git a/confmap/xconfmap/go.mod b/confmap/xconfmap/go.mod index 4233d6c8f13..4b6c8e836aa 100644 --- a/confmap/xconfmap/go.mod +++ b/confmap/xconfmap/go.mod @@ -1,6 +1,6 @@ module go.opentelemetry.io/collector/confmap/xconfmap -go 1.23.3 +go 1.22.0 require ( github.com/stretchr/testify v1.10.0 diff --git a/confmap/xconfmap/go.sum b/confmap/xconfmap/go.sum index b05eacddb55..7739cd77111 100644 --- a/confmap/xconfmap/go.sum +++ b/confmap/xconfmap/go.sum @@ -22,8 +22,6 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -go.opentelemetry.io/collector/confmap v1.25.0 h1:dLqd6hF4JqcDHl5GWWhc2jXsHs3hkq3KPvU/2Nw5aN4= -go.opentelemetry.io/collector/confmap v1.25.0/go.mod h1:Rrhs+MWoaP6AswZp+ReQ2VO9dfOfcUjdjiSHBsG+nec= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= diff --git a/exporter/otlpexporter/config_test.go b/exporter/otlpexporter/config_test.go index c093c42aa96..099d67958a4 100644 --- a/exporter/otlpexporter/config_test.go +++ b/exporter/otlpexporter/config_test.go @@ -19,6 +19,7 @@ import ( "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/exporter/exporterbatcher" "go.opentelemetry.io/collector/exporter/exporterhelper" ) @@ -136,7 +137,7 @@ func TestUnmarshalInvalidConfig(t *testing.T) { sub, err := cm.Sub(tt.name) require.NoError(t, err) assert.NoError(t, sub.Unmarshal(&cfg)) - assert.ErrorContains(t, confmap.Validate(cfg), tt.errorMsg) + assert.ErrorContains(t, xconfmap.Validate(cfg), tt.errorMsg) }) } } diff --git a/exporter/otlpexporter/go.mod b/exporter/otlpexporter/go.mod index fbf27246087..475c8dd2b3f 100644 --- a/exporter/otlpexporter/go.mod +++ b/exporter/otlpexporter/go.mod @@ -14,6 +14,7 @@ require ( go.opentelemetry.io/collector/config/configretry v1.25.0 go.opentelemetry.io/collector/config/configtls v1.25.0 go.opentelemetry.io/collector/confmap v1.25.0 + go.opentelemetry.io/collector/confmap/xconfmap v0.0.0-00010101000000-000000000000 go.opentelemetry.io/collector/consumer v1.25.0 go.opentelemetry.io/collector/consumer/consumererror v0.119.0 go.opentelemetry.io/collector/exporter v0.119.0 @@ -99,6 +100,8 @@ replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/confmap => ../../confmap +replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap + replace go.opentelemetry.io/collector/exporter => ../ replace go.opentelemetry.io/collector/extension => ../../extension diff --git a/exporter/otlphttpexporter/config_test.go b/exporter/otlphttpexporter/config_test.go index 542f29e1299..9d0c78a7d28 100644 --- a/exporter/otlphttpexporter/config_test.go +++ b/exporter/otlphttpexporter/config_test.go @@ -18,6 +18,7 @@ import ( "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/exporter/exporterhelper" ) @@ -27,7 +28,7 @@ func TestUnmarshalDefaultConfig(t *testing.T) { require.NoError(t, confmap.New().Unmarshal(&cfg)) assert.Equal(t, factory.CreateDefaultConfig(), cfg) // Default/Empty config is invalid. - assert.Error(t, confmap.Validate(cfg)) + assert.Error(t, xconfmap.Validate(cfg)) } func TestUnmarshalConfig(t *testing.T) { diff --git a/exporter/otlphttpexporter/go.mod b/exporter/otlphttpexporter/go.mod index 79b87864d46..c77da55a59f 100644 --- a/exporter/otlphttpexporter/go.mod +++ b/exporter/otlphttpexporter/go.mod @@ -13,6 +13,7 @@ require ( go.opentelemetry.io/collector/config/configretry v1.25.0 go.opentelemetry.io/collector/config/configtls v1.25.0 go.opentelemetry.io/collector/confmap v1.25.0 + go.opentelemetry.io/collector/confmap/xconfmap v0.0.0-00010101000000-000000000000 go.opentelemetry.io/collector/consumer v1.25.0 go.opentelemetry.io/collector/consumer/consumererror v0.119.0 go.opentelemetry.io/collector/exporter v0.119.0 @@ -101,6 +102,8 @@ replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/confmap => ../../confmap +replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap + replace go.opentelemetry.io/collector/exporter => ../ replace go.opentelemetry.io/collector/extension => ../../extension diff --git a/internal/e2e/go.mod b/internal/e2e/go.mod index 07447d0a7fc..a778424f711 100644 --- a/internal/e2e/go.mod +++ b/internal/e2e/go.mod @@ -177,6 +177,8 @@ replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/confmap => ../../confmap +replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap + replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest diff --git a/otelcol/collector.go b/otelcol/collector.go index e21b9966297..1c46be61819 100644 --- a/otelcol/collector.go +++ b/otelcol/collector.go @@ -21,6 +21,7 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" + "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/otelcol/internal/grpclog" "go.opentelemetry.io/collector/service" @@ -171,7 +172,7 @@ func (col *Collector) setupConfigurationComponents(ctx context.Context) error { return fmt.Errorf("failed to get config: %w", err) } - if err = confmap.Validate(cfg); err != nil { + if err = xconfmap.Validate(cfg); err != nil { return fmt.Errorf("invalid configuration: %w", err) } @@ -261,7 +262,7 @@ func (col *Collector) DryRun(ctx context.Context) error { return fmt.Errorf("failed to get config: %w", err) } - return confmap.Validate(cfg) + return xconfmap.Validate(cfg) } func newFallbackLogger(options []zap.Option) (*zap.Logger, error) { diff --git a/otelcol/config_test.go b/otelcol/config_test.go index 08b95a5f208..d9adc5ce5e7 100644 --- a/otelcol/config_test.go +++ b/otelcol/config_test.go @@ -14,7 +14,7 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" - "go.opentelemetry.io/collector/confmap" + "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/service" "go.opentelemetry.io/collector/service/pipelines" @@ -242,7 +242,7 @@ func TestConfigValidate(t *testing.T) { for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfg := tt.cfgFn() - err := confmap.Validate(cfg) + err := xconfmap.Validate(cfg) if tt.expected != nil { assert.EqualError(t, err, tt.expected.Error()) } else { diff --git a/otelcol/go.mod b/otelcol/go.mod index 06e5762c0f9..4be9a3d87fa 100644 --- a/otelcol/go.mod +++ b/otelcol/go.mod @@ -9,6 +9,7 @@ require ( go.opentelemetry.io/collector/component/componentstatus v0.119.0 go.opentelemetry.io/collector/config/configtelemetry v0.119.0 go.opentelemetry.io/collector/confmap v1.25.0 + go.opentelemetry.io/collector/confmap/xconfmap v0.0.0-00010101000000-000000000000 go.opentelemetry.io/collector/connector v0.119.0 go.opentelemetry.io/collector/connector/connectortest v0.119.0 go.opentelemetry.io/collector/exporter v0.119.0 @@ -141,6 +142,8 @@ replace go.opentelemetry.io/collector/exporter => ../exporter replace go.opentelemetry.io/collector/confmap => ../confmap +replace go.opentelemetry.io/collector/confmap/xconfmap => ../confmap/xconfmap + replace go.opentelemetry.io/collector/config/configtelemetry => ../config/configtelemetry replace go.opentelemetry.io/collector/processor => ../processor diff --git a/otelcol/otelcoltest/config.go b/otelcol/otelcoltest/config.go index c2d549145cd..47aeda2332e 100644 --- a/otelcol/otelcoltest/config.go +++ b/otelcol/otelcoltest/config.go @@ -40,5 +40,5 @@ func LoadConfigAndValidate(fileName string, factories otelcol.Factories) (*otelc if err != nil { return nil, err } - return cfg, confmap.Validate(cfg) + return cfg, xconfmap.Validate(cfg) } diff --git a/otelcol/otelcoltest/go.mod b/otelcol/otelcoltest/go.mod index 66904323ffd..6889cfbaf60 100644 --- a/otelcol/otelcoltest/go.mod +++ b/otelcol/otelcoltest/go.mod @@ -68,6 +68,7 @@ require ( go.opentelemetry.io/collector/component/componentstatus v0.119.0 // indirect go.opentelemetry.io/collector/component/componenttest v0.119.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.119.0 // indirect + go.opentelemetry.io/collector/confmap/xconfmap v0.0.0-00010101000000-000000000000 // indirect go.opentelemetry.io/collector/connector/xconnector v0.119.0 // indirect go.opentelemetry.io/collector/consumer v1.25.0 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.119.0 // indirect @@ -216,6 +217,8 @@ replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xe replace go.opentelemetry.io/collector/confmap => ../../confmap +replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap + replace go.opentelemetry.io/collector/processor/processortest => ../../processor/processortest replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata diff --git a/receiver/otlpreceiver/config_test.go b/receiver/otlpreceiver/config_test.go index b3bae8f6656..5261b60600a 100644 --- a/receiver/otlpreceiver/config_test.go +++ b/receiver/otlpreceiver/config_test.go @@ -19,6 +19,7 @@ import ( "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/confmap/xconfmap" ) func TestUnmarshalDefaultConfig(t *testing.T) { @@ -193,7 +194,7 @@ func TestUnmarshalConfigEmptyProtocols(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) - assert.EqualError(t, confmap.Validate(cfg), "must specify at least one protocol when using the OTLP receiver") + assert.EqualError(t, xconfmap.Validate(cfg), "must specify at least one protocol when using the OTLP receiver") } func TestUnmarshalConfigInvalidSignalPath(t *testing.T) { @@ -230,5 +231,5 @@ func TestUnmarshalConfigEmpty(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, confmap.New().Unmarshal(&cfg)) - assert.EqualError(t, confmap.Validate(cfg), "must specify at least one protocol when using the OTLP receiver") + assert.EqualError(t, xconfmap.Validate(cfg), "must specify at least one protocol when using the OTLP receiver") } diff --git a/receiver/otlpreceiver/go.mod b/receiver/otlpreceiver/go.mod index f6f19494d6c..a920315170d 100644 --- a/receiver/otlpreceiver/go.mod +++ b/receiver/otlpreceiver/go.mod @@ -16,6 +16,7 @@ require ( go.opentelemetry.io/collector/config/confignet v1.25.0 go.opentelemetry.io/collector/config/configtls v1.25.0 go.opentelemetry.io/collector/confmap v1.25.0 + go.opentelemetry.io/collector/confmap/xconfmap v0.0.0-00010101000000-000000000000 go.opentelemetry.io/collector/consumer v1.25.0 go.opentelemetry.io/collector/consumer/consumererror v0.119.0 go.opentelemetry.io/collector/consumer/consumertest v0.119.0 @@ -101,6 +102,8 @@ replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/confmap => ../../confmap +replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap + replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/extension/auth => ../../extension/auth diff --git a/service/config_test.go b/service/config_test.go index d1ecc5f0aa0..0032ac5d7eb 100644 --- a/service/config_test.go +++ b/service/config_test.go @@ -13,7 +13,7 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" - "go.opentelemetry.io/collector/confmap" + "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/service/extensions" "go.opentelemetry.io/collector/service/pipelines" @@ -78,7 +78,7 @@ func TestConfigValidate(t *testing.T) { for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfg := tt.cfgFn() - err := confmap.Validate(cfg) + err := xconfmap.Validate(cfg) if tt.expected != nil { assert.ErrorContains(t, err, tt.expected.Error()) } else { diff --git a/service/go.mod b/service/go.mod index d706b1de331..1a1a51b84e6 100644 --- a/service/go.mod +++ b/service/go.mod @@ -15,6 +15,7 @@ require ( go.opentelemetry.io/collector/config/confighttp v0.119.0 go.opentelemetry.io/collector/config/configtelemetry v0.119.0 go.opentelemetry.io/collector/confmap v1.25.0 + go.opentelemetry.io/collector/confmap/xconfmap v0.0.0-00010101000000-000000000000 go.opentelemetry.io/collector/connector v0.119.0 go.opentelemetry.io/collector/connector/connectortest v0.119.0 go.opentelemetry.io/collector/connector/xconnector v0.119.0 @@ -150,6 +151,8 @@ replace go.opentelemetry.io/collector/exporter => ../exporter replace go.opentelemetry.io/collector/confmap => ../confmap +replace go.opentelemetry.io/collector/confmap/xconfmap => ../confmap/xconfmap + replace go.opentelemetry.io/collector/config/configtelemetry => ../config/configtelemetry replace go.opentelemetry.io/collector/pipeline => ../pipeline diff --git a/service/pipelines/config_test.go b/service/pipelines/config_test.go index 3a535979df8..69ee8670e85 100644 --- a/service/pipelines/config_test.go +++ b/service/pipelines/config_test.go @@ -109,9 +109,9 @@ func TestConfigValidate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { cfg := tt.cfgFn(t) if tt.expected != nil { - require.ErrorContains(t, confmap.Validate(cfg), tt.expected.Error()) + require.ErrorContains(t, xconfmap.Validate(cfg), tt.expected.Error()) } else { - require.NoError(t, confmap.Validate(cfg)) + require.NoError(t, xconfmap.Validate(cfg)) } // Clean up the profiles support gate, which may have been enabled in `cfgFn`. From b3c61b07dc9a6f748422a9ea49977a7753d49f38 Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Tue, 4 Feb 2025 09:40:52 -0500 Subject: [PATCH 6/8] More fixes --- otelcol/otelcoltest/config.go | 1 + otelcol/otelcoltest/go.mod | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/otelcol/otelcoltest/config.go b/otelcol/otelcoltest/config.go index 47aeda2332e..55087dfda29 100644 --- a/otelcol/otelcoltest/config.go +++ b/otelcol/otelcoltest/config.go @@ -11,6 +11,7 @@ import ( "go.opentelemetry.io/collector/confmap/provider/fileprovider" "go.opentelemetry.io/collector/confmap/provider/httpprovider" "go.opentelemetry.io/collector/confmap/provider/yamlprovider" + "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/otelcol" ) diff --git a/otelcol/otelcoltest/go.mod b/otelcol/otelcoltest/go.mod index 6889cfbaf60..962abac247f 100644 --- a/otelcol/otelcoltest/go.mod +++ b/otelcol/otelcoltest/go.mod @@ -10,6 +10,7 @@ require ( go.opentelemetry.io/collector/confmap/provider/fileprovider v1.25.0 go.opentelemetry.io/collector/confmap/provider/httpprovider v1.25.0 go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.25.0 + go.opentelemetry.io/collector/confmap/xconfmap v0.0.0-00010101000000-000000000000 go.opentelemetry.io/collector/connector v0.119.0 go.opentelemetry.io/collector/connector/connectortest v0.119.0 go.opentelemetry.io/collector/exporter v0.119.0 @@ -68,7 +69,6 @@ require ( go.opentelemetry.io/collector/component/componentstatus v0.119.0 // indirect go.opentelemetry.io/collector/component/componenttest v0.119.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.119.0 // indirect - go.opentelemetry.io/collector/confmap/xconfmap v0.0.0-00010101000000-000000000000 // indirect go.opentelemetry.io/collector/connector/xconnector v0.119.0 // indirect go.opentelemetry.io/collector/consumer v1.25.0 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.119.0 // indirect From 0ebb797b4323a14cb5fba59220c45ff93f636b5b Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Tue, 4 Feb 2025 09:46:46 -0500 Subject: [PATCH 7/8] Fixup --- service/pipelines/config_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/pipelines/config_test.go b/service/pipelines/config_test.go index 69ee8670e85..c24f8c744c9 100644 --- a/service/pipelines/config_test.go +++ b/service/pipelines/config_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/confmap" + "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" From fed9c9959ca3eef049ea1313379e127c951203a9 Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Tue, 4 Feb 2025 10:00:23 -0500 Subject: [PATCH 8/8] Update tests --- confmap/xconfmap/config_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/confmap/xconfmap/config_test.go b/confmap/xconfmap/config_test.go index 7959608a581..0b45779d0fa 100644 --- a/confmap/xconfmap/config_test.go +++ b/confmap/xconfmap/config_test.go @@ -240,7 +240,7 @@ func TestValidateConfig(t *testing.T) { { name: "child map key pointer", cfg: &configChildMapKey{ChildPtr: map[*errType]string{newErrType("child map key pointer"): ""}}, - expected: errors.New("childptr::[*confmap.errType key]: child map key pointer"), + expected: errors.New("childptr::[*xconfmap.errType key]: child map key pointer"), }, { name: "map with stringified non-string key type", @@ -280,7 +280,7 @@ func TestValidateConfig(t *testing.T) { { name: "nested map key error", cfg: configDeeplyNested{MapKeyChild: map[configChildStruct]string{{Child: errValidateConfig{err: errors.New("child key error")}}: "val"}}, - expected: errors.New("mapkeychild::[confmap.configChildStruct key]::child: child key error"), + expected: errors.New("mapkeychild::[xconfmap.configChildStruct key]::child: child key error"), }, { name: "nested map value error",