Skip to content

[confmap] - add a more targeted version of append-merging strategy #12926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 5, 2025
25 changes: 25 additions & 0 deletions .chloggen/confmap-append-merge-components.yaml
Original file line number Diff line number Diff line change
@@ -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: Update the behavior of the confmap.enableMergeAppendOption feature gate to merge only component lists.

# One or more tracking issues or pull requests related to the change
issues: [12926]

# (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: []
1 change: 1 addition & 0 deletions cmd/mdatagen/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ require (
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions cmd/mdatagen/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cmd/otelcorecol/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/google/uuid v1.6.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions cmd/otelcorecol/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions confmap/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.23.0

require (
github.com/go-viper/mapstructure/v2 v2.2.1
github.com/gobwas/glob v0.2.3
github.com/knadh/koanf/maps v0.1.2
github.com/knadh/koanf/providers/confmap v1.0.0
github.com/knadh/koanf/v2 v2.2.0
Expand Down
2 changes: 2 additions & 0 deletions confmap/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions confmap/internal/e2e/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/knadh/koanf/providers/confmap v1.0.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions confmap/internal/e2e/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 46 additions & 23 deletions confmap/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,70 @@ package confmap // import "go.opentelemetry.io/collector/confmap"

import (
"reflect"

"github.com/gobwas/glob"
"github.com/knadh/koanf/maps"
)

func mergeAppend(src, dest map[string]any) error {
// mergeAppend recursively merges the src map into the dest map (left to right),
// modifying and expanding the dest map in the process.
// This function does not overwrite lists, and ensures that the final value is a name-aware
// copy of lists from src and dest.
// This function does not overwrite component lists, and ensures that the
// final value is a name-aware copy of lists from src and dest.

for sKey, sVal := range src {
dVal, dOk := dest[sKey]
if !dOk {
// key is not present in destination config. Hence, add it to destination map
dest[sKey] = sVal
continue
// Compile the globs once
patterns := []string{
"service::extensions",
"service::**::receivers",
"service::**::exporters",
}
var globs []glob.Glob
for _, p := range patterns {
if g, err := glob.Compile(p); err == nil {
globs = append(globs, g)
}
}

srcVal := reflect.ValueOf(sVal)
destVal := reflect.ValueOf(dVal)
// Flatten both source and destination maps
srcFlat, _ := maps.Flatten(src, []string{}, KeyDelimiter)
destFlat, _ := maps.Flatten(dest, []string{}, KeyDelimiter)

if destVal.Kind() != srcVal.Kind() {
// different kinds. Override the destination map
dest[sKey] = sVal
for sKey, sVal := range srcFlat {
if !isMatch(sKey, globs) {
continue
}

switch srcVal.Kind() {
case reflect.Array, reflect.Slice:
// both of them are array. Merge them
dest[sKey] = mergeSlice(srcVal, destVal)
case reflect.Map:
// both of them are maps. Recursively call the mergeAppend
_ = mergeAppend(sVal.(map[string]any), dVal.(map[string]any))
default:
// any other datatype. Override the destination map
dest[sKey] = sVal
dVal, dOk := destFlat[sKey]
if !dOk {
continue // Let maps.Merge handle missing keys
}

srcVal := reflect.ValueOf(sVal)
destVal := reflect.ValueOf(dVal)

// Only merge if the value is a slice or array; let maps.Merge handle other types
if srcVal.Kind() == reflect.Slice || srcVal.Kind() == reflect.Array {
srcFlat[sKey] = mergeSlice(srcVal, destVal)
}
}

// Unflatten and merge
mergedSrc := maps.Unflatten(srcFlat, KeyDelimiter)
maps.Merge(mergedSrc, dest)

return nil
}

// isMatch checks if a key matches any glob in the list
func isMatch(key string, globs []glob.Glob) bool {
for _, g := range globs {
if g.Match(key) {
return true
}
}
return false
}

func mergeSlice(src, dest reflect.Value) any {
slice := reflect.MakeSlice(src.Type(), 0, src.Cap()+dest.Cap())
for i := 0; i < dest.Len(); i++ {
Expand Down
1 change: 1 addition & 0 deletions confmap/provider/envprovider/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/knadh/koanf/providers/confmap v1.0.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions confmap/provider/envprovider/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions confmap/provider/fileprovider/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/knadh/koanf/providers/confmap v1.0.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions confmap/provider/fileprovider/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions confmap/provider/httpprovider/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/knadh/koanf/providers/confmap v1.0.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions confmap/provider/httpprovider/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions confmap/provider/httpsprovider/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/knadh/koanf/providers/confmap v1.0.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions confmap/provider/httpsprovider/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions confmap/provider/yamlprovider/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/knadh/koanf/providers/confmap v1.0.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions confmap/provider/yamlprovider/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions confmap/testdata/config2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
service:
extensions: [nop2]
pipelines:
traces:
receivers: [nop2]
processors: [nop]
exporters: [nop2]
Loading
Loading