github.com/netdata/go.d.plugin@v0.58.1/modules/postgres/collect_metrics.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package postgres 4 5 import "fmt" 6 7 func (p *Postgres) collectMetrics(mx map[string]int64) { 8 mx["server_connections_used"] = p.mx.connUsed 9 if p.mx.maxConnections > 0 { 10 mx["server_connections_available"] = p.mx.maxConnections - p.mx.connUsed 11 mx["server_connections_utilization"] = calcPercentage(p.mx.connUsed, p.mx.maxConnections) 12 } 13 p.mx.xactTimeHist.WriteTo(mx, "transaction_running_time_hist", 1, 1) 14 p.mx.queryTimeHist.WriteTo(mx, "query_running_time_hist", 1, 1) 15 mx["server_uptime"] = p.mx.uptime 16 mx["server_connections_state_active"] = p.mx.connStateActive 17 mx["server_connections_state_idle"] = p.mx.connStateIdle 18 mx["server_connections_state_idle_in_transaction"] = p.mx.connStateIdleInTrans 19 mx["server_connections_state_idle_in_transaction_aborted"] = p.mx.connStateIdleInTransAborted 20 mx["server_connections_state_fastpath_function_call"] = p.mx.connStateFastpathFunctionCall 21 mx["server_connections_state_disabled"] = p.mx.connStateDisabled 22 mx["checkpoints_timed"] = p.mx.checkpointsTimed 23 mx["checkpoints_req"] = p.mx.checkpointsReq 24 mx["checkpoint_write_time"] = p.mx.checkpointWriteTime 25 mx["checkpoint_sync_time"] = p.mx.checkpointSyncTime 26 mx["buffers_checkpoint"] = p.mx.buffersCheckpoint 27 mx["buffers_clean"] = p.mx.buffersClean 28 mx["maxwritten_clean"] = p.mx.maxwrittenClean 29 mx["buffers_backend"] = p.mx.buffersBackend 30 mx["buffers_backend_fsync"] = p.mx.buffersBackendFsync 31 mx["buffers_alloc"] = p.mx.buffersAlloc 32 mx["oldest_current_xid"] = p.mx.oldestXID 33 mx["percent_towards_wraparound"] = p.mx.percentTowardsWraparound 34 mx["percent_towards_emergency_autovacuum"] = p.mx.percentTowardsEmergencyAutovacuum 35 mx["wal_writes"] = p.mx.walWrites 36 mx["wal_recycled_files"] = p.mx.walRecycledFiles 37 mx["wal_written_files"] = p.mx.walWrittenFiles 38 mx["wal_archive_files_ready_count"] = p.mx.walArchiveFilesReady 39 mx["wal_archive_files_done_count"] = p.mx.walArchiveFilesDone 40 mx["catalog_relkind_r_count"] = p.mx.relkindOrdinaryTable 41 mx["catalog_relkind_i_count"] = p.mx.relkindIndex 42 mx["catalog_relkind_S_count"] = p.mx.relkindSequence 43 mx["catalog_relkind_t_count"] = p.mx.relkindTOASTTable 44 mx["catalog_relkind_v_count"] = p.mx.relkindView 45 mx["catalog_relkind_m_count"] = p.mx.relkindMatView 46 mx["catalog_relkind_c_count"] = p.mx.relkindCompositeType 47 mx["catalog_relkind_f_count"] = p.mx.relkindForeignTable 48 mx["catalog_relkind_p_count"] = p.mx.relkindPartitionedTable 49 mx["catalog_relkind_I_count"] = p.mx.relkindPartitionedIndex 50 mx["catalog_relkind_r_size"] = p.mx.relkindOrdinaryTableSize 51 mx["catalog_relkind_i_size"] = p.mx.relkindIndexSize 52 mx["catalog_relkind_S_size"] = p.mx.relkindSequenceSize 53 mx["catalog_relkind_t_size"] = p.mx.relkindTOASTTableSize 54 mx["catalog_relkind_v_size"] = p.mx.relkindViewSize 55 mx["catalog_relkind_m_size"] = p.mx.relkindMatViewSize 56 mx["catalog_relkind_c_size"] = p.mx.relkindCompositeTypeSize 57 mx["catalog_relkind_f_size"] = p.mx.relkindForeignTableSize 58 mx["catalog_relkind_p_size"] = p.mx.relkindPartitionedTableSize 59 mx["catalog_relkind_I_size"] = p.mx.relkindPartitionedIndexSize 60 mx["autovacuum_analyze"] = p.mx.autovacuumWorkersAnalyze 61 mx["autovacuum_vacuum_analyze"] = p.mx.autovacuumWorkersVacuumAnalyze 62 mx["autovacuum_vacuum"] = p.mx.autovacuumWorkersVacuum 63 mx["autovacuum_vacuum_freeze"] = p.mx.autovacuumWorkersVacuumFreeze 64 mx["autovacuum_brin_summarize"] = p.mx.autovacuumWorkersBrinSummarize 65 66 var locksHeld int64 67 for name, m := range p.mx.dbs { 68 if !m.updated { 69 delete(p.mx.dbs, name) 70 p.removeDatabaseCharts(m) 71 continue 72 } 73 if !m.hasCharts { 74 m.hasCharts = true 75 p.addNewDatabaseCharts(m) 76 if p.isPGInRecovery() { 77 p.addDBConflictsCharts(m) 78 } 79 } 80 px := "db_" + m.name + "_" 81 mx[px+"numbackends"] = m.numBackends 82 if m.datConnLimit <= 0 { 83 mx[px+"numbackends_utilization"] = calcPercentage(m.numBackends, p.mx.maxConnections) 84 } else { 85 mx[px+"numbackends_utilization"] = calcPercentage(m.numBackends, m.datConnLimit) 86 } 87 mx[px+"xact_commit"] = m.xactCommit 88 mx[px+"xact_rollback"] = m.xactRollback 89 mx[px+"blks_read"] = m.blksRead.last 90 mx[px+"blks_hit"] = m.blksHit.last 91 mx[px+"blks_read_perc"] = calcDeltaPercentage(m.blksRead, m.blksHit) 92 m.blksRead.prev, m.blksHit.prev = m.blksRead.last, m.blksHit.last 93 mx[px+"tup_returned"] = m.tupReturned.last 94 mx[px+"tup_fetched"] = m.tupFetched.last 95 mx[px+"tup_fetched_perc"] = calcPercentage(m.tupFetched.delta(), m.tupReturned.delta()) 96 m.tupReturned.prev, m.tupFetched.prev = m.tupReturned.last, m.tupFetched.last 97 mx[px+"tup_inserted"] = m.tupInserted 98 mx[px+"tup_updated"] = m.tupUpdated 99 mx[px+"tup_deleted"] = m.tupDeleted 100 mx[px+"conflicts"] = m.conflicts 101 if m.size != nil { 102 mx[px+"size"] = *m.size 103 } 104 mx[px+"temp_files"] = m.tempFiles 105 mx[px+"temp_bytes"] = m.tempBytes 106 mx[px+"deadlocks"] = m.deadlocks 107 mx[px+"confl_tablespace"] = m.conflTablespace 108 mx[px+"confl_lock"] = m.conflLock 109 mx[px+"confl_snapshot"] = m.conflSnapshot 110 mx[px+"confl_bufferpin"] = m.conflBufferpin 111 mx[px+"confl_deadlock"] = m.conflDeadlock 112 mx[px+"lock_mode_AccessShareLock_held"] = m.accessShareLockHeld 113 mx[px+"lock_mode_RowShareLock_held"] = m.rowShareLockHeld 114 mx[px+"lock_mode_RowExclusiveLock_held"] = m.rowExclusiveLockHeld 115 mx[px+"lock_mode_ShareUpdateExclusiveLock_held"] = m.shareUpdateExclusiveLockHeld 116 mx[px+"lock_mode_ShareLock_held"] = m.shareLockHeld 117 mx[px+"lock_mode_ShareRowExclusiveLock_held"] = m.shareRowExclusiveLockHeld 118 mx[px+"lock_mode_ExclusiveLock_held"] = m.exclusiveLockHeld 119 mx[px+"lock_mode_AccessExclusiveLock_held"] = m.accessExclusiveLockHeld 120 mx[px+"lock_mode_AccessShareLock_awaited"] = m.accessShareLockAwaited 121 mx[px+"lock_mode_RowShareLock_awaited"] = m.rowShareLockAwaited 122 mx[px+"lock_mode_RowExclusiveLock_awaited"] = m.rowExclusiveLockAwaited 123 mx[px+"lock_mode_ShareUpdateExclusiveLock_awaited"] = m.shareUpdateExclusiveLockAwaited 124 mx[px+"lock_mode_ShareLock_awaited"] = m.shareLockAwaited 125 mx[px+"lock_mode_ShareRowExclusiveLock_awaited"] = m.shareRowExclusiveLockAwaited 126 mx[px+"lock_mode_ExclusiveLock_awaited"] = m.exclusiveLockAwaited 127 mx[px+"lock_mode_AccessExclusiveLock_awaited"] = m.accessExclusiveLockAwaited 128 locksHeld += m.accessShareLockHeld + m.rowShareLockHeld + 129 m.rowExclusiveLockHeld + m.shareUpdateExclusiveLockHeld + 130 m.shareLockHeld + m.shareRowExclusiveLockHeld + 131 m.exclusiveLockHeld + m.accessExclusiveLockHeld 132 } 133 mx["databases_count"] = int64(len(p.mx.dbs)) 134 mx["locks_utilization"] = calcPercentage(locksHeld, p.mx.maxLocksHeld) 135 136 for name, m := range p.mx.tables { 137 if !m.updated { 138 delete(p.mx.tables, name) 139 p.removeTableCharts(m) 140 continue 141 } 142 if !m.hasCharts { 143 m.hasCharts = true 144 p.addNewTableCharts(m) 145 } 146 if !m.hasLastAutoVacuumChart && m.lastAutoVacuumAgo > 0 { 147 m.hasLastAutoVacuumChart = true 148 p.addTableLastAutoVacuumAgoChart(m) 149 } 150 if !m.hasLastVacuumChart && m.lastVacuumAgo > 0 { 151 m.hasLastVacuumChart = true 152 p.addTableLastVacuumAgoChart(m) 153 } 154 if !m.hasLastAutoAnalyzeChart && m.lastAutoAnalyzeAgo > 0 { 155 m.hasLastAutoAnalyzeChart = true 156 p.addTableLastAutoAnalyzeAgoChart(m) 157 } 158 if !m.hasLastAnalyzeChart && m.lastAnalyzeAgo > 0 { 159 m.hasLastAnalyzeChart = true 160 p.addTableLastAnalyzeAgoChart(m) 161 } 162 if !m.hasTableIOCharts && m.heapBlksRead.last != -1 { 163 m.hasTableIOCharts = true 164 p.addTableIOChartsCharts(m) 165 } 166 if !m.hasTableIdxIOCharts && m.idxBlksRead.last != -1 { 167 m.hasTableIdxIOCharts = true 168 p.addTableIndexIOCharts(m) 169 } 170 if !m.hasTableTOASTIOCharts && m.toastBlksRead.last != -1 { 171 m.hasTableTOASTIOCharts = true 172 p.addTableTOASTIOCharts(m) 173 } 174 if !m.hasTableTOASTIdxIOCharts && m.tidxBlksRead.last != -1 { 175 m.hasTableTOASTIdxIOCharts = true 176 p.addTableTOASTIndexIOCharts(m) 177 } 178 179 px := fmt.Sprintf("table_%s_db_%s_schema_%s_", m.name, m.db, m.schema) 180 181 mx[px+"seq_scan"] = m.seqScan 182 mx[px+"seq_tup_read"] = m.seqTupRead 183 mx[px+"idx_scan"] = m.idxScan 184 mx[px+"idx_tup_fetch"] = m.idxTupFetch 185 mx[px+"n_live_tup"] = m.nLiveTup 186 mx[px+"n_dead_tup"] = m.nDeadTup 187 mx[px+"n_dead_tup_perc"] = calcPercentage(m.nDeadTup, m.nDeadTup+m.nLiveTup) 188 mx[px+"n_tup_ins"] = m.nTupIns 189 mx[px+"n_tup_upd"] = m.nTupUpd.last 190 mx[px+"n_tup_del"] = m.nTupDel 191 mx[px+"n_tup_hot_upd"] = m.nTupHotUpd.last 192 if m.lastAutoVacuumAgo != -1 { 193 mx[px+"last_autovacuum_ago"] = m.lastAutoVacuumAgo 194 } 195 if m.lastVacuumAgo != -1 { 196 mx[px+"last_vacuum_ago"] = m.lastVacuumAgo 197 } 198 if m.lastAutoAnalyzeAgo != -1 { 199 mx[px+"last_autoanalyze_ago"] = m.lastAutoAnalyzeAgo 200 } 201 if m.lastAnalyzeAgo != -1 { 202 mx[px+"last_analyze_ago"] = m.lastAnalyzeAgo 203 } 204 mx[px+"total_size"] = m.totalSize 205 if m.bloatSize != nil && m.bloatSizePerc != nil { 206 mx[px+"bloat_size"] = *m.bloatSize 207 mx[px+"bloat_size_perc"] = *m.bloatSizePerc 208 } 209 if m.nullColumns != nil { 210 mx[px+"null_columns"] = *m.nullColumns 211 } 212 213 mx[px+"n_tup_hot_upd_perc"] = calcPercentage(m.nTupHotUpd.delta(), m.nTupUpd.delta()) 214 m.nTupHotUpd.prev, m.nTupUpd.prev = m.nTupHotUpd.last, m.nTupUpd.last 215 216 mx[px+"heap_blks_read"] = m.heapBlksRead.last 217 mx[px+"heap_blks_hit"] = m.heapBlksHit.last 218 mx[px+"heap_blks_read_perc"] = calcDeltaPercentage(m.heapBlksRead, m.heapBlksHit) 219 m.heapBlksHit.prev, m.heapBlksRead.prev = m.heapBlksHit.last, m.heapBlksRead.last 220 221 mx[px+"idx_blks_read"] = m.idxBlksRead.last 222 mx[px+"idx_blks_hit"] = m.idxBlksHit.last 223 mx[px+"idx_blks_read_perc"] = calcDeltaPercentage(m.idxBlksRead, m.idxBlksHit) 224 m.idxBlksHit.prev, m.idxBlksRead.prev = m.idxBlksHit.last, m.idxBlksRead.last 225 226 mx[px+"toast_blks_read"] = m.toastBlksRead.last 227 mx[px+"toast_blks_hit"] = m.toastBlksHit.last 228 mx[px+"toast_blks_read_perc"] = calcDeltaPercentage(m.toastBlksRead, m.toastBlksHit) 229 m.toastBlksHit.prev, m.toastBlksRead.prev = m.toastBlksHit.last, m.toastBlksRead.last 230 231 mx[px+"tidx_blks_read"] = m.tidxBlksRead.last 232 mx[px+"tidx_blks_hit"] = m.tidxBlksHit.last 233 mx[px+"tidx_blks_read_perc"] = calcDeltaPercentage(m.tidxBlksRead, m.tidxBlksHit) 234 m.tidxBlksHit.prev, m.tidxBlksRead.prev = m.tidxBlksHit.last, m.tidxBlksRead.last 235 } 236 237 for name, m := range p.mx.indexes { 238 if !m.updated { 239 delete(p.mx.indexes, name) 240 p.removeIndexCharts(m) 241 continue 242 } 243 if !m.hasCharts { 244 m.hasCharts = true 245 p.addNewIndexCharts(m) 246 } 247 248 px := fmt.Sprintf("index_%s_table_%s_db_%s_schema_%s_", m.name, m.table, m.db, m.schema) 249 mx[px+"size"] = m.size 250 if m.bloatSize != nil && m.bloatSizePerc != nil { 251 mx[px+"bloat_size"] = *m.bloatSize 252 mx[px+"bloat_size_perc"] = *m.bloatSizePerc 253 } 254 if m.idxScan+m.idxTupRead+m.idxTupFetch > 0 { 255 mx[px+"usage_status_used"], mx[px+"usage_status_unused"] = 1, 0 256 } else { 257 mx[px+"usage_status_used"], mx[px+"usage_status_unused"] = 0, 1 258 } 259 } 260 261 for name, m := range p.mx.replApps { 262 if !m.updated { 263 delete(p.mx.replApps, name) 264 p.removeReplicationStandbyAppCharts(name) 265 continue 266 } 267 if !m.hasCharts { 268 m.hasCharts = true 269 p.addNewReplicationStandbyAppCharts(name) 270 } 271 px := "repl_standby_app_" + m.name + "_wal_" 272 mx[px+"sent_lag_size"] = m.walSentDelta 273 mx[px+"write_lag_size"] = m.walWriteDelta 274 mx[px+"flush_lag_size"] = m.walFlushDelta 275 mx[px+"replay_lag_size"] = m.walReplayDelta 276 mx[px+"write_time"] = m.walWriteLag 277 mx[px+"flush_lag_time"] = m.walFlushLag 278 mx[px+"replay_lag_time"] = m.walReplayLag 279 } 280 281 for name, m := range p.mx.replSlots { 282 if !m.updated { 283 delete(p.mx.replSlots, name) 284 p.removeReplicationSlotCharts(name) 285 continue 286 } 287 if !m.hasCharts { 288 m.hasCharts = true 289 p.addNewReplicationSlotCharts(name) 290 } 291 px := "repl_slot_" + m.name + "_" 292 mx[px+"replslot_wal_keep"] = m.walKeep 293 mx[px+"replslot_files"] = m.files 294 } 295 } 296 297 func (p *Postgres) resetMetrics() { 298 p.mx.srvMetrics = srvMetrics{ 299 xactTimeHist: p.mx.xactTimeHist, 300 queryTimeHist: p.mx.queryTimeHist, 301 maxConnections: p.mx.maxConnections, 302 maxLocksHeld: p.mx.maxLocksHeld, 303 } 304 for name, m := range p.mx.dbs { 305 p.mx.dbs[name] = &dbMetrics{ 306 name: m.name, 307 hasCharts: m.hasCharts, 308 blksRead: incDelta{prev: m.blksRead.prev}, 309 blksHit: incDelta{prev: m.blksHit.prev}, 310 tupReturned: incDelta{prev: m.tupReturned.prev}, 311 tupFetched: incDelta{prev: m.tupFetched.prev}, 312 } 313 } 314 for name, m := range p.mx.tables { 315 p.mx.tables[name] = &tableMetrics{ 316 db: m.db, 317 schema: m.schema, 318 name: m.name, 319 hasCharts: m.hasCharts, 320 hasLastAutoVacuumChart: m.hasLastAutoVacuumChart, 321 hasLastVacuumChart: m.hasLastVacuumChart, 322 hasLastAutoAnalyzeChart: m.hasLastAutoAnalyzeChart, 323 hasLastAnalyzeChart: m.hasLastAnalyzeChart, 324 hasTableIOCharts: m.hasTableIOCharts, 325 hasTableIdxIOCharts: m.hasTableIdxIOCharts, 326 hasTableTOASTIOCharts: m.hasTableTOASTIOCharts, 327 hasTableTOASTIdxIOCharts: m.hasTableTOASTIdxIOCharts, 328 nTupUpd: incDelta{prev: m.nTupUpd.prev}, 329 nTupHotUpd: incDelta{prev: m.nTupHotUpd.prev}, 330 heapBlksRead: incDelta{prev: m.heapBlksRead.prev}, 331 heapBlksHit: incDelta{prev: m.heapBlksHit.prev}, 332 idxBlksRead: incDelta{prev: m.idxBlksRead.prev}, 333 idxBlksHit: incDelta{prev: m.idxBlksHit.prev}, 334 toastBlksRead: incDelta{prev: m.toastBlksRead.prev}, 335 toastBlksHit: incDelta{prev: m.toastBlksHit.prev}, 336 tidxBlksRead: incDelta{prev: m.tidxBlksRead.prev}, 337 tidxBlksHit: incDelta{prev: m.tidxBlksHit.prev}, 338 bloatSize: m.bloatSize, 339 bloatSizePerc: m.bloatSizePerc, 340 nullColumns: m.nullColumns, 341 } 342 } 343 for name, m := range p.mx.indexes { 344 p.mx.indexes[name] = &indexMetrics{ 345 name: m.name, 346 db: m.db, 347 schema: m.schema, 348 table: m.table, 349 updated: m.updated, 350 hasCharts: m.hasCharts, 351 bloatSize: m.bloatSize, 352 bloatSizePerc: m.bloatSizePerc, 353 } 354 } 355 for name, m := range p.mx.replApps { 356 p.mx.replApps[name] = &replStandbyAppMetrics{ 357 name: m.name, 358 hasCharts: m.hasCharts, 359 } 360 } 361 for name, m := range p.mx.replSlots { 362 p.mx.replSlots[name] = &replSlotMetrics{ 363 name: m.name, 364 hasCharts: m.hasCharts, 365 } 366 } 367 }