Skip to content

Commit 072864d

Browse files
authored
pg_stat_statements PG17 (#1114)
Signed-off-by: Nevermind <[email protected]>
1 parent d85a771 commit 072864d

File tree

2 files changed

+71
-2
lines changed

2 files changed

+71
-2
lines changed

Diff for: collector/pg_stat_statements.go

+28-2
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,38 @@ var (
112112
)
113113
ORDER BY seconds_total DESC
114114
LIMIT 100;`
115+
116+
pgStatStatementsQuery_PG17 = `SELECT
117+
pg_get_userbyid(userid) as user,
118+
pg_database.datname,
119+
pg_stat_statements.queryid,
120+
pg_stat_statements.calls as calls_total,
121+
pg_stat_statements.total_exec_time / 1000.0 as seconds_total,
122+
pg_stat_statements.rows as rows_total,
123+
pg_stat_statements.shared_blk_read_time / 1000.0 as block_read_seconds_total,
124+
pg_stat_statements.shared_blk_write_time / 1000.0 as block_write_seconds_total
125+
FROM pg_stat_statements
126+
JOIN pg_database
127+
ON pg_database.oid = pg_stat_statements.dbid
128+
WHERE
129+
total_exec_time > (
130+
SELECT percentile_cont(0.1)
131+
WITHIN GROUP (ORDER BY total_exec_time)
132+
FROM pg_stat_statements
133+
)
134+
ORDER BY seconds_total DESC
135+
LIMIT 100;`
115136
)
116137

117138
func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
118-
query := pgStatStatementsQuery
119-
if instance.version.GE(semver.MustParse("13.0.0")) {
139+
var query string
140+
switch {
141+
case instance.version.GE(semver.MustParse("17.0.0")):
142+
query = pgStatStatementsQuery_PG17
143+
case instance.version.GE(semver.MustParse("13.0.0")):
120144
query = pgStatStatementsNewQuery
145+
default:
146+
query = pgStatStatementsQuery
121147
}
122148

123149
db := instance.getDB()

Diff for: collector/pg_stat_statements_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,46 @@ func TestPGStateStatementsCollectorNewPG(t *testing.T) {
151151
t.Errorf("there were unfulfilled exceptions: %s", err)
152152
}
153153
}
154+
155+
func TestPGStateStatementsCollector_PG17(t *testing.T) {
156+
db, mock, err := sqlmock.New()
157+
if err != nil {
158+
t.Fatalf("Error opening a stub db connection: %s", err)
159+
}
160+
defer db.Close()
161+
162+
inst := &instance{db: db, version: semver.MustParse("17.0.0")}
163+
164+
columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"}
165+
rows := sqlmock.NewRows(columns).
166+
AddRow("postgres", "postgres", 1500, 5, 0.4, 100, 0.1, 0.2)
167+
mock.ExpectQuery(sanitizeQuery(pgStatStatementsQuery_PG17)).WillReturnRows(rows)
168+
169+
ch := make(chan prometheus.Metric)
170+
go func() {
171+
defer close(ch)
172+
c := PGStatStatementsCollector{}
173+
174+
if err := c.Update(context.Background(), inst, ch); err != nil {
175+
t.Errorf("Error calling PGStatStatementsCollector.Update: %s", err)
176+
}
177+
}()
178+
179+
expected := []MetricResult{
180+
{labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 5},
181+
{labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.4},
182+
{labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 100},
183+
{labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.1},
184+
{labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.2},
185+
}
186+
187+
convey.Convey("Metrics comparison", t, func() {
188+
for _, expect := range expected {
189+
m := readMetric(<-ch)
190+
convey.So(expect, convey.ShouldResemble, m)
191+
}
192+
})
193+
if err := mock.ExpectationsWereMet(); err != nil {
194+
t.Errorf("there were unfulfilled exceptions: %s", err)
195+
}
196+
}

0 commit comments

Comments
 (0)