diff --git a/collector/pg_stat_user_tables.go b/collector/pg_stat_user_tables.go index 949a0ea2b..67467d773 100644 --- a/collector/pg_stat_user_tables.go +++ b/collector/pg_stat_user_tables.go @@ -36,6 +36,18 @@ func NewPGStatUserTablesCollector(config collectorConfig) (Collector, error) { } 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"), + "Estimated table size", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) statUserTablesSeqScan = prometheus.NewDesc( prometheus.BuildFQName(namespace, userTableSubsystem, "seq_scan"), "Number of sequential scans initiated on this table", @@ -154,7 +166,9 @@ var ( statUserTablesQuery = `SELECT current_database() datname, schemaname, - relname, + pg_stat_user_tables.relname, + relpages, + pg_relation_size(pg_stat_user_tables.relname::text::regclass) AS relsize, seq_scan, seq_tup_read, idx_scan, @@ -175,7 +189,9 @@ var ( analyze_count, autoanalyze_count 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 { @@ -190,11 +206,11 @@ func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instan for rows.Next() { var datname, schemaname, relname sql.NullString - var seqScan, seqTupRead, idxScan, idxTupFetch, nTupIns, nTupUpd, nTupDel, nTupHotUpd, nLiveTup, nDeadTup, + var relPages, relSize, seqScan, seqTupRead, idxScan, idxTupFetch, nTupIns, nTupUpd, nTupDel, nTupHotUpd, nLiveTup, nDeadTup, nModSinceAnalyze, vacuumCount, autovacuumCount, analyzeCount, autoanalyzeCount sql.NullInt64 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); err != nil { + if err := rows.Scan(&datname, &schemaname, &relname, &relPages, &relSize, &seqScan, &seqTupRead, &idxScan, &idxTupFetch, &nTupIns, &nTupUpd, &nTupDel, &nTupHotUpd, &nLiveTup, &nDeadTup, &nModSinceAnalyze, &lastVacuum, &lastAutovacuum, &lastAnalyze, &lastAutoanalyze, &vacuumCount, &autovacuumCount, &analyzeCount, &autoanalyzeCount); err != nil { return err } @@ -211,6 +227,28 @@ func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instan 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, + ) + seqScanMetric := 0.0 if seqScan.Valid { seqScanMetric = float64(seqScan.Int64) diff --git a/collector/pg_stat_user_tables_test.go b/collector/pg_stat_user_tables_test.go index e592fa5e4..488ad008c 100644 --- a/collector/pg_stat_user_tables_test.go +++ b/collector/pg_stat_user_tables_test.go @@ -53,6 +53,8 @@ func TestPGStatUserTablesCollector(t *testing.T) { "datname", "schemaname", "relname", + "relpages", + "relsize", "seq_scan", "seq_tup_read", "idx_scan", @@ -86,15 +88,17 @@ func TestPGStatUserTablesCollector(t *testing.T) { 8, 9, 10, + 11, + 12, 0, lastVacuumTime, lastAutoVacuumTime, lastAnalyzeTime, lastAutoAnalyzeTime, - 11, - 12, 13, - 14) + 14, + 15, + 16) mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -107,25 +111,27 @@ func TestPGStatUserTablesCollector(t *testing.T) { }() 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_COUNTER, value: 2}, + {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_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_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: 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: 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_GAUGE, value: 10}, + {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_COUNTER, value: 10}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, 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: 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: 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: 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: 15}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 16}, } convey.Convey("Metrics comparison", t, func() { @@ -152,6 +158,8 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) { "datname", "schemaname", "relname", + "relpages", + "relsize", "seq_scan", "seq_tup_read", "idx_scan", @@ -193,6 +201,8 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) { nil, nil, nil, + nil, + nil, nil) mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -206,6 +216,8 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) { }() 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_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},