From 029556a624d317a4e3247ecba953b36874d280e8 Mon Sep 17 00:00:00 2001 From: Jean-Francois Chevrette Date: Thu, 10 Oct 2019 11:07:54 -0400 Subject: [PATCH 1/4] append rds_ to metrics names --- rds.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rds.go b/rds.go index 2e2ec9d..89ff1a2 100644 --- a/rds.go +++ b/rds.go @@ -16,28 +16,29 @@ type RDSExporter struct { } func NewRDSExporter(sess *session.Session) *RDSExporter { + log.Info("[RDS] Initializing RDS exporter") return &RDSExporter{ sess: sess, AllocatedStorage: prometheus.NewDesc( - prometheus.BuildFQName(namespace, "", "allocatedstorage"), + prometheus.BuildFQName(namespace, "", "rds_allocatedstorage"), "The amount of allocated storage in bytes.", []string{"aws_region", "dbinstance_identifier"}, nil, ), DBInstanceClass: prometheus.NewDesc( - prometheus.BuildFQName(namespace, "", "dbinstanceclass"), + prometheus.BuildFQName(namespace, "", "rds_dbinstanceclass"), "The DB instance class (type).", []string{"aws_region", "dbinstance_identifier", "instance_class"}, nil, ), DBInstanceStatus: prometheus.NewDesc( - prometheus.BuildFQName(namespace, "", "dbinstancestatus"), + prometheus.BuildFQName(namespace, "", "rds_dbinstancestatus"), "The instance status.", []string{"aws_region", "dbinstance_identifier", "instance_status"}, nil, ), EngineVersion: prometheus.NewDesc( - prometheus.BuildFQName(namespace, "", "engineversion"), + prometheus.BuildFQName(namespace, "", "rds_engineversion"), "The DB engine type and version.", []string{"aws_region", "dbinstance_identifier", "engine", "engine_version"}, nil, From 3ca80977994bafca7f673abce1d5944ad49d993d Mon Sep 17 00:00:00 2001 From: Jean-Francois Chevrette Date: Thu, 10 Oct 2019 11:30:09 -0400 Subject: [PATCH 2/4] update awk sdk --- go.mod | 2 +- go.sum | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index edaff24..5e7fb86 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/app-sre/aws-resource-exporter go 1.12 require ( - github.com/aws/aws-sdk-go v1.15.77 + github.com/aws/aws-sdk-go v1.25.9 github.com/prometheus/client_golang v0.9.3 github.com/prometheus/common v0.4.1 github.com/prometheus/procfs v0.0.2 // indirect diff --git a/go.sum b/go.sum index e74a40f..9ee5532 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5Vpd github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/aws/aws-sdk-go v1.15.77 h1:qlut2MDI5mRKllPC6grO5n9M8UhPQg1TIA9cYAkC/gc= -github.com/aws/aws-sdk-go v1.15.77/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= +github.com/aws/aws-sdk-go v1.25.9 h1:WtVzerf5wSgPwlTTwl+ktCq/0GCS5MI9ZlLIcjsTr+Q= +github.com/aws/aws-sdk-go v1.25.9/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= @@ -27,8 +27,8 @@ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= From d17fb42937ea5498f2782404ba277b8b200861b6 Mon Sep 17 00:00:00 2001 From: Jean-Francois Chevrette Date: Fri, 11 Oct 2019 11:19:07 -0400 Subject: [PATCH 3/4] add rds maxconnections metrics --- go.sum | 1 + rds.go | 97 +++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 63 insertions(+), 35 deletions(-) diff --git a/go.sum b/go.sum index 9ee5532..3cbcd6e 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,7 @@ github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80n github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= diff --git a/rds.go b/rds.go index 89ff1a2..f079aef 100644 --- a/rds.go +++ b/rds.go @@ -1,24 +1,45 @@ package main import ( + "sync" + "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/rds" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/log" ) +var DBMaxConnections = map[string]map[string]int64{ + "db.t2.small": map[string]int64{ + "default.mysql5.7": 150, + }, + "db.m5.2xlarge": map[string]int64{ + "default.postgres10": 3429, + }, + "db.m5.large": map[string]int64{ + "default.postgres10": 823, + }, +} + type RDSExporter struct { - sess *session.Session - AllocatedStorage *prometheus.Desc - DBInstanceClass *prometheus.Desc - DBInstanceStatus *prometheus.Desc - EngineVersion *prometheus.Desc + sess *session.Session + AllocatedStorage *prometheus.Desc + DBInstanceClass *prometheus.Desc + DBInstanceStatus *prometheus.Desc + EngineVersion *prometheus.Desc + MaxConnections *prometheus.Desc + MaxConnectionsMappingErrors *prometheus.Desc + + MaxConnectionsMappingErrorsValue float64 + + mutex *sync.Mutex } func NewRDSExporter(sess *session.Session) *RDSExporter { log.Info("[RDS] Initializing RDS exporter") return &RDSExporter{ - sess: sess, + sess: sess, + mutex: &sync.Mutex{}, AllocatedStorage: prometheus.NewDesc( prometheus.BuildFQName(namespace, "", "rds_allocatedstorage"), "The amount of allocated storage in bytes.", @@ -43,6 +64,18 @@ func NewRDSExporter(sess *session.Session) *RDSExporter { []string{"aws_region", "dbinstance_identifier", "engine", "engine_version"}, nil, ), + MaxConnections: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "", "rds_maxconnections"), + "The DB's max_connections value", + []string{"aws_region", "dbinstance_identifier"}, + nil, + ), + MaxConnectionsMappingErrors: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "", "rds_maxconnections_errors"), + "Indicates no mapping found for instance/parameter group.", + []string{}, + nil, + ), } } @@ -74,41 +107,35 @@ func (e *RDSExporter) Collect(ch chan<- prometheus.Metric) { } } - parameterGroups := make(map[string][]*rds.Parameter) for _, instance := range instances { - for _, dbpg := range instance.DBParameterGroups { - if *dbpg.ParameterApplyStatus == "in-sync" { - if _, ok := parameterGroups[*dbpg.DBParameterGroupName]; ok { - log.Debugln("ParameterGroup", *dbpg.DBParameterGroupName, "exists in cache.") - continue - } - - log.Debugln("Fetching parameters for group", *dbpg.DBParameterGroupName) - input := &rds.DescribeDBParametersInput{ - DBParameterGroupName: dbpg.DBParameterGroupName, - } - var parameters []*rds.Parameter - for { - exporterMetrics.IncrementRequests() - result, err := svc.DescribeDBParameters(input) - if err != nil { - log.Errorf("[RDS] Call to DescribeDBInstances failed in region %s: %s", *e.sess.Config.Region, err) - exporterMetrics.IncrementErrors() - return - } - parameters = append(parameters, result.Parameters...) - input.Marker = result.Marker - if result.Marker == nil { - break - } - } - parameterGroups[*dbpg.DBParameterGroupName] = parameters + var maxConnections int64 + if val, ok := DBMaxConnections[*instance.DBInstanceClass]; ok { + if val, ok := val[*instance.DBParameterGroups[0].DBParameterGroupName]; ok { + log.Debugf("[RDS] Found mapping for instance type %s group %s value %d", + *instance.DBInstanceClass, + *instance.DBParameterGroups[0].DBParameterGroupName, + val) + maxConnections = val + } else { + log.Errorf("[RDS] No DB max_connections mapping exists for instance type %s parameter group %s", + *instance.DBInstanceClass, + *instance.DBParameterGroups[0].DBParameterGroupName) + e.mutex.Lock() + e.MaxConnectionsMappingErrorsValue++ + e.mutex.Unlock() } + } else { + log.Errorf("[RDS] No DB max_connections mapping exists for instance type %s", + *instance.DBInstanceClass) + e.mutex.Lock() + e.MaxConnectionsMappingErrorsValue++ + e.mutex.Unlock() } - + ch <- prometheus.MustNewConstMetric(e.MaxConnections, prometheus.GaugeValue, float64(maxConnections), *e.sess.Config.Region, *instance.DBInstanceIdentifier) ch <- prometheus.MustNewConstMetric(e.AllocatedStorage, prometheus.GaugeValue, float64(*instance.AllocatedStorage*1024*1024*1024), *e.sess.Config.Region, *instance.DBInstanceIdentifier) ch <- prometheus.MustNewConstMetric(e.DBInstanceStatus, prometheus.GaugeValue, 1, *e.sess.Config.Region, *instance.DBInstanceIdentifier, *instance.DBInstanceStatus) ch <- prometheus.MustNewConstMetric(e.EngineVersion, prometheus.GaugeValue, 1, *e.sess.Config.Region, *instance.DBInstanceIdentifier, *instance.Engine, *instance.EngineVersion) ch <- prometheus.MustNewConstMetric(e.DBInstanceClass, prometheus.GaugeValue, 1, *e.sess.Config.Region, *instance.DBInstanceIdentifier, *instance.DBInstanceClass) } + ch <- prometheus.MustNewConstMetric(e.MaxConnectionsMappingErrors, prometheus.CounterValue, e.MaxConnectionsMappingErrorsValue) } From 0ed7fd73b56ea5f05784e32fb9a580917f09049e Mon Sep 17 00:00:00 2001 From: Jean-Francois Chevrette Date: Fri, 11 Oct 2019 11:26:58 -0400 Subject: [PATCH 4/4] add comments --- rds.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rds.go b/rds.go index f079aef..4f94c38 100644 --- a/rds.go +++ b/rds.go @@ -9,6 +9,10 @@ import ( "github.com/prometheus/common/log" ) +// DBMaxConnections is a hardcoded map of instance types and DB Parameter Group names +// This is a dump workaround created because by default the DB Parameter Group `max_connections` is a function +// that is hard to parse and process in code and it contains a variable whose value is unknown to us (DBInstanceClassMemory) +// AWS has no means to return the actual `max_connections` value. var DBMaxConnections = map[string]map[string]int64{ "db.t2.small": map[string]int64{ "default.mysql5.7": 150, @@ -21,6 +25,7 @@ var DBMaxConnections = map[string]map[string]int64{ }, } +// RDSExporter defines an instance of the RDS Exporter type RDSExporter struct { sess *session.Session AllocatedStorage *prometheus.Desc @@ -35,6 +40,7 @@ type RDSExporter struct { mutex *sync.Mutex } +// NewRDSExporter creates a new RDSExporter instance func NewRDSExporter(sess *session.Session) *RDSExporter { log.Info("[RDS] Initializing RDS exporter") return &RDSExporter{ @@ -79,12 +85,14 @@ func NewRDSExporter(sess *session.Session) *RDSExporter { } } +// Describe is used by the Prometheus client to return a description of the metrics func (e *RDSExporter) Describe(ch chan<- *prometheus.Desc) { ch <- e.AllocatedStorage ch <- e.DBInstanceStatus ch <- e.EngineVersion } +// Collect is used by the Prometheus client to collect and return the metrics values func (e *RDSExporter) Collect(ch chan<- prometheus.Metric) { svc := rds.New(e.sess) input := &rds.DescribeDBInstancesInput{}