@@ -17,6 +17,7 @@ import (
1717 "context"
1818 "fmt"
1919
20+ "github.com/mitchellh/mapstructure"
2021 "github.com/prometheus/client_golang/prometheus"
2122 "go.opentelemetry.io/collector/component"
2223 "go.opentelemetry.io/collector/consumer"
@@ -30,21 +31,21 @@ type ExporterInitializer interface {
3031 // containing all the metrics collectors.
3132 Initialize (ctx context.Context , exporterConfig Config ) (* prometheus.Registry , error )
3233
33- // Shutdown cleanly stops the exporter and releases resources .
34+ // Shutdown is used to release resources when the receiver is shutting down .
3435 Shutdown (ctx context.Context ) error
3536}
3637
37- // ConfigUnmarshaler is the interface for unmarshaling exporter-specific configuration.
38+ // ConfigUnmarshaler is the interface used to unmarshal the exporter-specific
39+ // configuration using mapstructure and struct tags.
3840type ConfigUnmarshaler interface {
39- // UnmarshalExporterConfig parses the exporter-specific configuration
40- // from the raw map into a Config instance .
41- UnmarshalExporterConfig ( data map [ string ] interface {}) ( Config , error )
41+ // GetConfigStruct returns a pointer to the config struct that mapstructure
42+ // will populate. The struct should have appropriate mapstructure tags .
43+ GetConfigStruct () Config
4244}
4345
4446// FactoryOption is a function that configures a Factory.
4547type FactoryOption func (* factoryConfig )
4648
47- // factoryConfig holds the configuration for creating a receiver factory.
4849type factoryConfig struct {
4950 typeStr component.Type
5051 initializer ExporterInitializer
@@ -73,6 +74,7 @@ func WithConfigUnmarshaler(unmarshaler ConfigUnmarshaler) FactoryOption {
7374 }
7475}
7576
77+ // WithComponentDefaults sets the default configuration for the component.
7678func WithComponentDefaults (defaults map [string ]interface {}) FactoryOption {
7779 return func (cfg * factoryConfig ) {
7880 cfg .defaultConfig = defaults
@@ -114,7 +116,6 @@ func NewFactory(opts ...FactoryOption) receiver.Factory {
114116 )
115117}
116118
117- // createMetricsReceiver returns a function that creates a metrics receiver instance.
118119func createMetricsReceiver (
119120 initializer ExporterInitializer ,
120121 unmarshaler ConfigUnmarshaler ,
@@ -130,21 +131,29 @@ func createMetricsReceiver(
130131 return nil , fmt .Errorf ("invalid config type: %T" , cfg )
131132 }
132133
133- // Unmarshal the exporter-specific config
134134 if len (receiverCfg .ExporterConfig ) > 0 {
135- exporterCfg , err := unmarshaler .UnmarshalExporterConfig (receiverCfg .ExporterConfig )
135+ exporterCfg := unmarshaler .GetConfigStruct ()
136+ decoder , err := mapstructure .NewDecoder (& mapstructure.DecoderConfig {
137+ Result : exporterCfg ,
138+ ErrorUnused : true , // Reject unknown fields
139+ WeaklyTypedInput : false , // Strict type checking
140+ TagName : "mapstructure" ,
141+ })
136142 if err != nil {
137- return nil , fmt .Errorf ("failed to unmarshal exporter config : %w" , err )
143+ return nil , fmt .Errorf ("failed to create decoder : %w" , err )
138144 }
145+
146+ if err = decoder .Decode (receiverCfg .ExporterConfig ); err != nil {
147+ return nil , fmt .Errorf ("configuration validation failed: %w" , err )
148+ }
149+
139150 receiverCfg .SetExporterConfig (exporterCfg )
140151 }
141152
142- // Validate the complete configuration
143153 if err := receiverCfg .Validate (); err != nil {
144154 return nil , fmt .Errorf ("invalid configuration: %w" , err )
145155 }
146156
147- // Create the receiver instance
148157 return newPrometheusReceiver (
149158 receiverCfg ,
150159 consumer ,
0 commit comments