Skip to content

Commit 49f66e1

Browse files
authored
fix: Only query active_time on pg>=14 (#1045)
Signed-off-by: MarcWort <[email protected]>
1 parent a4ac0e6 commit 49f66e1

File tree

2 files changed

+84
-60
lines changed

2 files changed

+84
-60
lines changed

collector/pg_stat_database.go

+54-37
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ package collector
1616
import (
1717
"context"
1818
"database/sql"
19+
"fmt"
20+
"strings"
1921

22+
"github.com/blang/semver/v4"
2023
"github.com/go-kit/log"
2124
"github.com/go-kit/log/level"
2225
"github.com/prometheus/client_golang/prometheus"
@@ -215,37 +218,44 @@ var (
215218
[]string{"datid", "datname"},
216219
prometheus.Labels{},
217220
)
218-
219-
statDatabaseQuery = `
220-
SELECT
221-
datid
222-
,datname
223-
,numbackends
224-
,xact_commit
225-
,xact_rollback
226-
,blks_read
227-
,blks_hit
228-
,tup_returned
229-
,tup_fetched
230-
,tup_inserted
231-
,tup_updated
232-
,tup_deleted
233-
,conflicts
234-
,temp_files
235-
,temp_bytes
236-
,deadlocks
237-
,blk_read_time
238-
,blk_write_time
239-
,active_time
240-
,stats_reset
241-
FROM pg_stat_database;
242-
`
243221
)
244222

223+
func statDatabaseQuery(columns []string) string {
224+
return fmt.Sprintf("SELECT %s FROM pg_stat_database;", strings.Join(columns, ","))
225+
}
226+
245227
func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
246228
db := instance.getDB()
229+
230+
columns := []string{
231+
"datid",
232+
"datname",
233+
"numbackends",
234+
"xact_commit",
235+
"xact_rollback",
236+
"blks_read",
237+
"blks_hit",
238+
"tup_returned",
239+
"tup_fetched",
240+
"tup_inserted",
241+
"tup_updated",
242+
"tup_deleted",
243+
"conflicts",
244+
"temp_files",
245+
"temp_bytes",
246+
"deadlocks",
247+
"blk_read_time",
248+
"blk_write_time",
249+
"stats_reset",
250+
}
251+
252+
activeTimeAvail := instance.version.GTE(semver.MustParse("14.0.0"))
253+
if activeTimeAvail {
254+
columns = append(columns, "active_time")
255+
}
256+
247257
rows, err := db.QueryContext(ctx,
248-
statDatabaseQuery,
258+
statDatabaseQuery(columns),
249259
)
250260
if err != nil {
251261
return err
@@ -257,7 +267,7 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance
257267
var numBackends, xactCommit, xactRollback, blksRead, blksHit, tupReturned, tupFetched, tupInserted, tupUpdated, tupDeleted, conflicts, tempFiles, tempBytes, deadlocks, blkReadTime, blkWriteTime, activeTime sql.NullFloat64
258268
var statsReset sql.NullTime
259269

260-
err := rows.Scan(
270+
r := []any{
261271
&datid,
262272
&datname,
263273
&numBackends,
@@ -276,9 +286,14 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance
276286
&deadlocks,
277287
&blkReadTime,
278288
&blkWriteTime,
279-
&activeTime,
280289
&statsReset,
281-
)
290+
}
291+
292+
if activeTimeAvail {
293+
r = append(r, &activeTime)
294+
}
295+
296+
err := rows.Scan(r...)
282297
if err != nil {
283298
return err
284299
}
@@ -355,7 +370,7 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance
355370
level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blk_write_time")
356371
continue
357372
}
358-
if !activeTime.Valid {
373+
if activeTimeAvail && !activeTime.Valid {
359374
level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no active_time")
360375
continue
361376
}
@@ -482,19 +497,21 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance
482497
labels...,
483498
)
484499

485-
ch <- prometheus.MustNewConstMetric(
486-
statDatabaseActiveTime,
487-
prometheus.CounterValue,
488-
activeTime.Float64/1000.0,
489-
labels...,
490-
)
491-
492500
ch <- prometheus.MustNewConstMetric(
493501
statDatabaseStatsReset,
494502
prometheus.CounterValue,
495503
statsResetMetric,
496504
labels...,
497505
)
506+
507+
if activeTimeAvail {
508+
ch <- prometheus.MustNewConstMetric(
509+
statDatabaseActiveTime,
510+
prometheus.CounterValue,
511+
activeTime.Float64/1000.0,
512+
labels...,
513+
)
514+
}
498515
}
499516
return nil
500517
}

collector/pg_stat_database_test.go

+30-23
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"time"
1919

2020
"github.com/DATA-DOG/go-sqlmock"
21+
"github.com/blang/semver/v4"
2122
"github.com/go-kit/log"
2223
"github.com/prometheus/client_golang/prometheus"
2324
dto "github.com/prometheus/client_model/go"
@@ -31,7 +32,7 @@ func TestPGStatDatabaseCollector(t *testing.T) {
3132
}
3233
defer db.Close()
3334

34-
inst := &instance{db: db}
35+
inst := &instance{db: db, version: semver.MustParse("14.0.0")}
3536

3637
columns := []string{
3738
"datid",
@@ -52,8 +53,8 @@ func TestPGStatDatabaseCollector(t *testing.T) {
5253
"deadlocks",
5354
"blk_read_time",
5455
"blk_write_time",
55-
"active_time",
5656
"stats_reset",
57+
"active_time",
5758
}
5859

5960
srT, err := time.Parse("2006-01-02 15:04:05.00000-07", "2023-05-25 17:10:42.81132-07")
@@ -81,10 +82,11 @@ func TestPGStatDatabaseCollector(t *testing.T) {
8182
925,
8283
16,
8384
823,
85+
srT,
8486
33,
85-
srT)
87+
)
8688

87-
mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows)
89+
mock.ExpectQuery(sanitizeQuery(statDatabaseQuery(columns))).WillReturnRows(rows)
8890

8991
ch := make(chan prometheus.Metric)
9092
go func() {
@@ -115,8 +117,8 @@ func TestPGStatDatabaseCollector(t *testing.T) {
115117
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925},
116118
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16},
117119
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823},
118-
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.033},
119120
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842},
121+
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.033},
120122
}
121123

122124
convey.Convey("Metrics comparison", t, func() {
@@ -141,7 +143,7 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) {
141143
if err != nil {
142144
t.Fatalf("Error parsing time: %s", err)
143145
}
144-
inst := &instance{db: db}
146+
inst := &instance{db: db, version: semver.MustParse("14.0.0")}
145147

146148
columns := []string{
147149
"datid",
@@ -162,8 +164,8 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) {
162164
"deadlocks",
163165
"blk_read_time",
164166
"blk_write_time",
165-
"active_time",
166167
"stats_reset",
168+
"active_time",
167169
}
168170

169171
rows := sqlmock.NewRows(columns).
@@ -186,8 +188,9 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) {
186188
925,
187189
16,
188190
823,
191+
srT,
189192
32,
190-
srT).
193+
).
191194
AddRow(
192195
"pid",
193196
"postgres",
@@ -207,9 +210,10 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) {
207210
925,
208211
16,
209212
823,
213+
srT,
210214
32,
211-
srT)
212-
mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows)
215+
)
216+
mock.ExpectQuery(sanitizeQuery(statDatabaseQuery(columns))).WillReturnRows(rows)
213217

214218
ch := make(chan prometheus.Metric)
215219
go func() {
@@ -240,8 +244,8 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) {
240244
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925},
241245
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16},
242246
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823},
243-
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.032},
244247
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842},
248+
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.032},
245249
}
246250

247251
convey.Convey("Metrics comparison", t, func() {
@@ -261,7 +265,7 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) {
261265
}
262266
defer db.Close()
263267

264-
inst := &instance{db: db}
268+
inst := &instance{db: db, version: semver.MustParse("14.0.0")}
265269

266270
columns := []string{
267271
"datid",
@@ -282,8 +286,8 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) {
282286
"deadlocks",
283287
"blk_read_time",
284288
"blk_write_time",
285-
"active_time",
286289
"stats_reset",
290+
"active_time",
287291
}
288292

289293
srT, err := time.Parse("2006-01-02 15:04:05.00000-07", "2023-05-25 17:10:42.81132-07")
@@ -311,8 +315,9 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) {
311315
925,
312316
16,
313317
823,
318+
srT,
314319
14,
315-
srT).
320+
).
316321
AddRow(
317322
nil,
318323
nil,
@@ -354,9 +359,10 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) {
354359
926,
355360
17,
356361
824,
362+
srT,
357363
15,
358-
srT)
359-
mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows)
364+
)
365+
mock.ExpectQuery(sanitizeQuery(statDatabaseQuery(columns))).WillReturnRows(rows)
360366

361367
ch := make(chan prometheus.Metric)
362368
go func() {
@@ -387,8 +393,8 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) {
387393
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925},
388394
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16},
389395
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823},
390-
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.014},
391396
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842},
397+
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.014},
392398

393399
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_GAUGE, value: 355},
394400
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 4946},
@@ -406,8 +412,8 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) {
406412
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 926},
407413
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 17},
408414
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 824},
409-
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.015},
410415
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842},
416+
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.015},
411417
}
412418

413419
convey.Convey("Metrics comparison", t, func() {
@@ -428,7 +434,7 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) {
428434
}
429435
defer db.Close()
430436

431-
inst := &instance{db: db}
437+
inst := &instance{db: db, version: semver.MustParse("14.0.0")}
432438

433439
columns := []string{
434440
"datid",
@@ -449,8 +455,8 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) {
449455
"deadlocks",
450456
"blk_read_time",
451457
"blk_write_time",
452-
"active_time",
453458
"stats_reset",
459+
"active_time",
454460
}
455461

456462
rows := sqlmock.NewRows(columns).
@@ -473,10 +479,11 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) {
473479
925,
474480
16,
475481
823,
482+
nil,
476483
7,
477-
nil)
484+
)
478485

479-
mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows)
486+
mock.ExpectQuery(sanitizeQuery(statDatabaseQuery(columns))).WillReturnRows(rows)
480487

481488
ch := make(chan prometheus.Metric)
482489
go func() {
@@ -507,8 +514,8 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) {
507514
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925},
508515
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16},
509516
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823},
510-
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.007},
511517
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0},
518+
{labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.007},
512519
}
513520

514521
convey.Convey("Metrics comparison", t, func() {

0 commit comments

Comments
 (0)