summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/postgres/charts.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/collectors/go.d.plugin/modules/postgres/charts.go1400
1 files changed, 1400 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/postgres/charts.go b/src/go/collectors/go.d.plugin/modules/postgres/charts.go
new file mode 100644
index 000000000..8003ab9f8
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/postgres/charts.go
@@ -0,0 +1,1400 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package postgres
+
+import (
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
+)
+
+const (
+ prioConnectionsUtilization = module.Priority + iota
+ prioConnectionsUsage
+ prioConnectionsStateCount
+ prioDBConnectionsUtilization
+ prioDBConnectionsCount
+
+ prioTransactionsDuration
+ prioDBTransactionsRatio
+ prioDBTransactionsRate
+
+ prioQueriesDuration
+
+ prioDBOpsFetchedRowsRatio
+ prioDBOpsReadRowsRate
+ prioDBOpsWriteRowsRate
+ prioDBTempFilesCreatedRate
+ prioDBTempFilesIORate
+ prioTableOpsRowsRate
+ prioTableOpsRowsHOTRatio
+ prioTableOpsRowsHOTRate
+ prioTableScansRate
+ prioTableScansRowsRate
+
+ prioDBCacheIORatio
+ prioDBIORate
+ prioTableCacheIORatio
+ prioTableIORate
+ prioTableIndexCacheIORatio
+ prioTableIndexIORate
+ prioTableToastCacheIORatio
+ prioTableToastIORate
+ prioTableToastIndexCacheIORatio
+ prioTableToastIndexIORate
+
+ prioDBSize
+ prioTableTotalSize
+ prioIndexSize
+
+ prioTableBloatSizePerc
+ prioTableBloatSize
+ prioIndexBloatSizePerc
+ prioIndexBloatSize
+
+ prioLocksUtilization
+ prioDBLocksHeldCount
+ prioDBLocksAwaitedCount
+ prioDBDeadlocksRate
+
+ prioAutovacuumWorkersCount
+ prioTableAutovacuumSinceTime
+ prioTableVacuumSinceTime
+ prioTableAutoAnalyzeSinceTime
+ prioTableLastAnalyzeAgo
+
+ prioCheckpointsRate
+ prioCheckpointsTime
+ prioBGWriterHaltsRate
+ prioBuffersIORate
+ prioBuffersBackendFsyncRate
+ prioBuffersAllocRate
+ prioTXIDExhaustionTowardsAutovacuumPerc
+ prioTXIDExhaustionPerc
+ prioTXIDExhaustionOldestTXIDNum
+ prioTableRowsDeadRatio
+ prioTableRowsCount
+ prioTableNullColumns
+ prioIndexUsageStatus
+
+ prioReplicationAppWALLagSize
+ prioReplicationAppWALLagTime
+ prioReplicationSlotFilesCount
+ prioDBConflictsRate
+ prioDBConflictsReasonRate
+
+ prioWALIORate
+ prioWALFilesCount
+ prioWALArchivingFilesCount
+
+ prioDatabasesCount
+ prioCatalogRelationsCount
+ prioCatalogRelationsSize
+
+ prioUptime
+)
+
+var baseCharts = module.Charts{
+ serverConnectionsUtilizationChart.Copy(),
+ serverConnectionsUsageChart.Copy(),
+ serverConnectionsStateCount.Copy(),
+ locksUtilization.Copy(),
+ checkpointsChart.Copy(),
+ checkpointWriteChart.Copy(),
+ buffersIORateChart.Copy(),
+ buffersAllocRateChart.Copy(),
+ bgWriterHaltsRateChart.Copy(),
+ buffersBackendFsyncRateChart.Copy(),
+ walIORateChart.Copy(),
+ autovacuumWorkersCountChart.Copy(),
+ txidExhaustionTowardsAutovacuumPercChart.Copy(),
+ txidExhaustionPercChart.Copy(),
+ txidExhaustionOldestTXIDNumChart.Copy(),
+
+ catalogRelationSCountChart.Copy(),
+ catalogRelationsSizeChart.Copy(),
+ serverUptimeChart.Copy(),
+ databasesCountChart.Copy(),
+}
+
+var walFilesCharts = module.Charts{
+ walFilesCountChart.Copy(),
+ walArchivingFilesCountChart.Copy(),
+}
+
+func (p *Postgres) addWALFilesCharts() {
+ charts := walFilesCharts.Copy()
+
+ if err := p.Charts().Add(*charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+var (
+ serverConnectionsUtilizationChart = module.Chart{
+ ID: "connections_utilization",
+ Title: "Connections utilization",
+ Units: "percentage",
+ Fam: "connections",
+ Ctx: "postgres.connections_utilization",
+ Priority: prioConnectionsUtilization,
+ Dims: module.Dims{
+ {ID: "server_connections_utilization", Name: "used"},
+ },
+ }
+ serverConnectionsUsageChart = module.Chart{
+ ID: "connections_usage",
+ Title: "Connections usage",
+ Units: "connections",
+ Fam: "connections",
+ Ctx: "postgres.connections_usage",
+ Priority: prioConnectionsUsage,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "server_connections_available", Name: "available"},
+ {ID: "server_connections_used", Name: "used"},
+ },
+ }
+ serverConnectionsStateCount = module.Chart{
+ ID: "connections_state",
+ Title: "Connections in each state",
+ Units: "connections",
+ Fam: "connections",
+ Ctx: "postgres.connections_state_count",
+ Priority: prioConnectionsStateCount,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "server_connections_state_active", Name: "active"},
+ {ID: "server_connections_state_idle", Name: "idle"},
+ {ID: "server_connections_state_idle_in_transaction", Name: "idle_in_transaction"},
+ {ID: "server_connections_state_idle_in_transaction_aborted", Name: "idle_in_transaction_aborted"},
+ {ID: "server_connections_state_fastpath_function_call", Name: "fastpath_function_call"},
+ {ID: "server_connections_state_disabled", Name: "disabled"},
+ },
+ }
+
+ locksUtilization = module.Chart{
+ ID: "locks_utilization",
+ Title: "Acquired locks utilization",
+ Units: "percentage",
+ Fam: "locks",
+ Ctx: "postgres.locks_utilization",
+ Priority: prioLocksUtilization,
+ Dims: module.Dims{
+ {ID: "locks_utilization", Name: "used"},
+ },
+ }
+
+ checkpointsChart = module.Chart{
+ ID: "checkpoints_rate",
+ Title: "Checkpoints",
+ Units: "checkpoints/s",
+ Fam: "maintenance",
+ Ctx: "postgres.checkpoints_rate",
+ Priority: prioCheckpointsRate,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "checkpoints_timed", Name: "scheduled", Algo: module.Incremental},
+ {ID: "checkpoints_req", Name: "requested", Algo: module.Incremental},
+ },
+ }
+ // TODO: should be seconds, also it is units/s when using incremental...
+ checkpointWriteChart = module.Chart{
+ ID: "checkpoints_time",
+ Title: "Checkpoint time",
+ Units: "milliseconds",
+ Fam: "maintenance",
+ Ctx: "postgres.checkpoints_time",
+ Priority: prioCheckpointsTime,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "checkpoint_write_time", Name: "write", Algo: module.Incremental},
+ {ID: "checkpoint_sync_time", Name: "sync", Algo: module.Incremental},
+ },
+ }
+ bgWriterHaltsRateChart = module.Chart{
+ ID: "bgwriter_halts_rate",
+ Title: "Background writer scan halts",
+ Units: "halts/s",
+ Fam: "maintenance",
+ Ctx: "postgres.bgwriter_halts_rate",
+ Priority: prioBGWriterHaltsRate,
+ Dims: module.Dims{
+ {ID: "maxwritten_clean", Name: "maxwritten", Algo: module.Incremental},
+ },
+ }
+
+ buffersIORateChart = module.Chart{
+ ID: "buffers_io_rate",
+ Title: "Buffers written rate",
+ Units: "B/s",
+ Fam: "maintenance",
+ Ctx: "postgres.buffers_io_rate",
+ Priority: prioBuffersIORate,
+ Type: module.Area,
+ Dims: module.Dims{
+ {ID: "buffers_checkpoint", Name: "checkpoint", Algo: module.Incremental},
+ {ID: "buffers_backend", Name: "backend", Algo: module.Incremental},
+ {ID: "buffers_clean", Name: "bgwriter", Algo: module.Incremental},
+ },
+ }
+ buffersBackendFsyncRateChart = module.Chart{
+ ID: "buffers_backend_fsync_rate",
+ Title: "Backend fsync calls",
+ Units: "calls/s",
+ Fam: "maintenance",
+ Ctx: "postgres.buffers_backend_fsync_rate",
+ Priority: prioBuffersBackendFsyncRate,
+ Dims: module.Dims{
+ {ID: "buffers_backend_fsync", Name: "fsync", Algo: module.Incremental},
+ },
+ }
+ buffersAllocRateChart = module.Chart{
+ ID: "buffers_alloc_rate",
+ Title: "Buffers allocated",
+ Units: "B/s",
+ Fam: "maintenance",
+ Ctx: "postgres.buffers_allocated_rate",
+ Priority: prioBuffersAllocRate,
+ Dims: module.Dims{
+ {ID: "buffers_alloc", Name: "allocated", Algo: module.Incremental},
+ },
+ }
+
+ walIORateChart = module.Chart{
+ ID: "wal_io_rate",
+ Title: "Write-Ahead Log writes",
+ Units: "B/s",
+ Fam: "wal",
+ Ctx: "postgres.wal_io_rate",
+ Priority: prioWALIORate,
+ Dims: module.Dims{
+ {ID: "wal_writes", Name: "written", Algo: module.Incremental},
+ },
+ }
+ walFilesCountChart = module.Chart{
+ ID: "wal_files_count",
+ Title: "Write-Ahead Log files",
+ Units: "files",
+ Fam: "wal",
+ Ctx: "postgres.wal_files_count",
+ Priority: prioWALFilesCount,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "wal_written_files", Name: "written"},
+ {ID: "wal_recycled_files", Name: "recycled"},
+ },
+ }
+
+ walArchivingFilesCountChart = module.Chart{
+ ID: "wal_archiving_files_count",
+ Title: "Write-Ahead Log archived files",
+ Units: "files/s",
+ Fam: "wal",
+ Ctx: "postgres.wal_archiving_files_count",
+ Priority: prioWALArchivingFilesCount,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "wal_archive_files_ready_count", Name: "ready"},
+ {ID: "wal_archive_files_done_count", Name: "done"},
+ },
+ }
+
+ autovacuumWorkersCountChart = module.Chart{
+ ID: "autovacuum_workers_count",
+ Title: "Autovacuum workers",
+ Units: "workers",
+ Fam: "vacuum and analyze",
+ Ctx: "postgres.autovacuum_workers_count",
+ Priority: prioAutovacuumWorkersCount,
+ Dims: module.Dims{
+ {ID: "autovacuum_analyze", Name: "analyze"},
+ {ID: "autovacuum_vacuum_analyze", Name: "vacuum_analyze"},
+ {ID: "autovacuum_vacuum", Name: "vacuum"},
+ {ID: "autovacuum_vacuum_freeze", Name: "vacuum_freeze"},
+ {ID: "autovacuum_brin_summarize", Name: "brin_summarize"},
+ },
+ }
+
+ txidExhaustionTowardsAutovacuumPercChart = module.Chart{
+ ID: "txid_exhaustion_towards_autovacuum_perc",
+ Title: "Percent towards emergency autovacuum",
+ Units: "percentage",
+ Fam: "maintenance",
+ Ctx: "postgres.txid_exhaustion_towards_autovacuum_perc",
+ Priority: prioTXIDExhaustionTowardsAutovacuumPerc,
+ Dims: module.Dims{
+ {ID: "percent_towards_emergency_autovacuum", Name: "emergency_autovacuum"},
+ },
+ }
+ txidExhaustionPercChart = module.Chart{
+ ID: "txid_exhaustion_perc",
+ Title: "Percent towards transaction ID wraparound",
+ Units: "percentage",
+ Fam: "maintenance",
+ Ctx: "postgres.txid_exhaustion_perc",
+ Priority: prioTXIDExhaustionPerc,
+ Dims: module.Dims{
+ {ID: "percent_towards_wraparound", Name: "txid_exhaustion"},
+ },
+ }
+ txidExhaustionOldestTXIDNumChart = module.Chart{
+ ID: "txid_exhaustion_oldest_txid_num",
+ Title: "Oldest transaction XID",
+ Units: "xid",
+ Fam: "maintenance",
+ Ctx: "postgres.txid_exhaustion_oldest_txid_num",
+ Priority: prioTXIDExhaustionOldestTXIDNum,
+ Dims: module.Dims{
+ {ID: "oldest_current_xid", Name: "xid"},
+ },
+ }
+
+ catalogRelationSCountChart = module.Chart{
+ ID: "catalog_relations_count",
+ Title: "Relation count",
+ Units: "relations",
+ Fam: "catalog",
+ Ctx: "postgres.catalog_relations_count",
+ Priority: prioCatalogRelationsCount,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "catalog_relkind_r_count", Name: "ordinary_table"},
+ {ID: "catalog_relkind_i_count", Name: "index"},
+ {ID: "catalog_relkind_S_count", Name: "sequence"},
+ {ID: "catalog_relkind_t_count", Name: "toast_table"},
+ {ID: "catalog_relkind_v_count", Name: "view"},
+ {ID: "catalog_relkind_m_count", Name: "materialized_view"},
+ {ID: "catalog_relkind_c_count", Name: "composite_type"},
+ {ID: "catalog_relkind_f_count", Name: "foreign_table"},
+ {ID: "catalog_relkind_p_count", Name: "partitioned_table"},
+ {ID: "catalog_relkind_I_count", Name: "partitioned_index"},
+ },
+ }
+ catalogRelationsSizeChart = module.Chart{
+ ID: "catalog_relations_size",
+ Title: "Relation size",
+ Units: "B",
+ Fam: "catalog",
+ Ctx: "postgres.catalog_relations_size",
+ Priority: prioCatalogRelationsSize,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "catalog_relkind_r_size", Name: "ordinary_table"},
+ {ID: "catalog_relkind_i_size", Name: "index"},
+ {ID: "catalog_relkind_S_size", Name: "sequence"},
+ {ID: "catalog_relkind_t_size", Name: "toast_table"},
+ {ID: "catalog_relkind_v_size", Name: "view"},
+ {ID: "catalog_relkind_m_size", Name: "materialized_view"},
+ {ID: "catalog_relkind_c_size", Name: "composite_type"},
+ {ID: "catalog_relkind_f_size", Name: "foreign_table"},
+ {ID: "catalog_relkind_p_size", Name: "partitioned_table"},
+ {ID: "catalog_relkind_I_size", Name: "partitioned_index"},
+ },
+ }
+
+ serverUptimeChart = module.Chart{
+ ID: "server_uptime",
+ Title: "Uptime",
+ Units: "seconds",
+ Fam: "uptime",
+ Ctx: "postgres.uptime",
+ Priority: prioUptime,
+ Dims: module.Dims{
+ {ID: "server_uptime", Name: "uptime"},
+ },
+ }
+
+ databasesCountChart = module.Chart{
+ ID: "databases_count",
+ Title: "Number of databases",
+ Units: "databases",
+ Fam: "catalog",
+ Ctx: "postgres.databases_count",
+ Priority: prioDatabasesCount,
+ Dims: module.Dims{
+ {ID: "databases_count", Name: "databases"},
+ },
+ }
+
+ transactionsDurationChartTmpl = module.Chart{
+ ID: "transactions_duration",
+ Title: "Observed transactions time",
+ Units: "transactions/s",
+ Fam: "transactions",
+ Ctx: "postgres.transactions_duration",
+ Priority: prioTransactionsDuration,
+ Type: module.Stacked,
+ }
+ queriesDurationChartTmpl = module.Chart{
+ ID: "queries_duration",
+ Title: "Observed active queries time",
+ Units: "queries/s",
+ Fam: "queries",
+ Ctx: "postgres.queries_duration",
+ Priority: prioQueriesDuration,
+ Type: module.Stacked,
+ }
+)
+
+func newRunningTimeHistogramChart(tmpl module.Chart, prefix string, buckets []float64) (*module.Chart, error) {
+ chart := tmpl.Copy()
+
+ for i, v := range buckets {
+ dim := &module.Dim{
+ ID: fmt.Sprintf("%s_hist_bucket_%d", prefix, i+1),
+ Name: time.Duration(v * float64(time.Second)).String(),
+ Algo: module.Incremental,
+ }
+ if err := chart.AddDim(dim); err != nil {
+ return nil, err
+ }
+ }
+
+ dim := &module.Dim{
+ ID: fmt.Sprintf("%s_hist_bucket_inf", prefix),
+ Name: "+Inf",
+ Algo: module.Incremental,
+ }
+ if err := chart.AddDim(dim); err != nil {
+ return nil, err
+ }
+
+ return chart, nil
+}
+
+func (p *Postgres) addTransactionsRunTimeHistogramChart() {
+ chart, err := newRunningTimeHistogramChart(
+ transactionsDurationChartTmpl,
+ "transaction_running_time",
+ p.XactTimeHistogram,
+ )
+ if err != nil {
+ p.Warning(err)
+ return
+ }
+ if err := p.Charts().Add(chart); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) addQueriesRunTimeHistogramChart() {
+ chart, err := newRunningTimeHistogramChart(
+ queriesDurationChartTmpl,
+ "query_running_time",
+ p.QueryTimeHistogram,
+ )
+ if err != nil {
+ p.Warning(err)
+ return
+ }
+ if err := p.Charts().Add(chart); err != nil {
+ p.Warning(err)
+ }
+}
+
+var (
+ replicationStandbyAppCharts = module.Charts{
+ replicationAppWALLagSizeChartTmpl.Copy(),
+ replicationAppWALLagTimeChartTmpl.Copy(),
+ }
+ replicationAppWALLagSizeChartTmpl = module.Chart{
+ ID: "replication_app_%s_wal_lag_size",
+ Title: "Standby application WAL lag size",
+ Units: "B",
+ Fam: "replication",
+ Ctx: "postgres.replication_app_wal_lag_size",
+ Priority: prioReplicationAppWALLagSize,
+ Dims: module.Dims{
+ {ID: "repl_standby_app_%s_wal_sent_lag_size", Name: "sent_lag"},
+ {ID: "repl_standby_app_%s_wal_write_lag_size", Name: "write_lag"},
+ {ID: "repl_standby_app_%s_wal_flush_lag_size", Name: "flush_lag"},
+ {ID: "repl_standby_app_%s_wal_replay_lag_size", Name: "replay_lag"},
+ },
+ }
+ replicationAppWALLagTimeChartTmpl = module.Chart{
+ ID: "replication_app_%s_wal_lag_time",
+ Title: "Standby application WAL lag time",
+ Units: "seconds",
+ Fam: "replication",
+ Ctx: "postgres.replication_app_wal_lag_time",
+ Priority: prioReplicationAppWALLagTime,
+ Dims: module.Dims{
+ {ID: "repl_standby_app_%s_wal_write_lag_time", Name: "write_lag"},
+ {ID: "repl_standby_app_%s_wal_flush_lag_time", Name: "flush_lag"},
+ {ID: "repl_standby_app_%s_wal_replay_lag_time", Name: "replay_lag"},
+ },
+ }
+)
+
+func newReplicationStandbyAppCharts(app string) *module.Charts {
+ charts := replicationStandbyAppCharts.Copy()
+ for _, c := range *charts {
+ c.ID = fmt.Sprintf(c.ID, app)
+ c.Labels = []module.Label{
+ {Key: "application", Value: app},
+ }
+ for _, d := range c.Dims {
+ d.ID = fmt.Sprintf(d.ID, app)
+ }
+ }
+ return charts
+}
+
+func (p *Postgres) addNewReplicationStandbyAppCharts(app string) {
+ charts := newReplicationStandbyAppCharts(app)
+ if err := p.Charts().Add(*charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) removeReplicationStandbyAppCharts(app string) {
+ prefix := fmt.Sprintf("replication_standby_app_%s_", app)
+ for _, c := range *p.Charts() {
+ if strings.HasPrefix(c.ID, prefix) {
+ c.MarkRemove()
+ c.MarkNotCreated()
+ }
+ }
+}
+
+var (
+ replicationSlotCharts = module.Charts{
+ replicationSlotFilesCountChartTmpl.Copy(),
+ }
+ replicationSlotFilesCountChartTmpl = module.Chart{
+ ID: "replication_slot_%s_files_count",
+ Title: "Replication slot files",
+ Units: "files",
+ Fam: "replication",
+ Ctx: "postgres.replication_slot_files_count",
+ Priority: prioReplicationSlotFilesCount,
+ Dims: module.Dims{
+ {ID: "repl_slot_%s_replslot_wal_keep", Name: "wal_keep"},
+ {ID: "repl_slot_%s_replslot_files", Name: "pg_replslot_files"},
+ },
+ }
+)
+
+func newReplicationSlotCharts(slot string) *module.Charts {
+ charts := replicationSlotCharts.Copy()
+ for _, c := range *charts {
+ c.ID = fmt.Sprintf(c.ID, slot)
+ c.Labels = []module.Label{
+ {Key: "slot", Value: slot},
+ }
+ for _, d := range c.Dims {
+ d.ID = fmt.Sprintf(d.ID, slot)
+ }
+ }
+ return charts
+}
+
+func (p *Postgres) addNewReplicationSlotCharts(slot string) {
+ charts := newReplicationSlotCharts(slot)
+ if err := p.Charts().Add(*charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) removeReplicationSlotCharts(slot string) {
+ prefix := fmt.Sprintf("replication_slot_%s_", slot)
+ for _, c := range *p.Charts() {
+ if strings.HasPrefix(c.ID, prefix) {
+ c.MarkRemove()
+ c.MarkNotCreated()
+ }
+ }
+}
+
+var (
+ dbChartsTmpl = module.Charts{
+ dbTransactionsRatioChartTmpl.Copy(),
+ dbTransactionsRateChartTmpl.Copy(),
+ dbConnectionsUtilizationChartTmpl.Copy(),
+ dbConnectionsCountChartTmpl.Copy(),
+ dbCacheIORatioChartTmpl.Copy(),
+ dbIORateChartTmpl.Copy(),
+ dbOpsFetchedRowsRatioChartTmpl.Copy(),
+ dbOpsReadRowsRateChartTmpl.Copy(),
+ dbOpsWriteRowsRateChartTmpl.Copy(),
+ dbDeadlocksRateChartTmpl.Copy(),
+ dbLocksHeldCountChartTmpl.Copy(),
+ dbLocksAwaitedCountChartTmpl.Copy(),
+ dbTempFilesCreatedRateChartTmpl.Copy(),
+ dbTempFilesIORateChartTmpl.Copy(),
+ dbSizeChartTmpl.Copy(),
+ }
+ dbTransactionsRatioChartTmpl = module.Chart{
+ ID: "db_%s_transactions_ratio",
+ Title: "Database transactions ratio",
+ Units: "percentage",
+ Fam: "transactions",
+ Ctx: "postgres.db_transactions_ratio",
+ Priority: prioDBTransactionsRatio,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "db_%s_xact_commit", Name: "committed", Algo: module.PercentOfIncremental},
+ {ID: "db_%s_xact_rollback", Name: "rollback", Algo: module.PercentOfIncremental},
+ },
+ }
+ dbTransactionsRateChartTmpl = module.Chart{
+ ID: "db_%s_transactions_rate",
+ Title: "Database transactions",
+ Units: "transactions/s",
+ Fam: "transactions",
+ Ctx: "postgres.db_transactions_rate",
+ Priority: prioDBTransactionsRate,
+ Dims: module.Dims{
+ {ID: "db_%s_xact_commit", Name: "committed", Algo: module.Incremental},
+ {ID: "db_%s_xact_rollback", Name: "rollback", Algo: module.Incremental},
+ },
+ }
+ dbConnectionsUtilizationChartTmpl = module.Chart{
+ ID: "db_%s_connections_utilization",
+ Title: "Database connections utilization",
+ Units: "percentage",
+ Fam: "connections",
+ Ctx: "postgres.db_connections_utilization",
+ Priority: prioDBConnectionsUtilization,
+ Dims: module.Dims{
+ {ID: "db_%s_numbackends_utilization", Name: "used"},
+ },
+ }
+ dbConnectionsCountChartTmpl = module.Chart{
+ ID: "db_%s_connections",
+ Title: "Database connections",
+ Units: "connections",
+ Fam: "connections",
+ Ctx: "postgres.db_connections_count",
+ Priority: prioDBConnectionsCount,
+ Dims: module.Dims{
+ {ID: "db_%s_numbackends", Name: "connections"},
+ },
+ }
+ dbCacheIORatioChartTmpl = module.Chart{
+ ID: "db_%s_cache_io_ratio",
+ Title: "Database buffer cache miss ratio",
+ Units: "percentage",
+ Fam: "cache",
+ Ctx: "postgres.db_cache_io_ratio",
+ Priority: prioDBCacheIORatio,
+ Dims: module.Dims{
+ {ID: "db_%s_blks_read_perc", Name: "miss"},
+ },
+ }
+ dbIORateChartTmpl = module.Chart{
+ ID: "db_%s_io_rate",
+ Title: "Database reads",
+ Units: "B/s",
+ Fam: "cache",
+ Ctx: "postgres.db_io_rate",
+ Priority: prioDBIORate,
+ Type: module.Area,
+ Dims: module.Dims{
+ {ID: "db_%s_blks_hit", Name: "memory", Algo: module.Incremental},
+ {ID: "db_%s_blks_read", Name: "disk", Algo: module.Incremental},
+ },
+ }
+ dbOpsFetchedRowsRatioChartTmpl = module.Chart{
+ ID: "db_%s_db_ops_fetched_rows_ratio",
+ Title: "Database rows fetched ratio",
+ Units: "percentage",
+ Fam: "throughput",
+ Ctx: "postgres.db_ops_fetched_rows_ratio",
+ Priority: prioDBOpsFetchedRowsRatio,
+ Dims: module.Dims{
+ {ID: "db_%s_tup_fetched_perc", Name: "fetched"},
+ },
+ }
+ dbOpsReadRowsRateChartTmpl = module.Chart{
+ ID: "db_%s_ops_read_rows_rate",
+ Title: "Database rows read",
+ Units: "rows/s",
+ Fam: "throughput",
+ Ctx: "postgres.db_ops_read_rows_rate",
+ Priority: prioDBOpsReadRowsRate,
+ Dims: module.Dims{
+ {ID: "db_%s_tup_returned", Name: "returned", Algo: module.Incremental},
+ {ID: "db_%s_tup_fetched", Name: "fetched", Algo: module.Incremental},
+ },
+ }
+ dbOpsWriteRowsRateChartTmpl = module.Chart{
+ ID: "db_%s_ops_write_rows_rate",
+ Title: "Database rows written",
+ Units: "rows/s",
+ Fam: "throughput",
+ Ctx: "postgres.db_ops_write_rows_rate",
+ Priority: prioDBOpsWriteRowsRate,
+ Dims: module.Dims{
+ {ID: "db_%s_tup_inserted", Name: "inserted", Algo: module.Incremental},
+ {ID: "db_%s_tup_deleted", Name: "deleted", Algo: module.Incremental},
+ {ID: "db_%s_tup_updated", Name: "updated", Algo: module.Incremental},
+ },
+ }
+ dbConflictsRateChartTmpl = module.Chart{
+ ID: "db_%s_conflicts_rate",
+ Title: "Database canceled queries",
+ Units: "queries/s",
+ Fam: "replication",
+ Ctx: "postgres.db_conflicts_rate",
+ Priority: prioDBConflictsRate,
+ Dims: module.Dims{
+ {ID: "db_%s_conflicts", Name: "conflicts", Algo: module.Incremental},
+ },
+ }
+ dbConflictsReasonRateChartTmpl = module.Chart{
+ ID: "db_%s_conflicts_reason_rate",
+ Title: "Database canceled queries by reason",
+ Units: "queries/s",
+ Fam: "replication",
+ Ctx: "postgres.db_conflicts_reason_rate",
+ Priority: prioDBConflictsReasonRate,
+ Dims: module.Dims{
+ {ID: "db_%s_confl_tablespace", Name: "tablespace", Algo: module.Incremental},
+ {ID: "db_%s_confl_lock", Name: "lock", Algo: module.Incremental},
+ {ID: "db_%s_confl_snapshot", Name: "snapshot", Algo: module.Incremental},
+ {ID: "db_%s_confl_bufferpin", Name: "bufferpin", Algo: module.Incremental},
+ {ID: "db_%s_confl_deadlock", Name: "deadlock", Algo: module.Incremental},
+ },
+ }
+ dbDeadlocksRateChartTmpl = module.Chart{
+ ID: "db_%s_deadlocks_rate",
+ Title: "Database deadlocks",
+ Units: "deadlocks/s",
+ Fam: "locks",
+ Ctx: "postgres.db_deadlocks_rate",
+ Priority: prioDBDeadlocksRate,
+ Dims: module.Dims{
+ {ID: "db_%s_deadlocks", Name: "deadlocks", Algo: module.Incremental},
+ },
+ }
+ dbLocksHeldCountChartTmpl = module.Chart{
+ ID: "db_%s_locks_held",
+ Title: "Database locks held",
+ Units: "locks",
+ Fam: "locks",
+ Ctx: "postgres.db_locks_held_count",
+ Priority: prioDBLocksHeldCount,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "db_%s_lock_mode_AccessShareLock_held", Name: "access_share"},
+ {ID: "db_%s_lock_mode_RowShareLock_held", Name: "row_share"},
+ {ID: "db_%s_lock_mode_RowExclusiveLock_held", Name: "row_exclusive"},
+ {ID: "db_%s_lock_mode_ShareUpdateExclusiveLock_held", Name: "share_update"},
+ {ID: "db_%s_lock_mode_ShareLock_held", Name: "share"},
+ {ID: "db_%s_lock_mode_ShareRowExclusiveLock_held", Name: "share_row_exclusive"},
+ {ID: "db_%s_lock_mode_ExclusiveLock_held", Name: "exclusive"},
+ {ID: "db_%s_lock_mode_AccessExclusiveLock_held", Name: "access_exclusive"},
+ },
+ }
+ dbLocksAwaitedCountChartTmpl = module.Chart{
+ ID: "db_%s_locks_awaited_count",
+ Title: "Database locks awaited",
+ Units: "locks",
+ Fam: "locks",
+ Ctx: "postgres.db_locks_awaited_count",
+ Priority: prioDBLocksAwaitedCount,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "db_%s_lock_mode_AccessShareLock_awaited", Name: "access_share"},
+ {ID: "db_%s_lock_mode_RowShareLock_awaited", Name: "row_share"},
+ {ID: "db_%s_lock_mode_RowExclusiveLock_awaited", Name: "row_exclusive"},
+ {ID: "db_%s_lock_mode_ShareUpdateExclusiveLock_awaited", Name: "share_update"},
+ {ID: "db_%s_lock_mode_ShareLock_awaited", Name: "share"},
+ {ID: "db_%s_lock_mode_ShareRowExclusiveLock_awaited", Name: "share_row_exclusive"},
+ {ID: "db_%s_lock_mode_ExclusiveLock_awaited", Name: "exclusive"},
+ {ID: "db_%s_lock_mode_AccessExclusiveLock_awaited", Name: "access_exclusive"},
+ },
+ }
+ dbTempFilesCreatedRateChartTmpl = module.Chart{
+ ID: "db_%s_temp_files_files_created_rate",
+ Title: "Database created temporary files",
+ Units: "files/s",
+ Fam: "throughput",
+ Ctx: "postgres.db_temp_files_created_rate",
+ Priority: prioDBTempFilesCreatedRate,
+ Dims: module.Dims{
+ {ID: "db_%s_temp_files", Name: "created", Algo: module.Incremental},
+ },
+ }
+ dbTempFilesIORateChartTmpl = module.Chart{
+ ID: "db_%s_temp_files_io_rate",
+ Title: "Database temporary files data written to disk",
+ Units: "B/s",
+ Fam: "throughput",
+ Ctx: "postgres.db_temp_files_io_rate",
+ Priority: prioDBTempFilesIORate,
+ Dims: module.Dims{
+ {ID: "db_%s_temp_bytes", Name: "written", Algo: module.Incremental},
+ },
+ }
+ dbSizeChartTmpl = module.Chart{
+ ID: "db_%s_size",
+ Title: "Database size",
+ Units: "B",
+ Fam: "size",
+ Ctx: "postgres.db_size",
+ Priority: prioDBSize,
+ Dims: module.Dims{
+ {ID: "db_%s_size", Name: "size"},
+ },
+ }
+)
+
+func (p *Postgres) addDBConflictsCharts(db *dbMetrics) {
+ tmpl := module.Charts{
+ dbConflictsRateChartTmpl.Copy(),
+ dbConflictsReasonRateChartTmpl.Copy(),
+ }
+ charts := newDatabaseCharts(tmpl.Copy(), db)
+
+ if err := p.Charts().Add(*charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func newDatabaseCharts(tmpl *module.Charts, db *dbMetrics) *module.Charts {
+ charts := tmpl.Copy()
+ for _, c := range *charts {
+ c.ID = fmt.Sprintf(c.ID, db.name)
+ c.Labels = []module.Label{
+ {Key: "database", Value: db.name},
+ }
+ for _, d := range c.Dims {
+ d.ID = fmt.Sprintf(d.ID, db.name)
+ }
+ }
+ return charts
+}
+
+func (p *Postgres) addNewDatabaseCharts(db *dbMetrics) {
+ charts := newDatabaseCharts(dbChartsTmpl.Copy(), db)
+
+ if db.size == nil {
+ _ = charts.Remove(fmt.Sprintf(dbSizeChartTmpl.ID, db.name))
+ }
+
+ if err := p.Charts().Add(*charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) removeDatabaseCharts(db *dbMetrics) {
+ prefix := fmt.Sprintf("db_%s_", db.name)
+ for _, c := range *p.Charts() {
+ if strings.HasPrefix(c.ID, prefix) {
+ c.MarkRemove()
+ c.MarkNotCreated()
+ }
+ }
+}
+
+var (
+ tableChartsTmpl = module.Charts{
+ tableRowsCountChartTmpl.Copy(),
+ tableDeadRowsDeadRatioChartTmpl.Copy(),
+ tableOpsRowsRateChartTmpl.Copy(),
+ tableOpsRowsHOTRatioChartTmpl.Copy(),
+ tableOpsRowsHOTRateChartTmpl.Copy(),
+ tableScansRateChartTmpl.Copy(),
+ tableScansRowsRateChartTmpl.Copy(),
+ tableNullColumnsCountChartTmpl.Copy(),
+ tableTotalSizeChartTmpl.Copy(),
+ tableBloatSizePercChartTmpl.Copy(),
+ tableBloatSizeChartTmpl.Copy(),
+ }
+
+ tableDeadRowsDeadRatioChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_rows_dead_ratio",
+ Title: "Table dead rows",
+ Units: "%",
+ Fam: "maintenance",
+ Ctx: "postgres.table_rows_dead_ratio",
+ Priority: prioTableRowsDeadRatio,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_n_dead_tup_perc", Name: "dead"},
+ },
+ }
+ tableRowsCountChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_rows_count",
+ Title: "Table total rows",
+ Units: "rows",
+ Fam: "maintenance",
+ Ctx: "postgres.table_rows_count",
+ Priority: prioTableRowsCount,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_n_live_tup", Name: "live"},
+ {ID: "table_%s_db_%s_schema_%s_n_dead_tup", Name: "dead"},
+ },
+ }
+ tableOpsRowsRateChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_ops_rows_rate",
+ Title: "Table throughput",
+ Units: "rows/s",
+ Fam: "throughput",
+ Ctx: "postgres.table_ops_rows_rate",
+ Priority: prioTableOpsRowsRate,
+ Type: module.Stacked,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_n_tup_ins", Name: "inserted", Algo: module.Incremental},
+ {ID: "table_%s_db_%s_schema_%s_n_tup_del", Name: "deleted", Algo: module.Incremental},
+ {ID: "table_%s_db_%s_schema_%s_n_tup_upd", Name: "updated", Algo: module.Incremental},
+ },
+ }
+ tableOpsRowsHOTRatioChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_ops_rows_hot_ratio",
+ Title: "Table HOT updates ratio",
+ Units: "percentage",
+ Fam: "throughput",
+ Ctx: "postgres.table_ops_rows_hot_ratio",
+ Priority: prioTableOpsRowsHOTRatio,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_n_tup_hot_upd_perc", Name: "hot"},
+ },
+ }
+ tableOpsRowsHOTRateChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_ops_rows_hot_rate",
+ Title: "Table HOT updates",
+ Units: "rows/s",
+ Fam: "throughput",
+ Ctx: "postgres.table_ops_rows_hot_rate",
+ Priority: prioTableOpsRowsHOTRate,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_n_tup_hot_upd", Name: "hot", Algo: module.Incremental},
+ },
+ }
+ tableCacheIORatioChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_cache_io_ratio",
+ Title: "Table I/O cache miss ratio",
+ Units: "percentage",
+ Fam: "cache",
+ Ctx: "postgres.table_cache_io_ratio",
+ Priority: prioTableCacheIORatio,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_heap_blks_read_perc", Name: "miss"},
+ },
+ }
+ tableIORateChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_io_rate",
+ Title: "Table I/O",
+ Units: "B/s",
+ Fam: "cache",
+ Ctx: "postgres.table_io_rate",
+ Priority: prioTableIORate,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_heap_blks_hit", Name: "memory", Algo: module.Incremental},
+ {ID: "table_%s_db_%s_schema_%s_heap_blks_read", Name: "disk", Algo: module.Incremental},
+ },
+ }
+ tableIndexCacheIORatioChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_index_cache_io_ratio",
+ Title: "Table index I/O cache miss ratio",
+ Units: "percentage",
+ Fam: "cache",
+ Ctx: "postgres.table_index_cache_io_ratio",
+ Priority: prioTableIndexCacheIORatio,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_idx_blks_read_perc", Name: "miss", Algo: module.Incremental},
+ },
+ }
+ tableIndexIORateChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_index_io_rate",
+ Title: "Table index I/O",
+ Units: "B/s",
+ Fam: "cache",
+ Ctx: "postgres.table_index_io_rate",
+ Priority: prioTableIndexIORate,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_idx_blks_hit", Name: "memory", Algo: module.Incremental},
+ {ID: "table_%s_db_%s_schema_%s_idx_blks_read", Name: "disk", Algo: module.Incremental},
+ },
+ }
+ tableTOASCacheIORatioChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_toast_cache_io_ratio",
+ Title: "Table TOAST I/O cache miss ratio",
+ Units: "percentage",
+ Fam: "cache",
+ Ctx: "postgres.table_toast_cache_io_ratio",
+ Priority: prioTableToastCacheIORatio,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_toast_blks_read_perc", Name: "miss", Algo: module.Incremental},
+ },
+ }
+ tableTOASTIORateChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_toast_io_rate",
+ Title: "Table TOAST I/O",
+ Units: "B/s",
+ Fam: "cache",
+ Ctx: "postgres.table_toast_io_rate",
+ Priority: prioTableToastIORate,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_toast_blks_hit", Name: "memory", Algo: module.Incremental},
+ {ID: "table_%s_db_%s_schema_%s_toast_blks_read", Name: "disk", Algo: module.Incremental},
+ },
+ }
+ tableTOASTIndexCacheIORatioChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_toast_index_cache_io_ratio",
+ Title: "Table TOAST index I/O cache miss ratio",
+ Units: "percentage",
+ Fam: "cache",
+ Ctx: "postgres.table_toast_index_cache_io_ratio",
+ Priority: prioTableToastIndexCacheIORatio,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_tidx_blks_read_perc", Name: "miss", Algo: module.Incremental},
+ },
+ }
+ tableTOASTIndexIORateChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_toast_index_io_rate",
+ Title: "Table TOAST index I/O",
+ Units: "B/s",
+ Fam: "cache",
+ Ctx: "postgres.table_toast_index_io_rate",
+ Priority: prioTableToastIndexIORate,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_tidx_blks_hit", Name: "memory", Algo: module.Incremental},
+ {ID: "table_%s_db_%s_schema_%s_tidx_blks_read", Name: "disk", Algo: module.Incremental},
+ },
+ }
+ tableScansRateChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_scans_rate",
+ Title: "Table scans",
+ Units: "scans/s",
+ Fam: "throughput",
+ Ctx: "postgres.table_scans_rate",
+ Priority: prioTableScansRate,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_idx_scan", Name: "index", Algo: module.Incremental},
+ {ID: "table_%s_db_%s_schema_%s_seq_scan", Name: "sequential", Algo: module.Incremental},
+ },
+ }
+ tableScansRowsRateChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_scans_rows_rate",
+ Title: "Table live rows fetched by scans",
+ Units: "rows/s",
+ Fam: "throughput",
+ Ctx: "postgres.table_scans_rows_rate",
+ Priority: prioTableScansRowsRate,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_idx_tup_fetch", Name: "index", Algo: module.Incremental},
+ {ID: "table_%s_db_%s_schema_%s_seq_tup_read", Name: "sequential", Algo: module.Incremental},
+ },
+ }
+ tableAutoVacuumSinceTimeChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_autovacuum_since_time",
+ Title: "Table time since last auto VACUUM",
+ Units: "seconds",
+ Fam: "vacuum and analyze",
+ Ctx: "postgres.table_autovacuum_since_time",
+ Priority: prioTableAutovacuumSinceTime,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_last_autovacuum_ago", Name: "time"},
+ },
+ }
+ tableVacuumSinceTimeChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_vacuum_since_time",
+ Title: "Table time since last manual VACUUM",
+ Units: "seconds",
+ Fam: "vacuum and analyze",
+ Ctx: "postgres.table_vacuum_since_time",
+ Priority: prioTableVacuumSinceTime,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_last_vacuum_ago", Name: "time"},
+ },
+ }
+ tableAutoAnalyzeSinceTimeChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_autoanalyze_since_time",
+ Title: "Table time since last auto ANALYZE",
+ Units: "seconds",
+ Fam: "vacuum and analyze",
+ Ctx: "postgres.table_autoanalyze_since_time",
+ Priority: prioTableAutoAnalyzeSinceTime,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_last_autoanalyze_ago", Name: "time"},
+ },
+ }
+ tableAnalyzeSinceTimeChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_analyze_since_time",
+ Title: "Table time since last manual ANALYZE",
+ Units: "seconds",
+ Fam: "vacuum and analyze",
+ Ctx: "postgres.table_analyze_since_time",
+ Priority: prioTableLastAnalyzeAgo,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_last_analyze_ago", Name: "time"},
+ },
+ }
+ tableNullColumnsCountChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_null_columns_count",
+ Title: "Table null columns",
+ Units: "columns",
+ Fam: "maintenance",
+ Ctx: "postgres.table_null_columns_count",
+ Priority: prioTableNullColumns,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_null_columns", Name: "null"},
+ },
+ }
+ tableTotalSizeChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_total_size",
+ Title: "Table total size",
+ Units: "B",
+ Fam: "size",
+ Ctx: "postgres.table_total_size",
+ Priority: prioTableTotalSize,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_total_size", Name: "size"},
+ },
+ }
+ tableBloatSizePercChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_bloat_size_perc",
+ Title: "Table bloat size percentage",
+ Units: "percentage",
+ Fam: "bloat",
+ Ctx: "postgres.table_bloat_size_perc",
+ Priority: prioTableBloatSizePerc,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_bloat_size_perc", Name: "bloat"},
+ },
+ Vars: module.Vars{
+ {ID: "table_%s_db_%s_schema_%s_total_size", Name: "table_size"},
+ },
+ }
+ tableBloatSizeChartTmpl = module.Chart{
+ ID: "table_%s_db_%s_schema_%s_bloat_size",
+ Title: "Table bloat size",
+ Units: "B",
+ Fam: "bloat",
+ Ctx: "postgres.table_bloat_size",
+ Priority: prioTableBloatSize,
+ Dims: module.Dims{
+ {ID: "table_%s_db_%s_schema_%s_bloat_size", Name: "bloat"},
+ },
+ }
+)
+
+func newTableCharts(tbl *tableMetrics) *module.Charts {
+ charts := tableChartsTmpl.Copy()
+
+ if tbl.bloatSize == nil {
+ _ = charts.Remove(tableBloatSizeChartTmpl.ID)
+ _ = charts.Remove(tableBloatSizePercChartTmpl.ID)
+ }
+
+ for i, chart := range *charts {
+ (*charts)[i] = newTableChart(chart, tbl)
+ }
+
+ return charts
+}
+
+func newTableChart(chart *module.Chart, tbl *tableMetrics) *module.Chart {
+ chart = chart.Copy()
+ chart.ID = fmt.Sprintf(chart.ID, tbl.name, tbl.db, tbl.schema)
+ chart.Labels = []module.Label{
+ {Key: "database", Value: tbl.db},
+ {Key: "schema", Value: tbl.schema},
+ {Key: "table", Value: tbl.name},
+ {Key: "parent_table", Value: tbl.parentName},
+ }
+ for _, d := range chart.Dims {
+ d.ID = fmt.Sprintf(d.ID, tbl.name, tbl.db, tbl.schema)
+ }
+ for _, v := range chart.Vars {
+ v.ID = fmt.Sprintf(v.ID, tbl.name, tbl.db, tbl.schema)
+ }
+ return chart
+}
+
+func (p *Postgres) addNewTableCharts(tbl *tableMetrics) {
+ charts := newTableCharts(tbl)
+ if err := p.Charts().Add(*charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) addTableLastAutoVacuumAgoChart(tbl *tableMetrics) {
+ chart := newTableChart(tableAutoVacuumSinceTimeChartTmpl.Copy(), tbl)
+
+ if err := p.Charts().Add(chart); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) addTableLastVacuumAgoChart(tbl *tableMetrics) {
+ chart := newTableChart(tableVacuumSinceTimeChartTmpl.Copy(), tbl)
+
+ if err := p.Charts().Add(chart); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) addTableLastAutoAnalyzeAgoChart(tbl *tableMetrics) {
+ chart := newTableChart(tableAutoAnalyzeSinceTimeChartTmpl.Copy(), tbl)
+
+ if err := p.Charts().Add(chart); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) addTableLastAnalyzeAgoChart(tbl *tableMetrics) {
+ chart := newTableChart(tableAnalyzeSinceTimeChartTmpl.Copy(), tbl)
+
+ if err := p.Charts().Add(chart); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) addTableIOChartsCharts(tbl *tableMetrics) {
+ charts := module.Charts{
+ newTableChart(tableCacheIORatioChartTmpl.Copy(), tbl),
+ newTableChart(tableIORateChartTmpl.Copy(), tbl),
+ }
+
+ if err := p.Charts().Add(charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) addTableIndexIOCharts(tbl *tableMetrics) {
+ charts := module.Charts{
+ newTableChart(tableIndexCacheIORatioChartTmpl.Copy(), tbl),
+ newTableChart(tableIndexIORateChartTmpl.Copy(), tbl),
+ }
+
+ if err := p.Charts().Add(charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) addTableTOASTIOCharts(tbl *tableMetrics) {
+ charts := module.Charts{
+ newTableChart(tableTOASCacheIORatioChartTmpl.Copy(), tbl),
+ newTableChart(tableTOASTIORateChartTmpl.Copy(), tbl),
+ }
+
+ if err := p.Charts().Add(charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) addTableTOASTIndexIOCharts(tbl *tableMetrics) {
+ charts := module.Charts{
+ newTableChart(tableTOASTIndexCacheIORatioChartTmpl.Copy(), tbl),
+ newTableChart(tableTOASTIndexIORateChartTmpl.Copy(), tbl),
+ }
+
+ if err := p.Charts().Add(charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) removeTableCharts(tbl *tableMetrics) {
+ prefix := fmt.Sprintf("table_%s_db_%s_schema_%s", tbl.name, tbl.db, tbl.schema)
+ for _, c := range *p.Charts() {
+ if strings.HasPrefix(c.ID, prefix) {
+ c.MarkRemove()
+ c.MarkNotCreated()
+ }
+ }
+}
+
+var (
+ indexChartsTmpl = module.Charts{
+ indexSizeChartTmpl.Copy(),
+ indexBloatSizePercChartTmpl.Copy(),
+ indexBloatSizeChartTmpl.Copy(),
+ indexUsageStatusChartTmpl.Copy(),
+ }
+ indexSizeChartTmpl = module.Chart{
+ ID: "index_%s_table_%s_db_%s_schema_%s_size",
+ Title: "Index size",
+ Units: "B",
+ Fam: "size",
+ Ctx: "postgres.index_size",
+ Priority: prioIndexSize,
+ Dims: module.Dims{
+ {ID: "index_%s_table_%s_db_%s_schema_%s_size", Name: "size"},
+ },
+ }
+ indexBloatSizePercChartTmpl = module.Chart{
+ ID: "index_%s_table_%s_db_%s_schema_%s_bloat_size_perc",
+ Title: "Index bloat size percentage",
+ Units: "percentage",
+ Fam: "bloat",
+ Ctx: "postgres.index_bloat_size_perc",
+ Priority: prioIndexBloatSizePerc,
+ Dims: module.Dims{
+ {ID: "index_%s_table_%s_db_%s_schema_%s_bloat_size_perc", Name: "bloat"},
+ },
+ Vars: module.Vars{
+ {ID: "index_%s_table_%s_db_%s_schema_%s_size", Name: "index_size"},
+ },
+ }
+ indexBloatSizeChartTmpl = module.Chart{
+ ID: "index_%s_table_%s_db_%s_schema_%s_bloat_size",
+ Title: "Index bloat size",
+ Units: "B",
+ Fam: "bloat",
+ Ctx: "postgres.index_bloat_size",
+ Priority: prioIndexBloatSize,
+ Dims: module.Dims{
+ {ID: "index_%s_table_%s_db_%s_schema_%s_bloat_size", Name: "bloat"},
+ },
+ }
+ indexUsageStatusChartTmpl = module.Chart{
+ ID: "index_%s_table_%s_db_%s_schema_%s_usage_status",
+ Title: "Index usage status",
+ Units: "status",
+ Fam: "maintenance",
+ Ctx: "postgres.index_usage_status",
+ Priority: prioIndexUsageStatus,
+ Dims: module.Dims{
+ {ID: "index_%s_table_%s_db_%s_schema_%s_usage_status_used", Name: "used"},
+ {ID: "index_%s_table_%s_db_%s_schema_%s_usage_status_unused", Name: "unused"},
+ },
+ }
+)
+
+func (p *Postgres) addNewIndexCharts(idx *indexMetrics) {
+ charts := indexChartsTmpl.Copy()
+
+ if idx.bloatSize == nil {
+ _ = charts.Remove(indexBloatSizeChartTmpl.ID)
+ _ = charts.Remove(indexBloatSizePercChartTmpl.ID)
+ }
+
+ for _, chart := range *charts {
+ chart.ID = fmt.Sprintf(chart.ID, idx.name, idx.table, idx.db, idx.schema)
+ chart.Labels = []module.Label{
+ {Key: "database", Value: idx.db},
+ {Key: "schema", Value: idx.schema},
+ {Key: "table", Value: idx.table},
+ {Key: "parent_table", Value: idx.parentTable},
+ {Key: "index", Value: idx.name},
+ }
+ for _, d := range chart.Dims {
+ d.ID = fmt.Sprintf(d.ID, idx.name, idx.table, idx.db, idx.schema)
+ }
+ for _, v := range chart.Vars {
+ v.ID = fmt.Sprintf(v.ID, idx.name, idx.table, idx.db, idx.schema)
+ }
+ }
+
+ if err := p.Charts().Add(*charts...); err != nil {
+ p.Warning(err)
+ }
+}
+
+func (p *Postgres) removeIndexCharts(idx *indexMetrics) {
+ prefix := fmt.Sprintf("index_%s_table_%s_db_%s_schema_%s", idx.name, idx.table, idx.db, idx.schema)
+ for _, c := range *p.Charts() {
+ if strings.HasPrefix(c.ID, prefix) {
+ c.MarkRemove()
+ c.MarkNotCreated()
+ }
+ }
+}