3
3
4
4
package component // import "go.opentelemetry.io/collector/component"
5
5
6
- import (
7
- "errors"
8
- "fmt"
9
- "reflect"
10
- "strconv"
11
- "strings"
12
- )
13
-
14
6
// Config defines the configuration for a component.Component.
15
7
//
16
8
// Implementations and/or any sub-configs (other types embedded or included in the Config implementation)
@@ -19,192 +11,3 @@ import (
19
11
//
20
12
// A valid implementation MUST pass the check componenttest.CheckConfigStruct (return nil error).
21
13
type Config any
22
-
23
- // As interface types are only used for static typing, a common idiom to find the reflection Type
24
- // for an interface type Foo is to use a *Foo value.
25
- var configValidatorType = reflect .TypeOf ((* ConfigValidator )(nil )).Elem ()
26
-
27
- // ConfigValidator defines an optional interface for configurations to implement to do validation.
28
- //
29
- // Deprecated: [v0.120.0] use xconfmap.Validator.
30
- type ConfigValidator interface {
31
- // Validate the configuration and returns an error if invalid.
32
- Validate () error
33
- }
34
-
35
- // ValidateConfig validates a config, by doing this:
36
- // - Call Validate on the config itself if the config implements ConfigValidator.
37
- //
38
- // Deprecated: [v0.120.0] use xconfmap.Validate.
39
- func ValidateConfig (cfg Config ) error {
40
- var err error
41
-
42
- for _ , validationErr := range validate (reflect .ValueOf (cfg )) {
43
- err = errors .Join (err , validationErr )
44
- }
45
-
46
- return err
47
- }
48
-
49
- type pathError struct {
50
- err error
51
- path []string
52
- }
53
-
54
- func (pe pathError ) Error () string {
55
- if len (pe .path ) > 0 {
56
- var path string
57
- sb := strings.Builder {}
58
-
59
- _ , _ = sb .WriteString (pe .path [len (pe .path )- 1 ])
60
- for i := len (pe .path ) - 2 ; i >= 0 ; i -- {
61
- _ , _ = sb .WriteString ("::" )
62
- _ , _ = sb .WriteString (pe .path [i ])
63
- }
64
- path = sb .String ()
65
-
66
- return fmt .Sprintf ("%s: %s" , path , pe .err )
67
- }
68
-
69
- return pe .err .Error ()
70
- }
71
-
72
- func (pe pathError ) Unwrap () error {
73
- return pe .err
74
- }
75
-
76
- func validate (v reflect.Value ) []pathError {
77
- errs := []pathError {}
78
- // Validate the value itself.
79
- switch v .Kind () {
80
- case reflect .Invalid :
81
- return nil
82
- case reflect .Ptr , reflect .Interface :
83
- return validate (v .Elem ())
84
- case reflect .Struct :
85
- err := callValidateIfPossible (v )
86
- if err != nil {
87
- errs = append (errs , pathError {err : err })
88
- }
89
-
90
- // Reflect on the pointed data and check each of its fields.
91
- for i := 0 ; i < v .NumField (); i ++ {
92
- if ! v .Type ().Field (i ).IsExported () {
93
- continue
94
- }
95
- field := v .Type ().Field (i )
96
- path := fieldName (field )
97
-
98
- subpathErrs := validate (v .Field (i ))
99
- for _ , err := range subpathErrs {
100
- errs = append (errs , pathError {
101
- err : err .err ,
102
- path : append (err .path , path ),
103
- })
104
- }
105
- }
106
- return errs
107
- case reflect .Slice , reflect .Array :
108
- err := callValidateIfPossible (v )
109
- if err != nil {
110
- errs = append (errs , pathError {err : err })
111
- }
112
-
113
- // Reflect on the pointed data and check each of its fields.
114
- for i := 0 ; i < v .Len (); i ++ {
115
- subPathErrs := validate (v .Index (i ))
116
-
117
- for _ , err := range subPathErrs {
118
- errs = append (errs , pathError {
119
- err : err .err ,
120
- path : append (err .path , strconv .Itoa (i )),
121
- })
122
- }
123
- }
124
- return errs
125
- case reflect .Map :
126
- err := callValidateIfPossible (v )
127
- if err != nil {
128
- errs = append (errs , pathError {err : err })
129
- }
130
-
131
- iter := v .MapRange ()
132
- for iter .Next () {
133
- keyErrs := validate (iter .Key ())
134
- valueErrs := validate (iter .Value ())
135
- key := stringifyMapKey (iter .Key ())
136
-
137
- for _ , err := range keyErrs {
138
- errs = append (errs , pathError {err : err .err , path : append (err .path , key )})
139
- }
140
-
141
- for _ , err := range valueErrs {
142
- errs = append (errs , pathError {err : err .err , path : append (err .path , key )})
143
- }
144
- }
145
- return errs
146
- default :
147
- err := callValidateIfPossible (v )
148
- if err != nil {
149
- return []pathError {{err : err }}
150
- }
151
-
152
- return nil
153
- }
154
- }
155
-
156
- func callValidateIfPossible (v reflect.Value ) error {
157
- // If the value type implements ConfigValidator just call Validate
158
- if v .Type ().Implements (configValidatorType ) {
159
- return v .Interface ().(ConfigValidator ).Validate ()
160
- }
161
-
162
- // If the pointer type implements ConfigValidator call Validate on the pointer to the current value.
163
- if reflect .PointerTo (v .Type ()).Implements (configValidatorType ) {
164
- // If not addressable, then create a new *V pointer and set the value to current v.
165
- if ! v .CanAddr () {
166
- pv := reflect .New (reflect .PointerTo (v .Type ()).Elem ())
167
- pv .Elem ().Set (v )
168
- v = pv .Elem ()
169
- }
170
- return v .Addr ().Interface ().(ConfigValidator ).Validate ()
171
- }
172
-
173
- return nil
174
- }
175
-
176
- func fieldName (field reflect.StructField ) string {
177
- var fieldName string
178
- if tag , ok := field .Tag .Lookup ("mapstructure" ); ok {
179
- tags := strings .Split (tag , "," )
180
- if len (tags ) > 0 {
181
- fieldName = tags [0 ]
182
- }
183
- }
184
- // Even if the mapstructure tag exists, the field name may not
185
- // be available, so set it if it is still blank.
186
- if len (fieldName ) == 0 {
187
- fieldName = strings .ToLower (field .Name )
188
- }
189
-
190
- return fieldName
191
- }
192
-
193
- func stringifyMapKey (val reflect.Value ) string {
194
- var key string
195
-
196
- if str , ok := val .Interface ().(string ); ok {
197
- key = str
198
- } else if stringer , ok := val .Interface ().(fmt.Stringer ); ok {
199
- key = stringer .String ()
200
- } else {
201
- switch val .Kind () {
202
- case reflect .Ptr , reflect .Interface , reflect .Struct , reflect .Slice , reflect .Array , reflect .Map :
203
- key = fmt .Sprintf ("[%T key]" , val .Interface ())
204
- default :
205
- key = fmt .Sprintf ("%v" , val .Interface ())
206
- }
207
- }
208
-
209
- return key
210
- }
0 commit comments