@@ -7,17 +7,23 @@ import (
7
7
"path/filepath"
8
8
"strings"
9
9
10
+ "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi"
11
+
10
12
"github.com/aws/aws-sdk-go-v2/service/cloudwatch"
11
13
"github.com/aws/aws-sdk-go-v2/service/ec2"
12
14
"github.com/aws/aws-sdk-go-v2/service/rds"
13
15
"github.com/aws/aws-sdk-go-v2/service/servicequotas"
16
+ "github.com/knadh/koanf/parsers/yaml"
17
+ "github.com/knadh/koanf/providers/env"
18
+ "github.com/knadh/koanf/providers/file"
19
+ "github.com/knadh/koanf/providers/posflag"
20
+ "github.com/knadh/koanf/v2"
14
21
"github.com/prometheus/client_golang/prometheus"
15
22
"github.com/qonto/prometheus-rds-exporter/internal/app/exporter"
16
23
"github.com/qonto/prometheus-rds-exporter/internal/infra/build"
17
24
"github.com/qonto/prometheus-rds-exporter/internal/infra/http"
18
25
"github.com/qonto/prometheus-rds-exporter/internal/infra/logger"
19
26
"github.com/spf13/cobra"
20
- "github.com/spf13/viper"
21
27
)
22
28
23
29
const (
@@ -27,25 +33,29 @@ const (
27
33
awsErrorExitCode = 4
28
34
)
29
35
30
- var cfgFile string
36
+ var (
37
+ cfgFile string
38
+ k = koanf .New ("." )
39
+ )
31
40
32
41
type exporterConfig struct {
33
- Debug bool `mapstructure:"debug"`
34
- LogFormat string `mapstructure:"log-format"`
35
- TLSCertPath string `mapstructure:"tls-cert-path"`
36
- TLSKeyPath string `mapstructure:"tls-key-path"`
37
- MetricPath string `mapstructure:"metrics-path"`
38
- ListenAddress string `mapstructure:"listen-address"`
39
- AWSAssumeRoleSession string `mapstructure:"aws-assume-role-session"`
40
- AWSAssumeRoleArn string `mapstructure:"aws-assume-role-arn"`
41
- CollectInstanceMetrics bool `mapstructure:"collect-instance-metrics"`
42
- CollectInstanceTags bool `mapstructure:"collect-instance-tags"`
43
- CollectInstanceTypes bool `mapstructure:"collect-instance-types"`
44
- CollectLogsSize bool `mapstructure:"collect-logs-size"`
45
- CollectMaintenances bool `mapstructure:"collect-maintenances"`
46
- CollectQuotas bool `mapstructure:"collect-quotas"`
47
- CollectUsages bool `mapstructure:"collect-usages"`
48
- OTELTracesEnabled bool `mapstructure:"enable-otel-traces"`
42
+ Debug bool `koanf:"debug"`
43
+ LogFormat string `koanf:"log-format"`
44
+ TLSCertPath string `koanf:"tls-cert-path"`
45
+ TLSKeyPath string `koanf:"tls-key-path"`
46
+ MetricPath string `koanf:"metrics-path"`
47
+ ListenAddress string `koanf:"listen-address"`
48
+ AWSAssumeRoleSession string `koanf:"aws-assume-role-session"`
49
+ AWSAssumeRoleArn string `koanf:"aws-assume-role-arn"`
50
+ CollectInstanceMetrics bool `koanf:"collect-instance-metrics"`
51
+ CollectInstanceTags bool `koanf:"collect-instance-tags"`
52
+ CollectInstanceTypes bool `koanf:"collect-instance-types"`
53
+ CollectLogsSize bool `koanf:"collect-logs-size"`
54
+ CollectMaintenances bool `koanf:"collect-maintenances"`
55
+ CollectQuotas bool `koanf:"collect-quotas"`
56
+ CollectUsages bool `koanf:"collect-usages"`
57
+ OTELTracesEnabled bool `koanf:"enable-otel-traces"`
58
+ TagSelections map [string ][]string `koanf:"tag-selections"`
49
59
}
50
60
51
61
func run (configuration exporterConfig ) {
@@ -55,6 +65,8 @@ func run(configuration exporterConfig) {
55
65
panic (err )
56
66
}
57
67
68
+ logger .Debug (fmt .Sprintf ("Config: %+v\n " , configuration ))
69
+
58
70
cfg , err := getAWSConfiguration (logger , configuration .AWSAssumeRoleArn , configuration .AWSAssumeRoleSession )
59
71
if err != nil {
60
72
logger .Error ("can't initialize AWS configuration" , "reason" , err )
@@ -68,6 +80,13 @@ func run(configuration exporterConfig) {
68
80
}
69
81
70
82
rdsClient := rds .NewFromConfig (cfg )
83
+
84
+ var tagClient * resourcegroupstaggingapi.Client
85
+
86
+ if configuration .TagSelections != nil {
87
+ tagClient = resourcegroupstaggingapi .NewFromConfig (cfg )
88
+ }
89
+
71
90
ec2Client := ec2 .NewFromConfig (cfg )
72
91
cloudWatchClient := cloudwatch .NewFromConfig (cfg )
73
92
servicequotasClient := servicequotas .NewFromConfig (cfg )
@@ -80,9 +99,10 @@ func run(configuration exporterConfig) {
80
99
CollectMaintenances : configuration .CollectMaintenances ,
81
100
CollectQuotas : configuration .CollectQuotas ,
82
101
CollectUsages : configuration .CollectUsages ,
102
+ TagSelections : configuration .TagSelections ,
83
103
}
84
104
85
- collector := exporter .NewCollector (* logger , collectorConfiguration , awsAccountID , awsRegion , rdsClient , ec2Client , cloudWatchClient , servicequotasClient )
105
+ collector := exporter .NewCollector (* logger , collectorConfiguration , awsAccountID , awsRegion , rdsClient , ec2Client , cloudWatchClient , servicequotasClient , tagClient )
86
106
87
107
prometheus .MustRegister (collector )
88
108
@@ -111,10 +131,16 @@ func NewRootCommand() (*cobra.Command, error) {
111
131
Long : `Collect AWS RDS key metrics from AWS APIs
112
132
and expose them as Prometheus metrics.` ,
113
133
Run : func (cmd * cobra.Command , args []string ) {
114
- var c exporterConfig
115
- err := viper .Unmarshal (& c )
134
+ err := k .Load (posflag .Provider (cmd .Flags (), "." , k ), nil )
116
135
if err != nil {
117
- fmt .Println ("ERROR: Unable to decode configuration, %w" , err )
136
+ fmt .Printf ("ERROR: Unable to interpret flags, %v\n " , err )
137
+
138
+ return
139
+ }
140
+
141
+ var c exporterConfig
142
+ if err := k .Unmarshal ("" , & c ); err != nil {
143
+ fmt .Printf ("ERROR: Unable to decode configuration, %v\n " , err )
118
144
119
145
return
120
146
}
@@ -142,86 +168,6 @@ func NewRootCommand() (*cobra.Command, error) {
142
168
cmd .Flags ().BoolP ("collect-quotas" , "" , true , "Collect AWS RDS quotas" )
143
169
cmd .Flags ().BoolP ("collect-usages" , "" , true , "Collect AWS RDS usages" )
144
170
145
- err := viper .BindPFlag ("debug" , cmd .Flags ().Lookup ("debug" ))
146
- if err != nil {
147
- return cmd , fmt .Errorf ("failed to bind 'debug' parameter: %w" , err )
148
- }
149
-
150
- err = viper .BindPFlag ("log-format" , cmd .Flags ().Lookup ("log-format" ))
151
- if err != nil {
152
- return cmd , fmt .Errorf ("failed to bind 'log-format' parameter: %w" , err )
153
- }
154
-
155
- err = viper .BindPFlag ("enable-otel-traces" , cmd .Flags ().Lookup ("enable-otel-traces" ))
156
- if err != nil {
157
- return cmd , fmt .Errorf ("failed to bind 'enable-otel-traces' parameter: %w" , err )
158
- }
159
-
160
- err = viper .BindPFlag ("metrics-path" , cmd .Flags ().Lookup ("metrics-path" ))
161
- if err != nil {
162
- return cmd , fmt .Errorf ("failed to bind 'metrics-path' parameter: %w" , err )
163
- }
164
-
165
- err = viper .BindPFlag ("tls-cert-path" , cmd .Flags ().Lookup ("tls-cert-path" ))
166
- if err != nil {
167
- return cmd , fmt .Errorf ("failed to bind 'tls-cert-path' parameter: %w" , err )
168
- }
169
-
170
- err = viper .BindPFlag ("tls-key-path" , cmd .Flags ().Lookup ("tls-key-path" ))
171
- if err != nil {
172
- return cmd , fmt .Errorf ("failed to bind 'tls-key-path' parameter: %w" , err )
173
- }
174
-
175
- err = viper .BindPFlag ("listen-address" , cmd .Flags ().Lookup ("listen-address" ))
176
- if err != nil {
177
- return cmd , fmt .Errorf ("failed to bind 'listen-address' parameter: %w" , err )
178
- }
179
-
180
- err = viper .BindPFlag ("aws-assume-role-arn" , cmd .Flags ().Lookup ("aws-assume-role-arn" ))
181
- if err != nil {
182
- return cmd , fmt .Errorf ("failed to bind 'aws-assume-role-arn' parameter: %w" , err )
183
- }
184
-
185
- err = viper .BindPFlag ("aws-assume-role-session" , cmd .Flags ().Lookup ("aws-assume-role-session" ))
186
- if err != nil {
187
- return cmd , fmt .Errorf ("failed to bind 'aws-assume-role-session' parameter: %w" , err )
188
- }
189
-
190
- err = viper .BindPFlag ("collect-instance-metrics" , cmd .Flags ().Lookup ("collect-instance-metrics" ))
191
- if err != nil {
192
- return cmd , fmt .Errorf ("failed to bind 'collect-instance-metrics' parameter: %w" , err )
193
- }
194
-
195
- err = viper .BindPFlag ("collect-instance-tags" , cmd .Flags ().Lookup ("collect-instance-tags" ))
196
- if err != nil {
197
- return cmd , fmt .Errorf ("failed to bind 'collect-instance-tags' parameter: %w" , err )
198
- }
199
-
200
- err = viper .BindPFlag ("collect-instance-types" , cmd .Flags ().Lookup ("collect-instance-types" ))
201
- if err != nil {
202
- return cmd , fmt .Errorf ("failed to bind 'collect-instance-types' parameter: %w" , err )
203
- }
204
-
205
- err = viper .BindPFlag ("collect-quotas" , cmd .Flags ().Lookup ("collect-quotas" ))
206
- if err != nil {
207
- return cmd , fmt .Errorf ("failed to bind 'collect-quotas' parameter: %w" , err )
208
- }
209
-
210
- err = viper .BindPFlag ("collect-usages" , cmd .Flags ().Lookup ("collect-usages" ))
211
- if err != nil {
212
- return cmd , fmt .Errorf ("failed to bind 'collect-usages' parameter: %w" , err )
213
- }
214
-
215
- err = viper .BindPFlag ("collect-logs-size" , cmd .Flags ().Lookup ("collect-logs-size" ))
216
- if err != nil {
217
- return cmd , fmt .Errorf ("failed to bind 'collect-logs-size' parameter: %w" , err )
218
- }
219
-
220
- err = viper .BindPFlag ("collect-maintenances" , cmd .Flags ().Lookup ("collect-maintenances" ))
221
- if err != nil {
222
- return cmd , fmt .Errorf ("failed to bind 'collect-maintenances' parameter: %w" , err )
223
- }
224
-
225
171
return cmd , nil
226
172
}
227
173
@@ -243,32 +189,30 @@ func Execute() {
243
189
func initConfig () {
244
190
if cfgFile != "" {
245
191
// Use config file from the flag.
246
- viper .SetConfigFile (cfgFile )
192
+ err := k .Load (file .Provider (cfgFile ), yaml .Parser ())
193
+ cobra .CheckErr (err )
247
194
} else {
248
- // Find home directory
195
+ // Find home directory.
249
196
home , err := os .UserHomeDir ()
250
197
cobra .CheckErr (err )
251
198
252
- // Search config in home directory or current directory with name "prometheus-rds-exporter.yaml"
253
-
199
+ // Search config in home directory or current directory with name "prometheus-rds-exporter.yaml".
254
200
configurationFilename := "prometheus-rds-exporter.yaml"
255
201
currentPathFilename := configurationFilename
256
202
homeFilename := filepath .Join (home , configurationFilename )
257
203
258
- if _ , err := os . Stat ( homeFilename ); err == nil {
259
- viper . SetConfigFile ( homeFilename )
204
+ if err := k . Load ( file . Provider ( homeFilename ), yaml . Parser () ); err == nil {
205
+ fmt . Printf ( "Using config file: %s \n " , homeFilename )
260
206
}
261
207
262
- if _ , err := os . Stat ( currentPathFilename ); err == nil {
263
- viper . SetConfigFile ( currentPathFilename )
208
+ if err := k . Load ( file . Provider ( currentPathFilename ), yaml . Parser () ); err == nil {
209
+ fmt . Printf ( "Using config file: %s \n " , currentPathFilename )
264
210
}
265
211
}
266
212
267
- if err := viper .ReadInConfig (); err == nil {
268
- fmt .Fprintln (os .Stderr , "Using config file:" , viper .ConfigFileUsed ())
269
- }
270
-
271
- viper .SetEnvPrefix ("prometheus_rds_exporter" ) // will be uppercased automatically
272
- viper .SetEnvKeyReplacer (strings .NewReplacer ("-" , "_" ))
273
- viper .AutomaticEnv ()
213
+ // Set environment variables.
214
+ err := k .Load (env .Provider ("PROMETHEUS_RDS_EXPORTER_" , "." , func (s string ) string {
215
+ return strings .ReplaceAll (strings .ToLower (strings .TrimPrefix (s , "PROMETHEUS_RDS_EXPORTER_" )), "_" , "." )
216
+ }), nil )
217
+ cobra .CheckErr (err )
274
218
}
0 commit comments