This commit is contained in:
Sylvain Rabot 2025-03-30 13:57:45 +00:00 committed by GitHub
commit 23382c8762
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 92 additions and 40 deletions

View File

@ -36,6 +36,24 @@ func NewPGStatUserTablesCollector(config collectorConfig) (Collector, error) {
} }
var ( var (
statUserTablesRelPages = prometheus.NewDesc(
prometheus.BuildFQName(namespace, userTableSubsystem, "relpages"),
"Estimated number of live pages",
[]string{"datname", "schemaname", "relname"},
prometheus.Labels{},
)
statUserTablesRelSize = prometheus.NewDesc(
prometheus.BuildFQName(namespace, userTableSubsystem, "relsize_bytes"),
"Estimated table size",
[]string{"datname", "schemaname", "relname"},
prometheus.Labels{},
)
statUserTablesRelSizeTotal = prometheus.NewDesc(
prometheus.BuildFQName(namespace, userTableSubsystem, "relsize_total_bytes"),
"Total disk space used by this table, in bytes, including all indexes and TOAST data",
[]string{"datname", "schemaname", "relname"},
prometheus.Labels{},
)
statUserTablesSeqScan = prometheus.NewDesc( statUserTablesSeqScan = prometheus.NewDesc(
prometheus.BuildFQName(namespace, userTableSubsystem, "seq_scan"), prometheus.BuildFQName(namespace, userTableSubsystem, "seq_scan"),
"Number of sequential scans initiated on this table", "Number of sequential scans initiated on this table",
@ -150,17 +168,14 @@ var (
[]string{"datname", "schemaname", "relname"}, []string{"datname", "schemaname", "relname"},
prometheus.Labels{}, prometheus.Labels{},
) )
statUserTablesTotalSize = prometheus.NewDesc(
prometheus.BuildFQName(namespace, userTableSubsystem, "size_bytes"),
"Total disk space used by this table, in bytes, including all indexes and TOAST data",
[]string{"datname", "schemaname", "relname"},
prometheus.Labels{},
)
statUserTablesQuery = `SELECT statUserTablesQuery = `SELECT
current_database() datname, current_database() datname,
schemaname, schemaname,
relname, pg_stat_user_tables.relname,
relpages,
pg_relation_size(relid) AS relsize,
pg_total_relation_size(relid) as relsize_total,
seq_scan, seq_scan,
seq_tup_read, seq_tup_read,
idx_scan, idx_scan,
@ -179,10 +194,11 @@ var (
vacuum_count, vacuum_count,
autovacuum_count, autovacuum_count,
analyze_count, analyze_count,
autoanalyze_count, autoanalyze_count
pg_total_relation_size(relid) as total_size
FROM FROM
pg_stat_user_tables` pg_stat_user_tables
JOIN
pg_class ON pg_stat_user_tables.relid = pg_class.oid`
) )
func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
@ -197,11 +213,11 @@ func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instan
for rows.Next() { for rows.Next() {
var datname, schemaname, relname sql.NullString var datname, schemaname, relname sql.NullString
var seqScan, seqTupRead, idxScan, idxTupFetch, nTupIns, nTupUpd, nTupDel, nTupHotUpd, nLiveTup, nDeadTup, var relPages, relSize, relSizeTotal, seqScan, seqTupRead, idxScan, idxTupFetch, nTupIns, nTupUpd, nTupDel, nTupHotUpd, nLiveTup, nDeadTup,
nModSinceAnalyze, vacuumCount, autovacuumCount, analyzeCount, autoanalyzeCount, totalSize sql.NullInt64 nModSinceAnalyze, vacuumCount, autovacuumCount, analyzeCount, autoanalyzeCount sql.NullInt64
var lastVacuum, lastAutovacuum, lastAnalyze, lastAutoanalyze sql.NullTime var lastVacuum, lastAutovacuum, lastAnalyze, lastAutoanalyze sql.NullTime
if err := rows.Scan(&datname, &schemaname, &relname, &seqScan, &seqTupRead, &idxScan, &idxTupFetch, &nTupIns, &nTupUpd, &nTupDel, &nTupHotUpd, &nLiveTup, &nDeadTup, &nModSinceAnalyze, &lastVacuum, &lastAutovacuum, &lastAnalyze, &lastAutoanalyze, &vacuumCount, &autovacuumCount, &analyzeCount, &autoanalyzeCount, &totalSize); err != nil { if err := rows.Scan(&datname, &schemaname, &relname, &relPages, &relSize, &relSizeTotal, &seqScan, &seqTupRead, &idxScan, &idxTupFetch, &nTupIns, &nTupUpd, &nTupDel, &nTupHotUpd, &nLiveTup, &nDeadTup, &nModSinceAnalyze, &lastVacuum, &lastAutovacuum, &lastAnalyze, &lastAutoanalyze, &vacuumCount, &autovacuumCount, &analyzeCount, &autoanalyzeCount); err != nil {
return err return err
} }
@ -218,6 +234,39 @@ func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instan
relnameLabel = relname.String relnameLabel = relname.String
} }
relPagesMetric := 0.0
if relPages.Valid {
relPagesMetric = float64(relPages.Int64)
}
ch <- prometheus.MustNewConstMetric(
statUserTablesRelPages,
prometheus.GaugeValue,
relPagesMetric,
datnameLabel, schemanameLabel, relnameLabel,
)
relSizeMetric := 0.0
if relSize.Valid {
relSizeMetric = float64(relSize.Int64)
}
ch <- prometheus.MustNewConstMetric(
statUserTablesRelSize,
prometheus.GaugeValue,
relSizeMetric,
datnameLabel, schemanameLabel, relnameLabel,
)
relSizeTotalMetric := 0.0
if relSizeTotal.Valid {
relSizeTotalMetric = float64(relSizeTotal.Int64)
}
ch <- prometheus.MustNewConstMetric(
statUserTablesRelSizeTotal,
prometheus.GaugeValue,
relSizeTotalMetric,
datnameLabel, schemanameLabel, relnameLabel,
)
seqScanMetric := 0.0 seqScanMetric := 0.0
if seqScan.Valid { if seqScan.Valid {
seqScanMetric = float64(seqScan.Int64) seqScanMetric = float64(seqScan.Int64)
@ -426,17 +475,6 @@ func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instan
autoanalyzeCountMetric, autoanalyzeCountMetric,
datnameLabel, schemanameLabel, relnameLabel, datnameLabel, schemanameLabel, relnameLabel,
) )
totalSizeMetric := 0.0
if totalSize.Valid {
totalSizeMetric = float64(totalSize.Int64)
}
ch <- prometheus.MustNewConstMetric(
statUserTablesTotalSize,
prometheus.GaugeValue,
totalSizeMetric,
datnameLabel, schemanameLabel, relnameLabel,
)
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {

View File

@ -53,6 +53,9 @@ func TestPGStatUserTablesCollector(t *testing.T) {
"datname", "datname",
"schemaname", "schemaname",
"relname", "relname",
"relpages",
"relsize",
"relsize_total",
"seq_scan", "seq_scan",
"seq_tup_read", "seq_tup_read",
"idx_scan", "idx_scan",
@ -71,8 +74,7 @@ func TestPGStatUserTablesCollector(t *testing.T) {
"vacuum_count", "vacuum_count",
"autovacuum_count", "autovacuum_count",
"analyze_count", "analyze_count",
"autoanalyze_count", "autoanalyze_count"}
"total_size"}
rows := sqlmock.NewRows(columns). rows := sqlmock.NewRows(columns).
AddRow("postgres", AddRow("postgres",
"public", "public",
@ -87,16 +89,18 @@ func TestPGStatUserTablesCollector(t *testing.T) {
8, 8,
9, 9,
10, 10,
11,
12,
13,
0, 0,
lastVacuumTime, lastVacuumTime,
lastAutoVacuumTime, lastAutoVacuumTime,
lastAnalyzeTime, lastAnalyzeTime,
lastAutoAnalyzeTime, lastAutoAnalyzeTime,
11,
12,
13,
14, 14,
15) 15,
16,
17)
mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows) mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows)
ch := make(chan prometheus.Metric) ch := make(chan prometheus.Metric)
go func() { go func() {
@ -109,25 +113,28 @@ func TestPGStatUserTablesCollector(t *testing.T) {
}() }()
expected := []MetricResult{ expected := []MetricResult{
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 1}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 2}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 2},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 3}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 3},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 4}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 4},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 5}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 5},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 6}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 6},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 7}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 7},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 8}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 8},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 9}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 9},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 10}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 10},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 11},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 12},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 13},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 0}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 0},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685664000}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685664000},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685750400}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685750400},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685836800}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685836800},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685923200}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685923200},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 11},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 12},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 13},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 14}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 14},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 15},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 16},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 17},
} }
convey.Convey("Metrics comparison", t, func() { convey.Convey("Metrics comparison", t, func() {
@ -154,6 +161,9 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) {
"datname", "datname",
"schemaname", "schemaname",
"relname", "relname",
"relpages",
"relsize",
"relsize_total",
"seq_scan", "seq_scan",
"seq_tup_read", "seq_tup_read",
"idx_scan", "idx_scan",
@ -172,8 +182,7 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) {
"vacuum_count", "vacuum_count",
"autovacuum_count", "autovacuum_count",
"analyze_count", "analyze_count",
"autoanalyze_count", "autoanalyze_count"}
"total_size"}
rows := sqlmock.NewRows(columns). rows := sqlmock.NewRows(columns).
AddRow("postgres", AddRow("postgres",
nil, nil,
@ -197,6 +206,8 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) {
nil, nil,
nil, nil,
nil, nil,
nil,
nil,
nil) nil)
mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows) mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows)
ch := make(chan prometheus.Metric) ch := make(chan prometheus.Metric)
@ -210,6 +221,9 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) {
}() }()
expected := []MetricResult{ expected := []MetricResult{
{labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0},
{labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0},
{labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0},
{labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0},
{labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0},
{labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0},