diff options
Diffstat (limited to 'src/go/collectors/go.d.plugin/modules/postgres/collect_metrics.go')
-rw-r--r-- | src/go/collectors/go.d.plugin/modules/postgres/collect_metrics.go | 367 |
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, + } + } +} |