forked from open-telemetry/opentelemetry-collector
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create configload.Parser struct to abstract away from Viper (open-tel…
…emetry#2728) * Make ConfigUnmarshaler use `map[string]interface{}` * Remove viper references on comments * Encapsulate in `Loader` struct This commit also moves the `ConfigUnmarshaler` and `CustomUnmarshaler` types into the config package, since otherwise an import cycle would happen. * Missing `config.NewLoader()` * Move `Loader` to `configload` package The `config` package indirectly depends on `exporterhelper`, so `Loader` can't be on it. * Empty commit to retrigger Github For some reason my commit is not showing up on the PR * Fix merge commit * More merge fixes * Address review comments - s/instanceg/instance - Add period at end of doc comments - Reword NewViper comment - Rename ViperDelimiter to KeyDelimiter * Rename from Loader to Parser * Add tests for `ToStringMap` and bring back old implementation * Revert changes on component/component.go and related changes This commit was done by running git diff origin/main component/component.go exporter/ extension/ \ internal/testcomponents/example_exporter.go processor/ receiver/ | git apply -R * Manual fixes after reverting component files * s/componentViperSection/componentSection/
- Loading branch information
Showing
12 changed files
with
251 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// package configload implements the configuration Parser. | ||
package configload | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/spf13/viper" | ||
) | ||
|
||
const ( | ||
// KeyDelimiter is used as the default key delimiter in the default viper instance. | ||
KeyDelimiter = "::" | ||
) | ||
|
||
// NewViper creates a new Viper instance with key delimiter KeyDelimiter instead of the | ||
// default ".". This way configs can have keys that contain ".". | ||
func NewViper() *viper.Viper { | ||
return viper.NewWithOptions(viper.KeyDelimiter(KeyDelimiter)) | ||
} | ||
|
||
// NewParser creates a new Parser instance. | ||
func NewParser() *Parser { | ||
return &Parser{ | ||
v: NewViper(), | ||
} | ||
} | ||
|
||
// FromViper creates a Parser from a Viper instance. | ||
func FromViper(v *viper.Viper) *Parser { | ||
return &Parser{v: v} | ||
} | ||
|
||
// Parser loads configuration. | ||
type Parser struct { | ||
v *viper.Viper | ||
} | ||
|
||
// Viper returns the underlying Viper instance. | ||
func (l *Parser) Viper() *viper.Viper { | ||
return l.v | ||
} | ||
|
||
// UnmarshalExact unmarshals the config into a struct, erroring if a field is nonexistent. | ||
func (l *Parser) UnmarshalExact(intoCfg interface{}) error { | ||
return l.v.UnmarshalExact(intoCfg) | ||
} | ||
|
||
// deepSearch scans deep maps, following the key indexes listed in the | ||
// sequence "path". | ||
// The last value is expected to be another map, and is returned. | ||
// | ||
// In case intermediate keys do not exist, or map to a non-map value, | ||
// a new map is created and inserted, and the search continues from there: | ||
// the initial map "m" may be modified! | ||
// This function comes from Viper code https://github.com/spf13/viper/blob/5253694/util.go#L201-L230 | ||
// It is used here because of https://github.com/spf13/viper/issues/819 | ||
func deepSearch(m map[string]interface{}, path []string) map[string]interface{} { | ||
for _, k := range path { | ||
m2, ok := m[k] | ||
if !ok { | ||
// intermediate key does not exist | ||
// => create it and continue from there | ||
m3 := make(map[string]interface{}) | ||
m[k] = m3 | ||
m = m3 | ||
continue | ||
} | ||
m3, ok := m2.(map[string]interface{}) | ||
if !ok { | ||
// intermediate key is a value | ||
// => replace with a new map | ||
m3 = make(map[string]interface{}) | ||
m[k] = m3 | ||
} | ||
// continue search from here | ||
m = m3 | ||
} | ||
return m | ||
} | ||
|
||
// ToStringMap creates a map[string]interface{} from a Parser. | ||
func (l *Parser) ToStringMap() map[string]interface{} { | ||
// This is equivalent to l.v.AllSettings() but it maps nil values | ||
// We can't use AllSettings here because of https://github.com/spf13/viper/issues/819 | ||
|
||
m := map[string]interface{}{} | ||
// start from the list of keys, and construct the map one value at a time | ||
for _, k := range l.v.AllKeys() { | ||
value := l.v.Get(k) | ||
path := strings.Split(k, KeyDelimiter) | ||
lastKey := strings.ToLower(path[len(path)-1]) | ||
deepestMap := deepSearch(m, path[0:len(path)-1]) | ||
// set innermost value | ||
deepestMap[lastKey] = value | ||
} | ||
return m | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package configload | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestToStringMap(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
fileName string | ||
stringMap map[string]interface{} | ||
}{ | ||
{ | ||
name: "Sample Collector configuration", | ||
fileName: "testdata/config.yaml", | ||
stringMap: map[string]interface{}{ | ||
"receivers": map[string]interface{}{ | ||
"nop": nil, | ||
"nop/myreceiver": nil, | ||
}, | ||
|
||
"processors": map[string]interface{}{ | ||
"nop": nil, | ||
"nop/myprocessor": nil, | ||
}, | ||
|
||
"exporters": map[string]interface{}{ | ||
"nop": nil, | ||
"nop/myexporter": nil, | ||
}, | ||
|
||
"extensions": map[string]interface{}{ | ||
"nop": nil, | ||
"nop/myextension": nil, | ||
}, | ||
|
||
"service": map[string]interface{}{ | ||
"extensions": []interface{}{"nop"}, | ||
"pipelines": map[string]interface{}{ | ||
"traces": map[string]interface{}{ | ||
"receivers": []interface{}{"nop"}, | ||
"processors": []interface{}{"nop"}, | ||
"exporters": []interface{}{"nop"}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "Sample types", | ||
fileName: "testdata/basic_types.yaml", | ||
stringMap: map[string]interface{}{ | ||
"typed.options": map[string]interface{}{ | ||
"floating.point.example": 3.14, | ||
"integer.example": 1234, | ||
"bool.example": false, | ||
"string.example": "this is a string", | ||
}, | ||
}, | ||
}, | ||
} | ||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
v := NewViper() | ||
v.SetConfigFile(test.fileName) | ||
require.NoError(t, v.ReadInConfig(), "Unable to read configuration file '%s'", test.fileName) | ||
parser := FromViper(v) | ||
assert.Equal(t, test.stringMap, parser.ToStringMap()) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
typed.options: | ||
floating.point.example: 3.14 | ||
integer.example: 1234 | ||
bool.example: no | ||
string.example: this is a string |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
receivers: | ||
nop: | ||
nop/myreceiver: | ||
|
||
processors: | ||
nop: | ||
nop/myprocessor: | ||
|
||
exporters: | ||
nop: | ||
nop/myexporter: | ||
|
||
extensions: | ||
nop: | ||
nop/myextension: | ||
|
||
service: | ||
extensions: [nop] | ||
pipelines: | ||
traces: | ||
receivers: [nop] | ||
processors: [nop] | ||
exporters: [nop] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.