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

Send replication slots metrics to Prometheus #60

Merged
merged 32 commits into from
Sep 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
13b8c66
Replication slots metrics
bern4rdelli Sep 18, 2019
b104219
Fix metrics
bern4rdelli Sep 19, 2019
11f6496
Add unit tests
bern4rdelli Sep 19, 2019
544cbfb
Improve tests
bern4rdelli Sep 19, 2019
ca4a2fc
Try to change postgresql.conf
bern4rdelli Sep 19, 2019
46683de
build
bern4rdelli Sep 19, 2019
12993bb
Try to set manually
bern4rdelli Sep 19, 2019
bb9025a
Try to set manually
bern4rdelli Sep 19, 2019
807a804
Restart PostgreSQL
bern4rdelli Sep 19, 2019
85e5dea
set max_replication_slots
bern4rdelli Sep 19, 2019
d2a197e
set max_replication_slots
bern4rdelli Sep 19, 2019
e634cc0
Using different slots
bern4rdelli Sep 19, 2019
a64bc1c
Using PostgreSQL 11
bern4rdelli Sep 19, 2019
8b85214
Revert to 9.6
bern4rdelli Sep 19, 2019
b25656b
Using 10.0
bern4rdelli Sep 19, 2019
4813d02
test 11.2
bern4rdelli Sep 19, 2019
9f8b823
Using user travis
bern4rdelli Sep 19, 2019
c45f93f
Show PostgreSQL version`
bern4rdelli Sep 19, 2019
8808f52
Install pg 11
bern4rdelli Sep 19, 2019
b3f52a3
Using pg 11.3
bern4rdelli Sep 19, 2019
25c5350
Try using packages
bern4rdelli Sep 19, 2019
4eab04a
Return warnning when pg is lower than 10
bern4rdelli Sep 20, 2019
0916656
Pass test
bern4rdelli Sep 20, 2019
ea75a97
Support pg 9.6
bern4rdelli Sep 20, 2019
17cddfb
Update postgres/version.go
bern4rdelli Sep 20, 2019
7c3a4b2
Update gauges/logical_replication.go
bern4rdelli Sep 20, 2019
a083e0a
Update gauges/logical_replication.go
bern4rdelli Sep 20, 2019
f5b4ffe
Update gauges/logical_replication.go
bern4rdelli Sep 20, 2019
cd0e0ed
Update gauges/logical_replication.go
bern4rdelli Sep 20, 2019
6bb1c3b
Apply suggestions from CR
bern4rdelli Sep 20, 2019
057b934
Improve help message
bern4rdelli Sep 20, 2019
c38ac74
Return lag in bytes
bern4rdelli Sep 20, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ language: go
go: "1.10"
addons:
postgresql: "9.6"
before_script:
- psql -U travis -c "ALTER SYSTEM SET wal_level TO 'logical';"
- psql -U travis -c "ALTER SYSTEM SET max_replication_slots TO '10';"
- sudo /etc/init.d/postgresql restart
services:
- docker
- postgresql
Expand Down
95 changes: 95 additions & 0 deletions gauges/logical_replication.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package gauges

import (
"fmt"
"time"

"github.com/ContaAzul/postgresql_exporter/postgres"
"github.com/prometheus/client_golang/prometheus"
)

type slots struct {
Name string `db:"slot_name"`
Active float64 `db:"active"`
TotalLag float64 `db:"total_lag"`
}

// ReplicationSlotStatus returns the state of the replication slots
func (g *Gauges) ReplicationSlotStatus() *prometheus.GaugeVec {
var gauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "postgresql_replication_slot_status",
Help: "Returns 1 if the slot is currently actively being used",
ConstLabels: g.labels,
},
[]string{"slot_name"},
)
go func() {
for {
gauge.Reset()
var slots []slots
if err := g.query(
`
SELECT
slot_name,
active::int
FROM pg_replication_slots
WHERE slot_type = 'logical'
AND "database" = current_database();
`,
&slots,
emptyParams,
); err == nil {
for _, slot := range slots {
gauge.With(prometheus.Labels{
"slot_name": slot.Name,
}).Set(slot.Active)
}
}
time.Sleep(g.interval)
}
}()
return gauge
}

// ReplicationSlotLagInBytes returns the total lag in bytes from the replication slots
func (g *Gauges) ReplicationSlotLagInBytes() *prometheus.GaugeVec {
var gauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "postgresql_replication_lag_bytes",
Help: "Total lag of the replication slots in bytes",
ConstLabels: g.labels,
},
[]string{"slot_name"},
)
go func() {
for {
gauge.Reset()
var slots []slots
if err := g.query(
fmt.Sprintf(
`
SELECT
slot_name,
%s(%s(), confirmed_flush_lsn) AS total_lag
FROM pg_replication_slots
WHERE slot_type = 'logical'
AND "database" = current_database();
`,
postgres.Version(g.version()).WalLsnDiffFunctionName(),
postgres.Version(g.version()).CurrentWalLsnFunctionName(),
),
&slots,
emptyParams,
); err == nil {
for _, slot := range slots {
gauge.With(prometheus.Labels{
"slot_name": slot.Name,
}).Set(slot.TotalLag)
}
}
time.Sleep(g.interval)
}
}()
return gauge
}
43 changes: 43 additions & 0 deletions gauges/logical_replication_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package gauges

import (
"database/sql"
"fmt"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestReplicationSlotStatus(t *testing.T) {
var assert = assert.New(t)
db, gauges, close := prepare(t)
defer close()
dropTestLogicalReplicationSlot := createTestLogicalReplicationSlot("test_status", t, db)
defer dropTestLogicalReplicationSlot()
var metrics = evaluate(t, gauges.ReplicationSlotStatus())
assert.Len(metrics, 1)
assertEqual(t, 0, metrics[0])
assertNoErrs(t, gauges)
}

func TestReplicationSlotLagInMegabytes(t *testing.T) {
var assert = assert.New(t)
db, gauges, close := prepare(t)
defer close()
dropTestLogicalReplicationSlot := createTestLogicalReplicationSlot("test_lag", t, db)
defer dropTestLogicalReplicationSlot()
var metrics = evaluate(t, gauges.ReplicationDelayInBytes())
assert.Len(metrics, 1)
assertEqual(t, 0, metrics[0])
assertNoErrs(t, gauges)
}

func createTestLogicalReplicationSlot(slotName string, t *testing.T, db *sql.DB) func() {
_, err := db.Exec(fmt.Sprintf("SELECT * FROM pg_create_logical_replication_slot('%s', 'test_decoding');", slotName))
require.NoError(t, err)
return func() {
_, err := db.Exec(fmt.Sprintf("SELECT pg_drop_replication_slot('%s');", slotName))
assert.New(t).NoError(err)
}
}
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,6 @@ func watch(db *sql.DB, reg prometheus.Registerer, name string) {
reg.MustRegister(gauges.LastTimeVacuumRan())
reg.MustRegister(gauges.LastTimeAutoVacuumRan())
reg.MustRegister(gauges.VacuumRunningTotal())
reg.MustRegister(gauges.ReplicationSlotStatus())
reg.MustRegister(gauges.ReplicationSlotLagInBytes())
}
8 changes: 8 additions & 0 deletions postgres/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,13 @@ func (v Version) LastWalReplayedLsnFunctionName() string {
return "pg_last_wal_replay_lsn"
}
return "pg_last_xlog_replay_location"
}

// CurrentWalLsnFunctionName returns the name of the function that gets current
// write-ahead log write location according to the postgres version
func (v Version) CurrentWalLsnFunctionName() string {
if v.IsEqualOrGreaterThan10() {
return "pg_current_wal_lsn"
}
return "pg_current_xlog_location"
}