Skip to content

Commit d5ff306

Browse files
committed
Do not fail postgresCollector when version query fails
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. There is now a goroutine that will poll for version information regularly which will exit on os signal. This does not solve for the instance version being blank when collecting metrics. Signed-off-by: Joe Adams <[email protected]>
1 parent 716ac23 commit d5ff306

File tree

4 files changed

+67
-11
lines changed

4 files changed

+67
-11
lines changed

Diff for: cmd/postgres_exporter/main.go

+20-2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414
package main
1515

1616
import (
17+
"context"
1718
"fmt"
1819
"net/http"
1920
"os"
21+
"os/signal"
2022
"strings"
23+
"syscall"
2124

2225
"github.com/alecthomas/kingpin/v2"
2326
"github.com/go-kit/log"
@@ -132,7 +135,11 @@ func main() {
132135
dsn = dsns[0]
133136
}
134137

138+
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM, os.Kill)
139+
defer cancel()
140+
135141
pe, err := collector.NewPostgresCollector(
142+
ctx,
136143
logger,
137144
excludedDatabases,
138145
dsn,
@@ -169,8 +176,19 @@ func main() {
169176
http.HandleFunc("/probe", handleProbe(logger, excludedDatabases))
170177

171178
srv := &http.Server{}
179+
180+
go func() {
181+
<-ctx.Done()
182+
level.Info(logger).Log("msg", "Shutting down server...")
183+
if err := srv.Shutdown(context.Background()); err != nil {
184+
level.Error(logger).Log("msg", "Error shutting down server", "err", err)
185+
}
186+
}()
187+
172188
if err := web.ListenAndServe(srv, webConfig, logger); err != nil {
173-
level.Error(logger).Log("msg", "Error running HTTP server", "err", err)
174-
os.Exit(1)
189+
if err != http.ErrServerClosed {
190+
level.Error(logger).Log("msg", "Error running HTTP server", "err", err)
191+
os.Exit(1)
192+
}
175193
}
176194
}

Diff for: collector/collector.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ type PostgresCollector struct {
9797
type Option func(*PostgresCollector) error
9898

9999
// NewPostgresCollector creates a new PostgresCollector.
100-
func NewPostgresCollector(logger log.Logger, excludeDatabases []string, dsn string, filters []string, options ...Option) (*PostgresCollector, error) {
100+
func NewPostgresCollector(ctx context.Context, logger log.Logger, excludeDatabases []string, dsn string, filters []string, options ...Option) (*PostgresCollector, error) {
101101
p := &PostgresCollector{
102102
logger: logger,
103103
}
@@ -148,7 +148,7 @@ func NewPostgresCollector(logger log.Logger, excludeDatabases []string, dsn stri
148148
return nil, errors.New("empty dsn")
149149
}
150150

151-
instance, err := newInstance(dsn)
151+
instance, err := newCollectorInstance(ctx, dsn, logger)
152152
if err != nil {
153153
return nil, err
154154
}

Diff for: collector/instance.go

+44-6
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,59 @@
1414
package collector
1515

1616
import (
17+
"context"
1718
"database/sql"
1819
"fmt"
1920
"regexp"
21+
"time"
2022

2123
"github.com/blang/semver/v4"
24+
"github.com/go-kit/log"
25+
"github.com/go-kit/log/level"
26+
)
27+
28+
var (
29+
versionPollInterval = 5 * time.Minute
2230
)
2331

2432
type instance struct {
2533
db *sql.DB
2634
version semver.Version
2735
}
2836

29-
func newInstance(dsn string) (*instance, error) {
37+
func newProbeInstance(dsn string, logger log.Logger) (*instance, error) {
38+
return newInstance(dsn, logger)
39+
}
40+
41+
func newCollectorInstance(ctx context.Context, dsn string, logger log.Logger) (*instance, error) {
42+
i, err := newInstance(dsn, logger)
43+
if err != nil {
44+
return nil, err
45+
}
46+
47+
// Poll for updated version information
48+
go func() {
49+
ticker := time.NewTicker(versionPollInterval)
50+
defer ticker.Stop()
51+
for {
52+
select {
53+
case <-ctx.Done():
54+
return
55+
case <-ticker.C:
56+
version, err := queryVersion(i.getDB())
57+
if err != nil {
58+
level.Warn(logger).Log("msg", "Error querying postgresql version", "err", err)
59+
} else {
60+
i.version = version
61+
}
62+
}
63+
}
64+
}()
65+
66+
return i, nil
67+
}
68+
69+
func newInstance(dsn string, logger log.Logger) (*instance, error) {
3070
i := &instance{}
3171
db, err := sql.Open("postgres", dsn)
3272
if err != nil {
@@ -38,12 +78,10 @@ func newInstance(dsn string) (*instance, error) {
3878

3979
version, err := queryVersion(db)
4080
if err != nil {
41-
db.Close()
42-
return nil, err
81+
level.Warn(logger).Log("msg", "Error querying postgresql version", "err", err)
82+
} else {
83+
i.version = version
4384
}
44-
45-
i.version = version
46-
4785
return i, nil
4886
}
4987

Diff for: collector/probe.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func NewProbeCollector(logger log.Logger, excludeDatabases []string, registry *p
5757
}
5858
}
5959

60-
instance, err := newInstance(dsn.GetConnectionString())
60+
instance, err := newProbeInstance(dsn.GetConnectionString(), logger)
6161
if err != nil {
6262
return nil, err
6363
}

0 commit comments

Comments
 (0)