summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/postgres/collect_metrics.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/collectors/go.d.plugin/modules/postgres/collect_metrics.go367
1 files changed, 367 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/postgres/collect_metrics.go b/src/go/collectors/go.d.plugin/modules/postgres/collect_metrics.go
new file mode 100644
index 000000000..84f9abbc7
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/postgres/collect_metrics.go
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package postgres
+
+import "fmt"
+
+func (p *Postgres) collectMetrics(mx map[string]int64) {
+ mx["server_connections_used"] = p.mx.connUsed
+ if p.mx.maxConnections > 0 {
+ mx["server_connections_available"] = p.mx.maxConnections - p.mx.connUsed
+ mx["server_connections_utilization"] = calcPercentage(p.mx.connUsed, p.mx.maxConnections)
+ }
+ p.mx.xactTimeHist.WriteTo(mx, "transaction_running_time_hist", 1, 1)
+ p.mx.queryTimeHist.WriteTo(mx, "query_running_time_hist", 1, 1)
+ mx["server_uptime"] = p.mx.uptime
+ mx["server_connections_state_active"] = p.mx.connStateActive
+ mx["server_connections_state_idle"] = p.mx.connStateIdle
+ mx["server_connections_state_idle_in_transaction"] = p.mx.connStateIdleInTrans
+ mx["server_connections_state_idle_in_transaction_aborted"] = p.mx.connStateIdleInTransAborted
+ mx["server_connections_state_fastpath_function_call"] = p.mx.connStateFastpathFunctionCall
+ mx["server_connections_state_disabled"] = p.mx.connStateDisabled
+ mx["checkpoints_timed"] = p.mx.checkpointsTimed
+ mx["checkpoints_req"] = p.mx.checkpointsReq
+ mx["checkpoint_write_time"] = p.mx.checkpointWriteTime
+ mx["checkpoint_sync_time"] = p.mx.checkpointSyncTime
+ mx["buffers_checkpoint"] = p.mx.buffersCheckpoint
+ mx["buffers_clean"] = p.mx.buffersClean
+ mx["maxwritten_clean"] = p.mx.maxwrittenClean
+ mx["buffers_backend"] = p.mx.buffersBackend
+ mx["buffers_backend_fsync"] = p.mx.buffersBackendFsync
+ mx["buffers_alloc"] = p.mx.buffersAlloc
+ mx["oldest_current_xid"] = p.mx.oldestXID
+ mx["percent_towards_wraparound"] = p.mx.percentTowardsWraparound
+ mx["percent_towards_emergency_autovacuum"] = p.mx.percentTowardsEmergencyAutovacuum
+ mx["wal_writes"] = p.mx.walWrites
+ mx["wal_recycled_files"] = p.mx.walRecycledFiles
+ mx["wal_written_files"] = p.mx.walWrittenFiles
+ mx["wal_archive_files_ready_count"] = p.mx.walArchiveFilesReady
+ mx["wal_archive_files_done_count"] = p.mx.walArchiveFilesDone
+ mx["catalog_relkind_r_count"] = p.mx.relkindOrdinaryTable
+ mx["catalog_relkind_i_count"] = p.mx.relkindIndex
+ mx["catalog_relkind_S_count"] = p.mx.relkindSequence
+ mx["catalog_relkind_t_count"] = p.mx.relkindTOASTTable
+ mx["catalog_relkind_v_count"] = p.mx.relkindView
+ mx["catalog_relkind_m_count"] = p.mx.relkindMatView
+ mx["catalog_relkind_c_count"] = p.mx.relkindCompositeType
+ mx["catalog_relkind_f_count"] = p.mx.relkindForeignTable
+ mx["catalog_relkind_p_count"] = p.mx.relkindPartitionedTable
+ mx["catalog_relkind_I_count"] = p.mx.relkindPartitionedIndex
+ mx["catalog_relkind_r_size"] = p.mx.relkindOrdinaryTableSize
+ mx["catalog_relkind_i_size"] = p.mx.relkindIndexSize
+ mx["catalog_relkind_S_size"] = p.mx.relkindSequenceSize
+ mx["catalog_relkind_t_size"] = p.mx.relkindTOASTTableSize
+ mx["catalog_relkind_v_size"] = p.mx.relkindViewSize
+ mx["catalog_relkind_m_size"] = p.mx.relkindMatViewSize
+ mx["catalog_relkind_c_size"] = p.mx.relkindCompositeTypeSize
+ mx["catalog_relkind_f_size"] = p.mx.relkindForeignTableSize
+ mx["catalog_relkind_p_size"] = p.mx.relkindPartitionedTableSize
+ mx["catalog_relkind_I_size"] = p.mx.relkindPartitionedIndexSize
+ mx["autovacuum_analyze"] = p.mx.autovacuumWorkersAnalyze
+ mx["autovacuum_vacuum_analyze"] = p.mx.autovacuumWorkersVacuumAnalyze
+ mx["autovacuum_vacuum"] = p.mx.autovacuumWorkersVacuum
+ mx["autovacuum_vacuum_freeze"] = p.mx.autovacuumWorkersVacuumFreeze
+ mx["autovacuum_brin_summarize"] = p.mx.autovacuumWorkersBrinSummarize
+
+ var locksHeld int64
+ for name, m := range p.mx.dbs {
+ if !m.updated {
+ delete(p.mx.dbs, name)
+ p.removeDatabaseCharts(m)
+ continue
+ }
+ if !m.hasCharts {
+ m.hasCharts = true
+ p.addNewDatabaseCharts(m)
+ if p.isPGInRecovery() {
+ p.addDBConflictsCharts(m)
+ }
+ }
+ px := "db_" + m.name + "_"
+ mx[px+"numbackends"] = m.numBackends
+ if m.datConnLimit <= 0 {
+ mx[px+"numbackends_utilization"] = calcPercentage(m.numBackends, p.mx.maxConnections)
+ } else {
+ mx[px+"numbackends_utilization"] = calcPercentage(m.numBackends, m.datConnLimit)
+ }
+ mx[px+"xact_commit"] = m.xactCommit
+ mx[px+"xact_rollback"] = m.xactRollback
+ mx[px+"blks_read"] = m.blksRead.last
+ mx[px+"blks_hit"] = m.blksHit.last
+ mx[px+"blks_read_perc"] = calcDeltaPercentage(m.blksRead, m.blksHit)
+ m.blksRead.prev, m.blksHit.prev = m.blksRead.last, m.blksHit.last
+ mx[px+"tup_returned"] = m.tupReturned.last
+ mx[px+"tup_fetched"] = m.tupFetched.last
+ mx[px+"tup_fetched_perc"] = calcPercentage(m.tupFetched.delta(), m.tupReturned.delta())
+ m.tupReturned.prev, m.tupFetched.prev = m.tupReturned.last, m.tupFetched.last
+ mx[px+"tup_inserted"] = m.tupInserted
+ mx[px+"tup_updated"] = m.tupUpdated
+ mx[px+"tup_deleted"] = m.tupDeleted
+ mx[px+"conflicts"] = m.conflicts
+ if m.size != nil {
+ mx[px+"size"] = *m.size
+ }
+ mx[px+"temp_files"] = m.tempFiles
+ mx[px+"temp_bytes"] = m.tempBytes
+ mx[px+"deadlocks"] = m.deadlocks
+ mx[px+"confl_tablespace"] = m.conflTablespace
+ mx[px+"confl_lock"] = m.conflLock
+ mx[px+"confl_snapshot"] = m.conflSnapshot
+ mx[px+"confl_bufferpin"] = m.conflBufferpin
+ mx[px+"confl_deadlock"] = m.conflDeadlock
+ mx[px+"lock_mode_AccessShareLock_held"] = m.accessShareLockHeld
+ mx[px+"lock_mode_RowShareLock_held"] = m.rowShareLockHeld
+ mx[px+"lock_mode_RowExclusiveLock_held"] = m.rowExclusiveLockHeld
+ mx[px+"lock_mode_ShareUpdateExclusiveLock_held"] = m.shareUpdateExclusiveLockHeld
+ mx[px+"lock_mode_ShareLock_held"] = m.shareLockHeld
+ mx[px+"lock_mode_ShareRowExclusiveLock_held"] = m.shareRowExclusiveLockHeld
+ mx[px+"lock_mode_ExclusiveLock_held"] = m.exclusiveLockHeld
+ mx[px+"lock_mode_AccessExclusiveLock_held"] = m.accessExclusiveLockHeld
+ mx[px+"lock_mode_AccessShareLock_awaited"] = m.accessShareLockAwaited
+ mx[px+"lock_mode_RowShareLock_awaited"] = m.rowShareLockAwaited
+ mx[px+"lock_mode_RowExclusiveLock_awaited"] = m.rowExclusiveLockAwaited
+ mx[px+"lock_mode_ShareUpdateExclusiveLock_awaited"] = m.shareUpdateExclusiveLockAwaited
+ mx[px+"lock_mode_ShareLock_awaited"] = m.shareLockAwaited
+ mx[px+"lock_mode_ShareRowExclusiveLock_awaited"] = m.shareRowExclusiveLockAwaited
+ mx[px+"lock_mode_ExclusiveLock_awaited"] = m.exclusiveLockAwaited
+ mx[px+"lock_mode_AccessExclusiveLock_awaited"] = m.accessExclusiveLockAwaited
+ locksHeld += m.accessShareLockHeld + m.rowShareLockHeld +
+ m.rowExclusiveLockHeld + m.shareUpdateExclusiveLockHeld +
+ m.shareLockHeld + m.shareRowExclusiveLockHeld +
+ m.exclusiveLockHeld + m.accessExclusiveLockHeld
+ }
+ mx["databases_count"] = int64(len(p.mx.dbs))
+ mx["locks_utilization"] = calcPercentage(locksHeld, p.mx.maxLocksHeld)
+
+ for name, m := range p.mx.tables {
+ if !m.updated {
+ delete(p.mx.tables, name)
+ p.removeTableCharts(m)
+ continue
+ }
+ if !m.hasCharts {
+ m.hasCharts = true
+ p.addNewTableCharts(m)
+ }
+ if !m.hasLastAutoVacuumChart && m.lastAutoVacuumAgo > 0 {
+ m.hasLastAutoVacuumChart = true
+ p.addTableLastAutoVacuumAgoChart(m)
+ }
+ if !m.hasLastVacuumChart && m.lastVacuumAgo > 0 {
+ m.hasLastVacuumChart = true
+ p.addTableLastVacuumAgoChart(m)
+ }
+ if !m.hasLastAutoAnalyzeChart && m.lastAutoAnalyzeAgo > 0 {
+ m.hasLastAutoAnalyzeChart = true
+ p.addTableLastAutoAnalyzeAgoChart(m)
+ }
+ if !m.hasLastAnalyzeChart && m.lastAnalyzeAgo > 0 {
+ m.hasLastAnalyzeChart = true
+ p.addTableLastAnalyzeAgoChart(m)
+ }
+ if !m.hasTableIOCharts && m.heapBlksRead.last != -1 {
+ m.hasTableIOCharts = true
+ p.addTableIOChartsCharts(m)
+ }
+ if !m.hasTableIdxIOCharts && m.idxBlksRead.last != -1 {
+ m.hasTableIdxIOCharts = true
+ p.addTableIndexIOCharts(m)
+ }
+ if !m.hasTableTOASTIOCharts && m.toastBlksRead.last != -1 {
+ m.hasTableTOASTIOCharts = true
+ p.addTableTOASTIOCharts(m)
+ }
+ if !m.hasTableTOASTIdxIOCharts && m.tidxBlksRead.last != -1 {
+ m.hasTableTOASTIdxIOCharts = true
+ p.addTableTOASTIndexIOCharts(m)
+ }
+
+ px := fmt.Sprintf("table_%s_db_%s_schema_%s_", m.name, m.db, m.schema)
+
+ mx[px+"seq_scan"] = m.seqScan
+ mx[px+"seq_tup_read"] = m.seqTupRead
+ mx[px+"idx_scan"] = m.idxScan
+ mx[px+"idx_tup_fetch"] = m.idxTupFetch
+ mx[px+"n_live_tup"] = m.nLiveTup
+ mx[px+"n_dead_tup"] = m.nDeadTup
+ mx[px+"n_dead_tup_perc"] = calcPercentage(m.nDeadTup, m.nDeadTup+m.nLiveTup)
+ mx[px+"n_tup_ins"] = m.nTupIns
+ mx[px+"n_tup_upd"] = m.nTupUpd.last
+ mx[px+"n_tup_del"] = m.nTupDel
+ mx[px+"n_tup_hot_upd"] = m.nTupHotUpd.last
+ if m.lastAutoVacuumAgo != -1 {
+ mx[px+"last_autovacuum_ago"] = m.lastAutoVacuumAgo
+ }
+ if m.lastVacuumAgo != -1 {
+ mx[px+"last_vacuum_ago"] = m.lastVacuumAgo
+ }
+ if m.lastAutoAnalyzeAgo != -1 {
+ mx[px+"last_autoanalyze_ago"] = m.lastAutoAnalyzeAgo
+ }
+ if m.lastAnalyzeAgo != -1 {
+ mx[px+"last_analyze_ago"] = m.lastAnalyzeAgo
+ }
+ mx[px+"total_size"] = m.totalSize
+ if m.bloatSize != nil && m.bloatSizePerc != nil {
+ mx[px+"bloat_size"] = *m.bloatSize
+ mx[px+"bloat_size_perc"] = *m.bloatSizePerc
+ }
+ if m.nullColumns != nil {
+ mx[px+"null_columns"] = *m.nullColumns
+ }
+
+ mx[px+"n_tup_hot_upd_perc"] = calcPercentage(m.nTupHotUpd.delta(), m.nTupUpd.delta())
+ m.nTupHotUpd.prev, m.nTupUpd.prev = m.nTupHotUpd.last, m.nTupUpd.last
+
+ mx[px+"heap_blks_read"] = m.heapBlksRead.last
+ mx[px+"heap_blks_hit"] = m.heapBlksHit.last
+ mx[px+"heap_blks_read_perc"] = calcDeltaPercentage(m.heapBlksRead, m.heapBlksHit)
+ m.heapBlksHit.prev, m.heapBlksRead.prev = m.heapBlksHit.last, m.heapBlksRead.last
+
+ mx[px+"idx_blks_read"] = m.idxBlksRead.last
+ mx[px+"idx_blks_hit"] = m.idxBlksHit.last
+ mx[px+"idx_blks_read_perc"] = calcDeltaPercentage(m.idxBlksRead, m.idxBlksHit)
+ m.idxBlksHit.prev, m.idxBlksRead.prev = m.idxBlksHit.last, m.idxBlksRead.last
+
+ mx[px+"toast_blks_read"] = m.toastBlksRead.last
+ mx[px+"toast_blks_hit"] = m.toastBlksHit.last
+ mx[px+"toast_blks_read_perc"] = calcDeltaPercentage(m.toastBlksRead, m.toastBlksHit)
+ m.toastBlksHit.prev, m.toastBlksRead.prev = m.toastBlksHit.last, m.toastBlksRead.last
+
+ mx[px+"tidx_blks_read"] = m.tidxBlksRead.last
+ mx[px+"tidx_blks_hit"] = m.tidxBlksHit.last
+ mx[px+"tidx_blks_read_perc"] = calcDeltaPercentage(m.tidxBlksRead, m.tidxBlksHit)
+ m.tidxBlksHit.prev, m.tidxBlksRead.prev = m.tidxBlksHit.last, m.tidxBlksRead.last
+ }
+
+ for name, m := range p.mx.indexes {
+ if !m.updated {
+ delete(p.mx.indexes, name)
+ p.removeIndexCharts(m)
+ continue
+ }
+ if !m.hasCharts {
+ m.hasCharts = true
+ p.addNewIndexCharts(m)
+ }
+
+ px := fmt.Sprintf("index_%s_table_%s_db_%s_schema_%s_", m.name, m.table, m.db, m.schema)
+ mx[px+"size"] = m.size
+ if m.bloatSize != nil && m.bloatSizePerc != nil {
+ mx[px+"bloat_size"] = *m.bloatSize
+ mx[px+"bloat_size_perc"] = *m.bloatSizePerc
+ }
+ if m.idxScan+m.idxTupRead+m.idxTupFetch > 0 {
+ mx[px+"usage_status_used"], mx[px+"usage_status_unused"] = 1, 0
+ } else {
+ mx[px+"usage_status_used"], mx[px+"usage_status_unused"] = 0, 1
+ }
+ }
+
+ for name, m := range p.mx.replApps {
+ if !m.updated {
+ delete(p.mx.replApps, name)
+ p.removeReplicationStandbyAppCharts(name)
+ continue
+ }
+ if !m.hasCharts {
+ m.hasCharts = true
+ p.addNewReplicationStandbyAppCharts(name)
+ }
+ px := "repl_standby_app_" + m.name + "_wal_"
+ mx[px+"sent_lag_size"] = m.walSentDelta
+ mx[px+"write_lag_size"] = m.walWriteDelta
+ mx[px+"flush_lag_size"] = m.walFlushDelta
+ mx[px+"replay_lag_size"] = m.walReplayDelta
+ mx[px+"write_time"] = m.walWriteLag
+ mx[px+"flush_lag_time"] = m.walFlushLag
+ mx[px+"replay_lag_time"] = m.walReplayLag
+ }
+
+ for name, m := range p.mx.replSlots {
+ if !m.updated {
+ delete(p.mx.replSlots, name)
+ p.removeReplicationSlotCharts(name)
+ continue
+ }
+ if !m.hasCharts {
+ m.hasCharts = true
+ p.addNewReplicationSlotCharts(name)
+ }
+ px := "repl_slot_" + m.name + "_"
+ mx[px+"replslot_wal_keep"] = m.walKeep
+ mx[px+"replslot_files"] = m.files
+ }
+}
+
+func (p *Postgres) resetMetrics() {
+ p.mx.srvMetrics = srvMetrics{
+ xactTimeHist: p.mx.xactTimeHist,
+ queryTimeHist: p.mx.queryTimeHist,
+ maxConnections: p.mx.maxConnections,
+ maxLocksHeld: p.mx.maxLocksHeld,
+ }
+ for name, m := range p.mx.dbs {
+ p.mx.dbs[name] = &dbMetrics{
+ name: m.name,
+ hasCharts: m.hasCharts,
+ blksRead: incDelta{prev: m.blksRead.prev},
+ blksHit: incDelta{prev: m.blksHit.prev},
+ tupReturned: incDelta{prev: m.tupReturned.prev},
+ tupFetched: incDelta{prev: m.tupFetched.prev},
+ }
+ }
+ for name, m := range p.mx.tables {
+ p.mx.tables[name] = &tableMetrics{
+ db: m.db,
+ schema: m.schema,
+ name: m.name,
+ hasCharts: m.hasCharts,
+ hasLastAutoVacuumChart: m.hasLastAutoVacuumChart,
+ hasLastVacuumChart: m.hasLastVacuumChart,
+ hasLastAutoAnalyzeChart: m.hasLastAutoAnalyzeChart,
+ hasLastAnalyzeChart: m.hasLastAnalyzeChart,
+ hasTableIOCharts: m.hasTableIOCharts,
+ hasTableIdxIOCharts: m.hasTableIdxIOCharts,
+ hasTableTOASTIOCharts: m.hasTableTOASTIOCharts,
+ hasTableTOASTIdxIOCharts: m.hasTableTOASTIdxIOCharts,
+ nTupUpd: incDelta{prev: m.nTupUpd.prev},
+ nTupHotUpd: incDelta{prev: m.nTupHotUpd.prev},
+ heapBlksRead: incDelta{prev: m.heapBlksRead.prev},
+ heapBlksHit: incDelta{prev: m.heapBlksHit.prev},
+ idxBlksRead: incDelta{prev: m.idxBlksRead.prev},
+ idxBlksHit: incDelta{prev: m.idxBlksHit.prev},
+ toastBlksRead: incDelta{prev: m.toastBlksRead.prev},
+ toastBlksHit: incDelta{prev: m.toastBlksHit.prev},
+ tidxBlksRead: incDelta{prev: m.tidxBlksRead.prev},
+ tidxBlksHit: incDelta{prev: m.tidxBlksHit.prev},
+ bloatSize: m.bloatSize,
+ bloatSizePerc: m.bloatSizePerc,
+ nullColumns: m.nullColumns,
+ }
+ }
+ for name, m := range p.mx.indexes {
+ p.mx.indexes[name] = &indexMetrics{
+ name: m.name,
+ db: m.db,
+ schema: m.schema,
+ table: m.table,
+ updated: m.updated,
+ hasCharts: m.hasCharts,
+ bloatSize: m.bloatSize,
+ bloatSizePerc: m.bloatSizePerc,
+ }
+ }
+ for name, m := range p.mx.replApps {
+ p.mx.replApps[name] = &replStandbyAppMetrics{
+ name: m.name,
+ hasCharts: m.hasCharts,
+ }
+ }
+ for name, m := range p.mx.replSlots {
+ p.mx.replSlots[name] = &replSlotMetrics{
+ name: m.name,
+ hasCharts: m.hasCharts,
+ }
+ }
+}