From b74852a5353b4bf2cb2cc944f329d651fbf99064 Mon Sep 17 00:00:00 2001 From: Joe Adams <github@joeadams.io> Date: Wed, 23 Aug 2023 17:33:47 -0400 Subject: [PATCH] Delay database connection until scrape (#882) This no longer returns an error when creating a collector.instance when the database cannot be reached for the version query. This will resolve the entire postgresCollector not being registered for metrics collection when a database is not available. If the version query fails, the scrape will fail. Resolves #880 Signed-off-by: Joe Adams <github@joeadams.io> --- collector/collector.go | 8 ++++++++ collector/instance.go | 30 ++++++++++++++++++++++-------- collector/probe.go | 8 ++++++++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/collector/collector.go b/collector/collector.go index c1bf2af9..e06ef7d1 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -166,6 +166,14 @@ func (p PostgresCollector) Describe(ch chan<- *prometheus.Desc) { // Collect implements the prometheus.Collector interface. func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) { ctx := context.TODO() + + // Set up the database connection for the collector. + err := p.instance.setup() + if err != nil { + level.Error(p.logger).Log("msg", "Error opening connection to database", "err", err) + return + } + wg := sync.WaitGroup{} wg.Add(len(p.Collectors)) for name, c := range p.Collectors { diff --git a/collector/instance.go b/collector/instance.go index 9b2bbf47..87eb0591 100644 --- a/collector/instance.go +++ b/collector/instance.go @@ -22,29 +22,43 @@ import ( ) type instance struct { + dsn string db *sql.DB version semver.Version } func newInstance(dsn string) (*instance, error) { - i := &instance{} + i := &instance{ + dsn: dsn, + } + + // "Create" a database handle to verify the DSN provided is valid. + // Open is not guaranteed to create a connection. db, err := sql.Open("postgres", dsn) if err != nil { return nil, err } + db.Close() + + return i, nil +} + +func (i *instance) setup() error { + db, err := sql.Open("postgres", i.dsn) + if err != nil { + return err + } db.SetMaxOpenConns(1) db.SetMaxIdleConns(1) i.db = db - version, err := queryVersion(db) + version, err := queryVersion(i.db) if err != nil { - db.Close() - return nil, err + return fmt.Errorf("error querying postgresql version: %w", err) + } else { + i.version = version } - - i.version = version - - return i, nil + return nil } func (i *instance) getDB() *sql.DB { diff --git a/collector/probe.go b/collector/probe.go index 834c6517..a7630272 100644 --- a/collector/probe.go +++ b/collector/probe.go @@ -18,6 +18,7 @@ import ( "sync" "github.com/go-kit/log" + "github.com/go-kit/log/level" "github.com/prometheus-community/postgres_exporter/config" "github.com/prometheus/client_golang/prometheus" ) @@ -74,6 +75,13 @@ func (pc *ProbeCollector) Describe(ch chan<- *prometheus.Desc) { } func (pc *ProbeCollector) Collect(ch chan<- prometheus.Metric) { + // Set up the database connection for the collector. + err := pc.instance.setup() + if err != nil { + level.Error(pc.logger).Log("msg", "Error opening connection to database", "err", err) + return + } + wg := sync.WaitGroup{} wg.Add(len(pc.collectors)) for name, c := range pc.collectors {