Skip to content
This repository was archived by the owner on Nov 28, 2022. It is now read-only.

Commit c99e529

Browse files
Merge pull request #28 from ContaAzul/pg10
Add support to PostgreSQL 10
2 parents bb8ac18 + 7b3b2f2 commit c99e529

File tree

8 files changed

+122
-21
lines changed

8 files changed

+122
-21
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
dist: trusty
22
sudo: required
33
language: go
4-
go: 1.9
4+
go: "1.10"
55
services:
66
- docker
77
- postgresql

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ build:
88
CGO_ENABLED=0 go build -ldflags="-s -w"
99

1010
test:
11-
go test -v ./...
11+
GOCACHE=off go test -v ./...
1212

1313
lint:
1414
gometalinter.v2 --vendor --deadline=60s ./...

gauges/backends.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package gauges
33
import (
44
"time"
55

6+
"github.com/ContaAzul/postgresql_exporter/postgres"
67
"github.com/apex/log"
78
"github.com/prometheus/client_golang/prometheus"
89
)
@@ -85,7 +86,7 @@ func (g *Gauges) BackendsStatus() *prometheus.GaugeVec {
8586
}
8687

8788
func (g *Gauges) waitingBackendsQuery() string {
88-
if isPG96(g.version()) {
89+
if postgres.Version(g.version()).Is96Or10() {
8990
return `
9091
SELECT COUNT(*) as count, 'waiting' as state, usename
9192
FROM pg_stat_activity

gauges/gauge.go

+2-9
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package gauges
33
import (
44
"context"
55
"database/sql"
6-
"regexp"
76
"strings"
87
"time"
98

@@ -171,17 +170,11 @@ func (g *Gauges) queryWithTimeout(
171170
return err
172171
}
173172

174-
var versionRE = regexp.MustCompile(`^PostgreSQL (\d\.\d\.\d).*`)
175-
176173
func (g *Gauges) version() string {
177174
var version string
178-
if err := g.db.QueryRow("select version()").Scan(&version); err != nil {
175+
if err := g.db.QueryRow("show server_version").Scan(&version); err != nil {
179176
log.WithError(err).Error("failed to get postgresql version, assuming 9.6.0")
180177
return "9.6.0"
181178
}
182-
return versionRE.FindStringSubmatch(version)[1]
183-
}
184-
185-
func isPG96(version string) bool {
186-
return strings.HasPrefix(version, "9.6.")
179+
return version
187180
}

gauges/gauge_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,11 @@ func connect(t *testing.T) *sql.DB {
8383
db.SetMaxOpenConns(1)
8484
return db
8585
}
86+
87+
func TestVersion(t *testing.T) {
88+
var assert = assert.New(t)
89+
_, gauges, close := prepare(t)
90+
defer close()
91+
assert.NotEmpty(gauges.version())
92+
assertNoErrs(t, gauges)
93+
}

gauges/replication.go

+25-9
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,41 @@
11
package gauges
22

3-
import "github.com/prometheus/client_golang/prometheus"
3+
import (
4+
"fmt"
45

6+
"github.com/ContaAzul/postgresql_exporter/postgres"
7+
"github.com/prometheus/client_golang/prometheus"
8+
)
9+
10+
// ReplicationStatus returns a prometheus gauge for the PostgreSQL
11+
// replication status
512
func (g *Gauges) ReplicationStatus() prometheus.Gauge {
613
return g.new(
714
prometheus.GaugeOpts{
815
Name: "postgresql_replication_status",
916
Help: "Returns 1 if in recovery and replay is paused, 0 if OK and -1 if not in recovery",
1017
ConstLabels: g.labels,
1118
},
12-
`
19+
fmt.Sprintf(`
1320
SELECT
1421
CASE
1522
WHEN pg_is_in_recovery() is true
1623
THEN
1724
CASE
18-
WHEN pg_is_xlog_replay_paused() is true
25+
WHEN %s() is true
1926
THEN 1
2027
ELSE 0
2128
END
2229
ELSE
2330
-1
24-
END
25-
`,
31+
END`,
32+
postgres.Version(g.version()).IsWalReplayPausedFunctionName(),
33+
),
2634
)
2735
}
2836

37+
// StreamingWALs returns a prometheus gauge for the count of WALs
38+
// in streaming state
2939
func (g *Gauges) StreamingWALs() prometheus.Gauge {
3040
return g.new(
3141
prometheus.GaugeOpts{
@@ -41,26 +51,32 @@ func (g *Gauges) StreamingWALs() prometheus.Gauge {
4151
)
4252
}
4353

54+
// ReplicationLag returns a prometheus gauge for the database replication
55+
// lag in milliseconds
4456
func (g *Gauges) ReplicationLag() prometheus.Gauge {
57+
version := postgres.Version(g.version())
58+
4559
return g.new(
4660
prometheus.GaugeOpts{
4761
Name: "postgresql_replication_lag",
4862
Help: "Dabatase replication lag",
4963
ConstLabels: g.labels,
5064
},
51-
`
65+
fmt.Sprintf(`
5266
SELECT COALESCE(
5367
CASE
5468
WHEN pg_is_in_recovery() is true
5569
THEN
5670
CASE
57-
WHEN pg_last_xlog_receive_location() = pg_last_xlog_replay_location()
71+
WHEN %s() = %s()
5872
THEN 0
5973
ELSE
6074
EXTRACT (EPOCH FROM now() - pg_last_xact_replay_timestamp())
6175
END
6276
END
63-
, 0)
64-
`,
77+
, 0)`,
78+
version.LastWalReceivedLsnFunctionName(),
79+
version.LastWalReplayedLsnFunctionName(),
80+
),
6581
)
6682
}

postgres/version.go

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package postgres
2+
3+
import "strings"
4+
5+
// Version for a postgres server
6+
type Version string
7+
8+
// IsWalReplayPausedFunctionName returns the name of the function to verify whether the replication
9+
// log is paused according to the postgres version
10+
func (v Version) IsWalReplayPausedFunctionName() string {
11+
if v.is10() {
12+
return "pg_is_wal_replay_paused"
13+
}
14+
return "pg_is_xlog_replay_paused"
15+
}
16+
17+
// LastWalReceivedLsnFunctionName returns the name of the function that returns the last write-ahead
18+
// log location received and synced to disk by replication according to the postgres version
19+
func (v Version) LastWalReceivedLsnFunctionName() string {
20+
if v.is10() {
21+
return "pg_last_wal_receive_lsn"
22+
}
23+
return "pg_last_xlog_receive_location"
24+
}
25+
26+
// LastWalReplayedLsnFunctionName returns the name of the function that returns the last write-ahead
27+
// log location replayed during recovery according to the postgres version
28+
func (v Version) LastWalReplayedLsnFunctionName() string {
29+
if v.is10() {
30+
return "pg_last_wal_replay_lsn"
31+
}
32+
return "pg_last_xlog_replay_location"
33+
34+
}
35+
36+
func (v Version) is96() bool {
37+
return strings.HasPrefix(string(v), "9.6.")
38+
}
39+
40+
func (v Version) is10() bool {
41+
return strings.HasPrefix(string(v), "10.")
42+
}
43+
44+
// Is96Or10 returns whether this is version 9.6.x, 10.x or not
45+
func (v Version) Is96Or10() bool {
46+
return v.is96() || v.is10()
47+
}

postgres/version_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package postgres
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestFunctionVersions(t *testing.T) {
11+
is96 := Version.is96
12+
is10 := Version.is10
13+
is96Or10 := Version.Is96Or10
14+
15+
tt := []struct {
16+
str string
17+
fn func(Version) bool
18+
expected bool
19+
}{
20+
{"9.6.6", is96, true},
21+
{"9.5.4", is96, false},
22+
{"10.3", is10, true},
23+
{"9.6.6", is10, false},
24+
{"9.6.6", is96Or10, true},
25+
{"9.5.4", is96Or10, false},
26+
{"10.4", is96Or10, true},
27+
{"11.0", is96Or10, false},
28+
}
29+
30+
for _, tc := range tt {
31+
testName := fmt.Sprintf("expecting %p(\"%v\") to be %v", tc.fn, tc.str, tc.expected)
32+
t.Run(testName, func(t *testing.T) {
33+
assert.Equal(t, tc.fn(Version(tc.str)), tc.expected)
34+
})
35+
}
36+
}

0 commit comments

Comments
 (0)