Skip to content

Commit ebf1add

Browse files
authored
Merge pull request #8 from app-sre/rds_conn
Add RDS max_connections metric
2 parents 6e74717 + 0ed7fd7 commit ebf1add

File tree

3 files changed

+81
-44
lines changed

3 files changed

+81
-44
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/app-sre/aws-resource-exporter
33
go 1.12
44

55
require (
6-
github.com/aws/aws-sdk-go v1.15.77
6+
github.com/aws/aws-sdk-go v1.25.9
77
github.com/prometheus/client_golang v0.9.3
88
github.com/prometheus/common v0.4.1
99
github.com/prometheus/procfs v0.0.2 // indirect

go.sum

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5Vpd
33
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
44
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
55
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
6-
github.com/aws/aws-sdk-go v1.15.77 h1:qlut2MDI5mRKllPC6grO5n9M8UhPQg1TIA9cYAkC/gc=
7-
github.com/aws/aws-sdk-go v1.15.77/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
6+
github.com/aws/aws-sdk-go v1.25.9 h1:WtVzerf5wSgPwlTTwl+ktCq/0GCS5MI9ZlLIcjsTr+Q=
7+
github.com/aws/aws-sdk-go v1.25.9/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
88
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
99
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
1010
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
@@ -22,13 +22,14 @@ github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80n
2222
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
2323
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
2424
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
25+
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
2526
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
2627
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
2728
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
2829
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
2930
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
30-
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE=
31-
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
31+
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
32+
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
3233
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
3334
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
3435
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=

rds.go

Lines changed: 75 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,98 @@
11
package main
22

33
import (
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
1029
type 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
1844
func 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
4889
func (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
5496
func (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

Comments
 (0)