Skip to content

Commit e1008c5

Browse files
PMM-14368 PostgreSQL 18 support (#336)
Introduce support for PostgreSQL 18, adding enhanced metrics for checkpointer, vacuum/analyze timings, and parallel worker activity. Implement new collectors for `pg_stat_io` and `pg_backend_memory_contexts` with version-specific queries, along with comprehensive tests. Update README and CI to reflect PostgreSQL 18 compatibility. Refactored IO and statistics queries to accommodate PostgreSQL 18 features, including byte-level statistics and WAL I/O. Updated tests to validate new columns and ensure query expectation checks are correctly enforced. Improved test coverage across different PostgreSQL versions. Updated CI matrix. --------- Co-authored-by: Nurlan Moldomurov <[email protected]>
1 parent c463163 commit e1008c5

File tree

11 files changed

+1073
-96
lines changed

11 files changed

+1073
-96
lines changed

.github/workflows/go.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ jobs:
1414
strategy:
1515
matrix:
1616
postgresql-image:
17-
- postgres:10
18-
- postgres:11
19-
- postgres:12
2017
- postgres:13
2118
- postgres:14
19+
- postgres:15
20+
- postgres:16
21+
- postgres:17
22+
- postgres:18
2223
runs-on: ubuntu-latest
2324
steps:
2425
- name: Checkout code

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## [Unreleased]
2+
3+
* [ENHANCEMENT] Add PostgreSQL 18 support:
4+
* Add parallel worker activity metrics
5+
* Add vacuum/analyze timing metrics
6+
* Add enhanced checkpointer metrics
7+
* Add `pg_stat_io` collector with byte statistics and WAL I/O activity tracking
8+
* [ENHANCEMENT] Update CI tested PostgreSQL versions to include PostgreSQL 18
9+
110
## 0.15.0 / 2023-10-27
211

312
* [ENHANCEMENT] Add 1kB and 2kB units #915

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
Prometheus exporter for PostgreSQL server metrics.
99

10-
CI Tested PostgreSQL versions: `11`, `12`, `13`, `14`, `15`, `16`
10+
CI Tested PostgreSQL versions: `13`, `14`, `15`, `16`, `18`
1111

1212
## Quick Start
1313
This package is available for Docker:

collector/pg_stat_bgwriter.go

Lines changed: 111 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package collector
1616
import (
1717
"context"
1818
"database/sql"
19+
1920
"github.com/blang/semver/v4"
2021
"github.com/prometheus/client_golang/prometheus"
2122
)
@@ -46,6 +47,12 @@ var (
4647
[]string{"collector", "server"},
4748
prometheus.Labels{},
4849
)
50+
statBGWriterCheckpointsDoneDesc = prometheus.NewDesc(
51+
prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_done_total"),
52+
"Number of completed checkpoints",
53+
[]string{"collector", "server"},
54+
prometheus.Labels{},
55+
)
4956
statBGWriterCheckpointsReqTimeDesc = prometheus.NewDesc(
5057
prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoint_write_time_total"),
5158
"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in milliseconds",
@@ -94,6 +101,12 @@ var (
94101
[]string{"collector", "server"},
95102
prometheus.Labels{},
96103
)
104+
statBGWriterCheckpointsSlruWrittenDesc = prometheus.NewDesc(
105+
prometheus.BuildFQName(namespace, bgWriterSubsystem, "slru_written_total"),
106+
"Number of SLRU buffers written during checkpoints and restartpoints",
107+
[]string{"collector", "server"},
108+
prometheus.Labels{},
109+
)
97110
statBGWriterStatsResetDesc = prometheus.NewDesc(
98111
prometheus.BuildFQName(namespace, bgWriterSubsystem, "stats_reset_total"),
99112
"Time at which these statistics were last reset",
@@ -114,6 +127,12 @@ var statBGWriter = map[string]*prometheus.Desc{
114127
[]string{"collector", "server"},
115128
prometheus.Labels{},
116129
),
130+
"percona_checkpoints_done": prometheus.NewDesc(
131+
prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_done"),
132+
"Number of completed checkpoints",
133+
[]string{"collector", "server"},
134+
prometheus.Labels{},
135+
),
117136
"percona_checkpoint_write_time": prometheus.NewDesc(
118137
prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoint_write_time"),
119138
"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in milliseconds",
@@ -162,6 +181,12 @@ var statBGWriter = map[string]*prometheus.Desc{
162181
[]string{"collector", "server"},
163182
prometheus.Labels{},
164183
),
184+
"percona_slru_written": prometheus.NewDesc(
185+
prometheus.BuildFQName(namespace, bgWriterSubsystem, "slru_written"),
186+
"Number of SLRU buffers written during checkpoints and restartpoints",
187+
[]string{"collector", "server"},
188+
prometheus.Labels{},
189+
),
165190
"percona_stats_reset": prometheus.NewDesc(
166191
prometheus.BuildFQName(namespace, bgWriterSubsystem, "stats_reset"),
167192
"Time at which these statistics were last reset",
@@ -191,25 +216,50 @@ const statBGWriterQueryPost17 = `SELECT
191216
,stats_reset
192217
FROM pg_stat_bgwriter;`
193218

194-
const statCheckpointerQuery = `SELECT
195-
num_timed
196-
,num_requested
197-
,restartpoints_timed
198-
,restartpoints_req
199-
,restartpoints_done
200-
,write_time
201-
,sync_time
202-
,buffers_written
203-
,stats_reset
204-
FROM pg_stat_checkpointer;`
219+
const statCheckpointerQueryPrePG18 = `
220+
SELECT
221+
num_timed,
222+
num_requested,
223+
NULL::bigint as num_done,
224+
restartpoints_timed,
225+
restartpoints_req,
226+
restartpoints_done,
227+
write_time,
228+
sync_time,
229+
buffers_written,
230+
NULL::bigint as slru_written,
231+
stats_reset
232+
FROM pg_stat_checkpointer;`
233+
234+
const statCheckpointerQueryPostPG18 = `
235+
SELECT
236+
num_timed,
237+
num_requested,
238+
num_done,
239+
restartpoints_timed,
240+
restartpoints_req,
241+
restartpoints_done,
242+
write_time,
243+
sync_time,
244+
buffers_written,
245+
slru_written,
246+
stats_reset
247+
FROM pg_stat_checkpointer;`
205248

206249
func (p PGStatBGWriterCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
207250
db := instance.getDB()
208251

209-
var cpt, cpr, bcp, bc, mwc, bb, bbf, ba sql.NullInt64
252+
var cpt, cpr, cpd, bcp, bc, mwc, bb, bbf, ba, slruw sql.NullInt64
210253
var cpwt, cpst sql.NullFloat64
211254
var sr sql.NullTime
212255

256+
v18plus := instance.version.GTE(semver.Version{Major: 18})
257+
258+
statCheckpointerQuery := statCheckpointerQueryPrePG18
259+
if v18plus {
260+
statCheckpointerQuery = statCheckpointerQueryPostPG18
261+
}
262+
213263
if instance.version.GE(semver.MustParse("17.0.0")) {
214264
row := db.QueryRowContext(ctx,
215265
statBGWriterQueryPost17)
@@ -219,10 +269,9 @@ func (p PGStatBGWriterCollector) Update(ctx context.Context, instance *instance,
219269
}
220270
var rpt, rpr, rpd sql.NullInt64
221271
var csr sql.NullTime
222-
// these variables are not used, but I left them here for reference
223-
row = db.QueryRowContext(ctx,
224-
statCheckpointerQuery)
225-
err = row.Scan(&cpt, &cpr, &rpt, &rpr, &rpd, &cpwt, &cpst, &bcp, &csr)
272+
273+
row = db.QueryRowContext(ctx, statCheckpointerQuery)
274+
err = row.Scan(&cpt, &cpr, &cpd, &rpt, &rpr, &rpd, &cpwt, &cpst, &bcp, &slruw, &csr)
226275
if err != nil {
227276
return err
228277
}
@@ -257,6 +306,21 @@ func (p PGStatBGWriterCollector) Update(ctx context.Context, instance *instance,
257306
"exporter",
258307
instance.name,
259308
)
309+
310+
cpdMetric := 0.0
311+
if v18plus {
312+
if cpd.Valid {
313+
cpdMetric = float64(cpd.Int64)
314+
}
315+
ch <- prometheus.MustNewConstMetric(
316+
statBGWriterCheckpointsDoneDesc,
317+
prometheus.CounterValue,
318+
cpdMetric,
319+
"exporter",
320+
instance.name,
321+
)
322+
}
323+
260324
cpwtMetric := 0.0
261325
if cpwt.Valid {
262326
cpwtMetric = float64(cpwt.Float64)
@@ -345,6 +409,19 @@ func (p PGStatBGWriterCollector) Update(ctx context.Context, instance *instance,
345409
"exporter",
346410
instance.name,
347411
)
412+
slruwMetric := 0.0
413+
if v18plus {
414+
if slruw.Valid {
415+
slruwMetric = float64(slruw.Int64)
416+
}
417+
ch <- prometheus.MustNewConstMetric(
418+
statBGWriterCheckpointsSlruWrittenDesc,
419+
prometheus.CounterValue,
420+
slruwMetric,
421+
"exporter",
422+
instance.name,
423+
)
424+
}
348425
srMetric := 0.0
349426
if sr.Valid {
350427
srMetric = float64(sr.Time.Unix())
@@ -373,6 +450,15 @@ func (p PGStatBGWriterCollector) Update(ctx context.Context, instance *instance,
373450
"exporter",
374451
instance.name,
375452
)
453+
if v18plus {
454+
ch <- prometheus.MustNewConstMetric(
455+
statBGWriter["percona_checkpoints_done"],
456+
prometheus.CounterValue,
457+
cpdMetric,
458+
"exporter",
459+
instance.name,
460+
)
461+
}
376462
ch <- prometheus.MustNewConstMetric(
377463
statBGWriter["percona_checkpoint_write_time"],
378464
prometheus.CounterValue,
@@ -429,6 +515,15 @@ func (p PGStatBGWriterCollector) Update(ctx context.Context, instance *instance,
429515
"exporter",
430516
instance.name,
431517
)
518+
if v18plus {
519+
ch <- prometheus.MustNewConstMetric(
520+
statBGWriter["percona_slru_written"],
521+
prometheus.CounterValue,
522+
slruwMetric,
523+
"exporter",
524+
instance.name,
525+
)
526+
}
432527
ch <- prometheus.MustNewConstMetric(
433528
statBGWriter["percona_stats_reset"],
434529
prometheus.CounterValue,

0 commit comments

Comments
 (0)