diff --git a/collector/pg_stat_statements.go b/collector/pg_stat_statements.go index c03e78b92..f3df22cae 100644 --- a/collector/pg_stat_statements.go +++ b/collector/pg_stat_statements.go @@ -40,34 +40,34 @@ func NewPGStatStatementsCollector(config collectorConfig) (Collector, error) { } var ( - statSTatementsCallsTotal = prometheus.NewDesc( + statStatementsCallsTotal = prometheus.NewDesc( prometheus.BuildFQName(namespace, statStatementsSubsystem, "calls_total"), "Number of times executed", - []string{"user", "datname", "queryid"}, + []string{"user", "datname", "queryid", "query", "stmt_type"}, prometheus.Labels{}, ) statStatementsSecondsTotal = prometheus.NewDesc( prometheus.BuildFQName(namespace, statStatementsSubsystem, "seconds_total"), "Total time spent in the statement, in seconds", - []string{"user", "datname", "queryid"}, + []string{"user", "datname", "queryid", "query", "stmt_type"}, prometheus.Labels{}, ) statStatementsRowsTotal = prometheus.NewDesc( prometheus.BuildFQName(namespace, statStatementsSubsystem, "rows_total"), "Total number of rows retrieved or affected by the statement", - []string{"user", "datname", "queryid"}, + []string{"user", "datname", "queryid", "query", "stmt_type"}, prometheus.Labels{}, ) statStatementsBlockReadSecondsTotal = prometheus.NewDesc( prometheus.BuildFQName(namespace, statStatementsSubsystem, "block_read_seconds_total"), "Total time the statement spent reading blocks, in seconds", - []string{"user", "datname", "queryid"}, + []string{"user", "datname", "queryid", "query", "stmt_type"}, prometheus.Labels{}, ) statStatementsBlockWriteSecondsTotal = prometheus.NewDesc( prometheus.BuildFQName(namespace, statStatementsSubsystem, "block_write_seconds_total"), "Total time the statement spent writing blocks, in seconds", - []string{"user", "datname", "queryid"}, + []string{"user", "datname", "queryid", "query", "stmt_type"}, prometheus.Labels{}, ) @@ -75,6 +75,14 @@ var ( pg_get_userbyid(userid) as user, pg_database.datname, pg_stat_statements.queryid, + LEFT(pg_stat_statements.query, 120) as query, + CASE + WHEN pg_stat_statements.query ILIKE 'SELECT%' THEN 'SELECT' + WHEN pg_stat_statements.query ILIKE 'INSERT%' THEN 'INSERT' + WHEN pg_stat_statements.query ILIKE 'UPDATE%' THEN 'UPDATE' + WHEN pg_stat_statements.query ILIKE 'DELETE%' THEN 'DELETE' + ELSE 'OTHER' + END AS stmt_type, pg_stat_statements.calls as calls_total, pg_stat_statements.total_time / 1000.0 as seconds_total, pg_stat_statements.rows as rows_total, @@ -96,6 +104,14 @@ var ( pg_get_userbyid(userid) as user, pg_database.datname, pg_stat_statements.queryid, + LEFT(pg_stat_statements.query, 120) as query, + CASE + WHEN pg_stat_statements.query ILIKE 'SELECT%' THEN 'SELECT' + WHEN pg_stat_statements.query ILIKE 'INSERT%' THEN 'INSERT' + WHEN pg_stat_statements.query ILIKE 'UPDATE%' THEN 'UPDATE' + WHEN pg_stat_statements.query ILIKE 'DELETE%' THEN 'DELETE' + ELSE 'OTHER' + END AS stmt_type, 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, @@ -128,11 +144,11 @@ func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, } defer rows.Close() for rows.Next() { - var user, datname, queryid sql.NullString + var user, datname, queryid, query, stmt_type sql.NullString var callsTotal, rowsTotal sql.NullInt64 var secondsTotal, blockReadSecondsTotal, blockWriteSecondsTotal sql.NullFloat64 - if err := rows.Scan(&user, &datname, &queryid, &callsTotal, &secondsTotal, &rowsTotal, &blockReadSecondsTotal, &blockWriteSecondsTotal); err != nil { + if err := rows.Scan(&user, &datname, &queryid, &query, &stmt_type, &callsTotal, &secondsTotal, &rowsTotal, &blockReadSecondsTotal, &blockWriteSecondsTotal); err != nil { return err } @@ -148,16 +164,23 @@ func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, if queryid.Valid { queryidLabel = queryid.String } - + queryLabel := "unknown" + if query.Valid { + queryLabel = query.String + } + stmt_typeLabel := "unknown" + if stmt_type.Valid { + stmt_typeLabel = stmt_type.String + } callsTotalMetric := 0.0 if callsTotal.Valid { callsTotalMetric = float64(callsTotal.Int64) } ch <- prometheus.MustNewConstMetric( - statSTatementsCallsTotal, + statStatementsCallsTotal, prometheus.CounterValue, callsTotalMetric, - userLabel, datnameLabel, queryidLabel, + userLabel, datnameLabel, queryidLabel, queryLabel, stmt_typeLabel, ) secondsTotalMetric := 0.0 @@ -168,7 +191,7 @@ func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, statStatementsSecondsTotal, prometheus.CounterValue, secondsTotalMetric, - userLabel, datnameLabel, queryidLabel, + userLabel, datnameLabel, queryidLabel, queryLabel, stmt_typeLabel, ) rowsTotalMetric := 0.0 @@ -179,7 +202,7 @@ func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, statStatementsRowsTotal, prometheus.CounterValue, rowsTotalMetric, - userLabel, datnameLabel, queryidLabel, + userLabel, datnameLabel, queryidLabel, queryLabel, stmt_typeLabel, ) blockReadSecondsTotalMetric := 0.0 @@ -190,7 +213,7 @@ func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, statStatementsBlockReadSecondsTotal, prometheus.CounterValue, blockReadSecondsTotalMetric, - userLabel, datnameLabel, queryidLabel, + userLabel, datnameLabel, queryidLabel, queryLabel, stmt_typeLabel, ) blockWriteSecondsTotalMetric := 0.0 @@ -201,7 +224,7 @@ func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, statStatementsBlockWriteSecondsTotal, prometheus.CounterValue, blockWriteSecondsTotalMetric, - userLabel, datnameLabel, queryidLabel, + userLabel, datnameLabel, queryidLabel, queryLabel, stmt_typeLabel, ) } if err := rows.Err(); err != nil { diff --git a/collector/pg_stat_statements_test.go b/collector/pg_stat_statements_test.go index 08aba34c2..b7b9cd628 100644 --- a/collector/pg_stat_statements_test.go +++ b/collector/pg_stat_statements_test.go @@ -32,9 +32,9 @@ func TestPGStateStatementsCollector(t *testing.T) { 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", "query", "stmt_type", "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) + AddRow("postgres", "postgres", 1500, "SELECT", "SELECT", 5, 0.4, 100, 0.1, 0.2) mock.ExpectQuery(sanitizeQuery(pgStatStatementsQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -48,11 +48,11 @@ func TestPGStateStatementsCollector(t *testing.T) { }() 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}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "query": "SELECT", "stmt_type": "SELECT", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 5}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "query": "SELECT", "stmt_type": "SELECT", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.4}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "query": "SELECT", "stmt_type": "SELECT", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 100}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "query": "SELECT", "stmt_type": "SELECT", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.1}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "query": "SELECT", "stmt_type": "SELECT", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.2}, } convey.Convey("Metrics comparison", t, func() { @@ -75,9 +75,9 @@ func TestPGStateStatementsCollectorNull(t *testing.T) { 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", "query", "stmt_type", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} rows := sqlmock.NewRows(columns). - AddRow(nil, nil, nil, nil, nil, nil, nil, nil) + AddRow(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) mock.ExpectQuery(sanitizeQuery(pgStatStatementsNewQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -91,11 +91,11 @@ func TestPGStateStatementsCollectorNull(t *testing.T) { }() expected := []MetricResult{ - {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "query": "unknown", "stmt_type": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "query": "unknown", "stmt_type": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "query": "unknown", "stmt_type": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "query": "unknown", "stmt_type": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "query": "unknown", "stmt_type": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, } convey.Convey("Metrics comparison", t, func() { @@ -118,9 +118,9 @@ func TestPGStateStatementsCollectorNewPG(t *testing.T) { 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", "query", "stmt_type", "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) + AddRow("postgres", "postgres", 1500, "SELECT", "SELECT", 5, 0.4, 100, 0.1, 0.2) mock.ExpectQuery(sanitizeQuery(pgStatStatementsNewQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -134,11 +134,11 @@ func TestPGStateStatementsCollectorNewPG(t *testing.T) { }() 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}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "query": "SELECT", "stmt_type": "SELECT", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 5}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "query": "SELECT", "stmt_type": "SELECT", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.4}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "query": "SELECT", "stmt_type": "SELECT", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 100}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "query": "SELECT", "stmt_type": "SELECT", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.1}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "query": "SELECT", "stmt_type": "SELECT", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.2}, } convey.Convey("Metrics comparison", t, func() {