11package main
22
33import (
4+ "sync"
5+
46 "github.com/aws/aws-sdk-go/aws/session"
57 "github.com/aws/aws-sdk-go/service/rds"
68 "github.com/prometheus/client_golang/prometheus"
79 "github.com/prometheus/common/log"
810)
911
12+ // DBMaxConnections is a hardcoded map of instance types and DB Parameter Group names
13+ // This is a dump workaround created because by default the DB Parameter Group `max_connections` is a function
14+ // that is hard to parse and process in code and it contains a variable whose value is unknown to us (DBInstanceClassMemory)
15+ // AWS has no means to return the actual `max_connections` value.
16+ var DBMaxConnections = map [string ]map [string ]int64 {
17+ "db.t2.small" : map [string ]int64 {
18+ "default.mysql5.7" : 150 ,
19+ },
20+ "db.m5.2xlarge" : map [string ]int64 {
21+ "default.postgres10" : 3429 ,
22+ },
23+ "db.m5.large" : map [string ]int64 {
24+ "default.postgres10" : 823 ,
25+ },
26+ }
27+
28+ // RDSExporter defines an instance of the RDS Exporter
1029type RDSExporter struct {
11- sess * session.Session
12- AllocatedStorage * prometheus.Desc
13- DBInstanceClass * prometheus.Desc
14- DBInstanceStatus * prometheus.Desc
15- EngineVersion * prometheus.Desc
30+ sess * session.Session
31+ AllocatedStorage * prometheus.Desc
32+ DBInstanceClass * prometheus.Desc
33+ DBInstanceStatus * prometheus.Desc
34+ EngineVersion * prometheus.Desc
35+ MaxConnections * prometheus.Desc
36+ MaxConnectionsMappingErrors * prometheus.Desc
37+
38+ MaxConnectionsMappingErrorsValue float64
39+
40+ mutex * sync.Mutex
1641}
1742
43+ // NewRDSExporter creates a new RDSExporter instance
1844func NewRDSExporter (sess * session.Session ) * RDSExporter {
45+ log .Info ("[RDS] Initializing RDS exporter" )
1946 return & RDSExporter {
20- sess : sess ,
47+ sess : sess ,
48+ mutex : & sync.Mutex {},
2149 AllocatedStorage : prometheus .NewDesc (
22- prometheus .BuildFQName (namespace , "" , "allocatedstorage " ),
50+ prometheus .BuildFQName (namespace , "" , "rds_allocatedstorage " ),
2351 "The amount of allocated storage in bytes." ,
2452 []string {"aws_region" , "dbinstance_identifier" },
2553 nil ,
2654 ),
2755 DBInstanceClass : prometheus .NewDesc (
28- prometheus .BuildFQName (namespace , "" , "dbinstanceclass " ),
56+ prometheus .BuildFQName (namespace , "" , "rds_dbinstanceclass " ),
2957 "The DB instance class (type)." ,
3058 []string {"aws_region" , "dbinstance_identifier" , "instance_class" },
3159 nil ,
3260 ),
3361 DBInstanceStatus : prometheus .NewDesc (
34- prometheus .BuildFQName (namespace , "" , "dbinstancestatus " ),
62+ prometheus .BuildFQName (namespace , "" , "rds_dbinstancestatus " ),
3563 "The instance status." ,
3664 []string {"aws_region" , "dbinstance_identifier" , "instance_status" },
3765 nil ,
3866 ),
3967 EngineVersion : prometheus .NewDesc (
40- prometheus .BuildFQName (namespace , "" , "engineversion " ),
68+ prometheus .BuildFQName (namespace , "" , "rds_engineversion " ),
4169 "The DB engine type and version." ,
4270 []string {"aws_region" , "dbinstance_identifier" , "engine" , "engine_version" },
4371 nil ,
4472 ),
73+ MaxConnections : prometheus .NewDesc (
74+ prometheus .BuildFQName (namespace , "" , "rds_maxconnections" ),
75+ "The DB's max_connections value" ,
76+ []string {"aws_region" , "dbinstance_identifier" },
77+ nil ,
78+ ),
79+ MaxConnectionsMappingErrors : prometheus .NewDesc (
80+ prometheus .BuildFQName (namespace , "" , "rds_maxconnections_errors" ),
81+ "Indicates no mapping found for instance/parameter group." ,
82+ []string {},
83+ nil ,
84+ ),
4585 }
4686}
4787
88+ // Describe is used by the Prometheus client to return a description of the metrics
4889func (e * RDSExporter ) Describe (ch chan <- * prometheus.Desc ) {
4990 ch <- e .AllocatedStorage
5091 ch <- e .DBInstanceStatus
5192 ch <- e .EngineVersion
5293}
5394
95+ // Collect is used by the Prometheus client to collect and return the metrics values
5496func (e * RDSExporter ) Collect (ch chan <- prometheus.Metric ) {
5597 svc := rds .New (e .sess )
5698 input := & rds.DescribeDBInstancesInput {}
@@ -73,41 +115,35 @@ func (e *RDSExporter) Collect(ch chan<- prometheus.Metric) {
73115 }
74116 }
75117
76- parameterGroups := make (map [string ][]* rds.Parameter )
77118 for _ , instance := range instances {
78- for _ , dbpg := range instance .DBParameterGroups {
79- if * dbpg .ParameterApplyStatus == "in-sync" {
80- if _ , ok := parameterGroups [* dbpg .DBParameterGroupName ]; ok {
81- log .Debugln ("ParameterGroup" , * dbpg .DBParameterGroupName , "exists in cache." )
82- continue
83- }
84-
85- log .Debugln ("Fetching parameters for group" , * dbpg .DBParameterGroupName )
86- input := & rds.DescribeDBParametersInput {
87- DBParameterGroupName : dbpg .DBParameterGroupName ,
88- }
89- var parameters []* rds.Parameter
90- for {
91- exporterMetrics .IncrementRequests ()
92- result , err := svc .DescribeDBParameters (input )
93- if err != nil {
94- log .Errorf ("[RDS] Call to DescribeDBInstances failed in region %s: %s" , * e .sess .Config .Region , err )
95- exporterMetrics .IncrementErrors ()
96- return
97- }
98- parameters = append (parameters , result .Parameters ... )
99- input .Marker = result .Marker
100- if result .Marker == nil {
101- break
102- }
103- }
104- parameterGroups [* dbpg .DBParameterGroupName ] = parameters
119+ var maxConnections int64
120+ if val , ok := DBMaxConnections [* instance .DBInstanceClass ]; ok {
121+ if val , ok := val [* instance .DBParameterGroups [0 ].DBParameterGroupName ]; ok {
122+ log .Debugf ("[RDS] Found mapping for instance type %s group %s value %d" ,
123+ * instance .DBInstanceClass ,
124+ * instance .DBParameterGroups [0 ].DBParameterGroupName ,
125+ val )
126+ maxConnections = val
127+ } else {
128+ log .Errorf ("[RDS] No DB max_connections mapping exists for instance type %s parameter group %s" ,
129+ * instance .DBInstanceClass ,
130+ * instance .DBParameterGroups [0 ].DBParameterGroupName )
131+ e .mutex .Lock ()
132+ e .MaxConnectionsMappingErrorsValue ++
133+ e .mutex .Unlock ()
105134 }
135+ } else {
136+ log .Errorf ("[RDS] No DB max_connections mapping exists for instance type %s" ,
137+ * instance .DBInstanceClass )
138+ e .mutex .Lock ()
139+ e .MaxConnectionsMappingErrorsValue ++
140+ e .mutex .Unlock ()
106141 }
107-
142+ ch <- prometheus . MustNewConstMetric ( e . MaxConnections , prometheus . GaugeValue , float64 ( maxConnections ), * e . sess . Config . Region , * instance . DBInstanceIdentifier )
108143 ch <- prometheus .MustNewConstMetric (e .AllocatedStorage , prometheus .GaugeValue , float64 (* instance .AllocatedStorage * 1024 * 1024 * 1024 ), * e .sess .Config .Region , * instance .DBInstanceIdentifier )
109144 ch <- prometheus .MustNewConstMetric (e .DBInstanceStatus , prometheus .GaugeValue , 1 , * e .sess .Config .Region , * instance .DBInstanceIdentifier , * instance .DBInstanceStatus )
110145 ch <- prometheus .MustNewConstMetric (e .EngineVersion , prometheus .GaugeValue , 1 , * e .sess .Config .Region , * instance .DBInstanceIdentifier , * instance .Engine , * instance .EngineVersion )
111146 ch <- prometheus .MustNewConstMetric (e .DBInstanceClass , prometheus .GaugeValue , 1 , * e .sess .Config .Region , * instance .DBInstanceIdentifier , * instance .DBInstanceClass )
112147 }
148+ ch <- prometheus .MustNewConstMetric (e .MaxConnectionsMappingErrors , prometheus .CounterValue , e .MaxConnectionsMappingErrorsValue )
113149}
0 commit comments