Record table only size bytes as well in addition to the total size bytes

Signed-off-by: Felix Yuan <felix.yuan@reddit.com>
This commit is contained in:
Felix Yuan 2025-04-09 09:49:04 -07:00
parent f8b7139174
commit 4bb84e9fa3
2 changed files with 32 additions and 6 deletions

View File

@ -156,6 +156,12 @@ var (
[]string{"datname", "schemaname", "relname"}, []string{"datname", "schemaname", "relname"},
prometheus.Labels{}, prometheus.Labels{},
) )
statUserTablesOnlySize = prometheus.NewDesc(
prometheus.BuildFQName(namespace, userTableSubsystem, "only_size_bytes"),
"Total disk space used by only this table, in bytes",
[]string{"datname", "schemaname", "relname"},
prometheus.Labels{},
)
statUserTablesQuery = `SELECT statUserTablesQuery = `SELECT
current_database() datname, current_database() datname,
@ -180,7 +186,8 @@ var (
autovacuum_count, autovacuum_count,
analyze_count, analyze_count,
autoanalyze_count, autoanalyze_count,
pg_total_relation_size(relid) as total_size pg_total_relation_size(relid) as total_size,
pg_table_size(relid) as table_only_size
FROM FROM
pg_stat_user_tables` pg_stat_user_tables`
) )
@ -198,10 +205,10 @@ 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 seqScan, seqTupRead, idxScan, idxTupFetch, nTupIns, nTupUpd, nTupDel, nTupHotUpd, nLiveTup, nDeadTup,
nModSinceAnalyze, vacuumCount, autovacuumCount, analyzeCount, autoanalyzeCount, totalSize sql.NullInt64 nModSinceAnalyze, vacuumCount, autovacuumCount, analyzeCount, autoanalyzeCount, totalSize, tableOnlySize 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, &seqScan, &seqTupRead, &idxScan, &idxTupFetch, &nTupIns, &nTupUpd, &nTupDel, &nTupHotUpd, &nLiveTup, &nDeadTup, &nModSinceAnalyze, &lastVacuum, &lastAutovacuum, &lastAnalyze, &lastAutoanalyze, &vacuumCount, &autovacuumCount, &analyzeCount, &autoanalyzeCount, &totalSize, &tableOnlySize); err != nil {
return err return err
} }
@ -437,6 +444,17 @@ func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instan
totalSizeMetric, totalSizeMetric,
datnameLabel, schemanameLabel, relnameLabel, datnameLabel, schemanameLabel, relnameLabel,
) )
tableOnlySizeMetric := 0.0
if tableOnlySize.Valid {
tableOnlySizeMetric = float64(tableOnlySize.Int64)
}
ch <- prometheus.MustNewConstMetric(
statUserTablesOnlySize,
prometheus.GaugeValue,
tableOnlySizeMetric,
datnameLabel, schemanameLabel, relnameLabel,
)
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {

View File

@ -72,7 +72,8 @@ func TestPGStatUserTablesCollector(t *testing.T) {
"autovacuum_count", "autovacuum_count",
"analyze_count", "analyze_count",
"autoanalyze_count", "autoanalyze_count",
"total_size"} "total_size",
"table_only_size"}
rows := sqlmock.NewRows(columns). rows := sqlmock.NewRows(columns).
AddRow("postgres", AddRow("postgres",
"public", "public",
@ -96,7 +97,8 @@ func TestPGStatUserTablesCollector(t *testing.T) {
12, 12,
13, 13,
14, 14,
15) 15,
16)
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() {
@ -128,6 +130,8 @@ func TestPGStatUserTablesCollector(t *testing.T) {
{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: 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: 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_GAUGE, value: 15},
{labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 16},
} }
convey.Convey("Metrics comparison", t, func() { convey.Convey("Metrics comparison", t, func() {
@ -173,7 +177,8 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) {
"autovacuum_count", "autovacuum_count",
"analyze_count", "analyze_count",
"autoanalyze_count", "autoanalyze_count",
"total_size"} "total_size",
"table_only_size"}
rows := sqlmock.NewRows(columns). rows := sqlmock.NewRows(columns).
AddRow("postgres", AddRow("postgres",
nil, nil,
@ -197,6 +202,7 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) {
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)
@ -229,6 +235,8 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) {
{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},
{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},
} }
convey.Convey("Metrics comparison", t, func() { convey.Convey("Metrics comparison", t, func() {