mirror of
https://github.com/prometheus-community/postgres_exporter
synced 2025-02-27 16:01:05 +00:00
Handle new pg_stat_statements column names (#874)
Update pg_stat_statements collector to handle the new column names in PostgreSQL 13. Fixes: https://github.com/prometheus-community/postgres_exporter/issues/502 Signed-off-by: SuperQ <superq@gmail.com>
This commit is contained in:
parent
74800f483a
commit
f9277b04b7
@ -17,6 +17,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/blang/semver/v4"
|
||||||
"github.com/go-kit/log"
|
"github.com/go-kit/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
@ -90,12 +91,37 @@ var (
|
|||||||
)
|
)
|
||||||
ORDER BY seconds_total DESC
|
ORDER BY seconds_total DESC
|
||||||
LIMIT 100;`
|
LIMIT 100;`
|
||||||
|
|
||||||
|
pgStatStatementsNewQuery = `SELECT
|
||||||
|
pg_get_userbyid(userid) as user,
|
||||||
|
pg_database.datname,
|
||||||
|
pg_stat_statements.queryid,
|
||||||
|
pg_stat_statements.calls as calls_total,
|
||||||
|
pg_stat_statements.total_exec_time / 1000.0 as seconds_total,
|
||||||
|
pg_stat_statements.rows as rows_total,
|
||||||
|
pg_stat_statements.blk_read_time / 1000.0 as block_read_seconds_total,
|
||||||
|
pg_stat_statements.blk_write_time / 1000.0 as block_write_seconds_total
|
||||||
|
FROM pg_stat_statements
|
||||||
|
JOIN pg_database
|
||||||
|
ON pg_database.oid = pg_stat_statements.dbid
|
||||||
|
WHERE
|
||||||
|
total_time > (
|
||||||
|
SELECT percentile_cont(0.1)
|
||||||
|
WITHIN GROUP (ORDER BY total_time)
|
||||||
|
FROM pg_stat_statements
|
||||||
|
)
|
||||||
|
ORDER BY seconds_total DESC
|
||||||
|
LIMIT 100;`
|
||||||
)
|
)
|
||||||
|
|
||||||
func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
|
func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
|
||||||
|
query := pgStatStatementsQuery
|
||||||
|
if instance.version.GE(semver.MustParse("13.0.0")) {
|
||||||
|
query = pgStatStatementsNewQuery
|
||||||
|
}
|
||||||
|
|
||||||
db := instance.getDB()
|
db := instance.getDB()
|
||||||
rows, err := db.QueryContext(ctx,
|
rows, err := db.QueryContext(ctx, query)
|
||||||
pgStatStatementsQuery)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/DATA-DOG/go-sqlmock"
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
"github.com/blang/semver/v4"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
"github.com/smartystreets/goconvey/convey"
|
"github.com/smartystreets/goconvey/convey"
|
||||||
@ -29,7 +30,7 @@ func TestPGStateStatementsCollector(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
inst := &instance{db: db}
|
inst := &instance{db: db, version: semver.MustParse("12.0.0")}
|
||||||
|
|
||||||
columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"}
|
columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
@ -72,12 +73,12 @@ func TestPGStateStatementsCollectorNull(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
inst := &instance{db: db}
|
inst := &instance{db: db, version: semver.MustParse("13.3.7")}
|
||||||
|
|
||||||
columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"}
|
columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"}
|
||||||
rows := sqlmock.NewRows(columns).
|
rows := sqlmock.NewRows(columns).
|
||||||
AddRow(nil, nil, nil, nil, nil, nil, nil, nil)
|
AddRow(nil, nil, nil, nil, nil, nil, nil, nil)
|
||||||
mock.ExpectQuery(sanitizeQuery(pgStatStatementsQuery)).WillReturnRows(rows)
|
mock.ExpectQuery(sanitizeQuery(pgStatStatementsNewQuery)).WillReturnRows(rows)
|
||||||
|
|
||||||
ch := make(chan prometheus.Metric)
|
ch := make(chan prometheus.Metric)
|
||||||
go func() {
|
go func() {
|
||||||
@ -107,3 +108,46 @@ func TestPGStateStatementsCollectorNull(t *testing.T) {
|
|||||||
t.Errorf("there were unfulfilled exceptions: %s", err)
|
t.Errorf("there were unfulfilled exceptions: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPGStateStatementsCollectorNewPG(t *testing.T) {
|
||||||
|
db, mock, err := sqlmock.New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error opening a stub db connection: %s", err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
inst := &instance{db: db, version: semver.MustParse("13.3.7")}
|
||||||
|
|
||||||
|
columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"}
|
||||||
|
rows := sqlmock.NewRows(columns).
|
||||||
|
AddRow("postgres", "postgres", 1500, 5, 0.4, 100, 0.1, 0.2)
|
||||||
|
mock.ExpectQuery(sanitizeQuery(pgStatStatementsNewQuery)).WillReturnRows(rows)
|
||||||
|
|
||||||
|
ch := make(chan prometheus.Metric)
|
||||||
|
go func() {
|
||||||
|
defer close(ch)
|
||||||
|
c := PGStatStatementsCollector{}
|
||||||
|
|
||||||
|
if err := c.Update(context.Background(), inst, ch); err != nil {
|
||||||
|
t.Errorf("Error calling PGStatStatementsCollector.Update: %s", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
expected := []MetricResult{
|
||||||
|
{labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 5},
|
||||||
|
{labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.4},
|
||||||
|
{labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 100},
|
||||||
|
{labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.1},
|
||||||
|
{labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.2},
|
||||||
|
}
|
||||||
|
|
||||||
|
convey.Convey("Metrics comparison", t, func() {
|
||||||
|
for _, expect := range expected {
|
||||||
|
m := readMetric(<-ch)
|
||||||
|
convey.So(expect, convey.ShouldResemble, m)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err := mock.ExpectationsWereMet(); err != nil {
|
||||||
|
t.Errorf("there were unfulfilled exceptions: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user