master
go 367 lines 14 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package postgres
4
5 import "fmt"
6
7 func (c *Collector) collectMetrics(mx map[string]int64) {
8 mx["server_connections_used"] = c.mx.connUsed
9 if c.mx.maxConnections > 0 {
10 mx["server_connections_available"] = c.mx.maxConnections - c.mx.connUsed
11 mx["server_connections_utilization"] = calcPercentage(c.mx.connUsed, c.mx.maxConnections)
12 }
13 c.mx.xactTimeHist.WriteTo(mx, "transaction_running_time_hist", 1, 1)
14 c.mx.queryTimeHist.WriteTo(mx, "query_running_time_hist", 1, 1)
15 mx["server_uptime"] = c.mx.uptime
16 mx["server_connections_state_active"] = c.mx.connStateActive
17 mx["server_connections_state_idle"] = c.mx.connStateIdle
18 mx["server_connections_state_idle_in_transaction"] = c.mx.connStateIdleInTrans
19 mx["server_connections_state_idle_in_transaction_aborted"] = c.mx.connStateIdleInTransAborted
20 mx["server_connections_state_fastpath_function_call"] = c.mx.connStateFastpathFunctionCall
21 mx["server_connections_state_disabled"] = c.mx.connStateDisabled
22 mx["checkpoints_timed"] = c.mx.checkpointsTimed
23 mx["checkpoints_req"] = c.mx.checkpointsReq
24 mx["checkpoint_write_time"] = c.mx.checkpointWriteTime
25 mx["checkpoint_sync_time"] = c.mx.checkpointSyncTime
26 mx["buffers_checkpoint"] = c.mx.buffersCheckpoint
27 mx["buffers_clean"] = c.mx.buffersClean
28 mx["maxwritten_clean"] = c.mx.maxwrittenClean
29 mx["buffers_backend"] = c.mx.buffersBackend
30 mx["buffers_backend_fsync"] = c.mx.buffersBackendFsync
31 mx["buffers_alloc"] = c.mx.buffersAlloc
32 mx["oldest_current_xid"] = c.mx.oldestXID
33 mx["percent_towards_wraparound"] = c.mx.percentTowardsWraparound
34 mx["percent_towards_emergency_autovacuum"] = c.mx.percentTowardsEmergencyAutovacuum
35 mx["wal_writes"] = c.mx.walWrites
36 mx["wal_recycled_files"] = c.mx.walRecycledFiles
37 mx["wal_written_files"] = c.mx.walWrittenFiles
38 mx["wal_archive_files_ready_count"] = c.mx.walArchiveFilesReady
39 mx["wal_archive_files_done_count"] = c.mx.walArchiveFilesDone
40 mx["catalog_relkind_r_count"] = c.mx.relkindOrdinaryTable
41 mx["catalog_relkind_i_count"] = c.mx.relkindIndex
42 mx["catalog_relkind_S_count"] = c.mx.relkindSequence
43 mx["catalog_relkind_t_count"] = c.mx.relkindTOASTTable
44 mx["catalog_relkind_v_count"] = c.mx.relkindView
45 mx["catalog_relkind_m_count"] = c.mx.relkindMatView
46 mx["catalog_relkind_c_count"] = c.mx.relkindCompositeType
47 mx["catalog_relkind_f_count"] = c.mx.relkindForeignTable
48 mx["catalog_relkind_p_count"] = c.mx.relkindPartitionedTable
49 mx["catalog_relkind_I_count"] = c.mx.relkindPartitionedIndex
50 mx["catalog_relkind_r_size"] = c.mx.relkindOrdinaryTableSize
51 mx["catalog_relkind_i_size"] = c.mx.relkindIndexSize
52 mx["catalog_relkind_S_size"] = c.mx.relkindSequenceSize
53 mx["catalog_relkind_t_size"] = c.mx.relkindTOASTTableSize
54 mx["catalog_relkind_v_size"] = c.mx.relkindViewSize
55 mx["catalog_relkind_m_size"] = c.mx.relkindMatViewSize
56 mx["catalog_relkind_c_size"] = c.mx.relkindCompositeTypeSize
57 mx["catalog_relkind_f_size"] = c.mx.relkindForeignTableSize
58 mx["catalog_relkind_p_size"] = c.mx.relkindPartitionedTableSize
59 mx["catalog_relkind_I_size"] = c.mx.relkindPartitionedIndexSize
60 mx["autovacuum_analyze"] = c.mx.autovacuumWorkersAnalyze
61 mx["autovacuum_vacuum_analyze"] = c.mx.autovacuumWorkersVacuumAnalyze
62 mx["autovacuum_vacuum"] = c.mx.autovacuumWorkersVacuum
63 mx["autovacuum_vacuum_freeze"] = c.mx.autovacuumWorkersVacuumFreeze
64 mx["autovacuum_brin_summarize"] = c.mx.autovacuumWorkersBrinSummarize
65
66 var locksHeld int64
67 for name, m := range c.mx.dbs {
68 if !m.updated {
69 delete(c.mx.dbs, name)
70 c.removeDatabaseCharts(m)
71 continue
72 }
73 if !m.hasCharts {
74 m.hasCharts = true
75 c.addNewDatabaseCharts(m)
76 if c.isPGInRecovery() {
77 c.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, c.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(c.mx.dbs))
134 mx["locks_utilization"] = calcPercentage(locksHeld, c.mx.maxLocksHeld)
135
136 for name, m := range c.mx.tables {
137 if !m.updated {
138 delete(c.mx.tables, name)
139 c.removeTableCharts(m)
140 continue
141 }
142 if !m.hasCharts {
143 m.hasCharts = true
144 c.addNewTableCharts(m)
145 }
146 if !m.hasLastAutoVacuumChart && m.lastAutoVacuumAgo > 0 {
147 m.hasLastAutoVacuumChart = true
148 c.addTableLastAutoVacuumAgoChart(m)
149 }
150 if !m.hasLastVacuumChart && m.lastVacuumAgo > 0 {
151 m.hasLastVacuumChart = true
152 c.addTableLastVacuumAgoChart(m)
153 }
154 if !m.hasLastAutoAnalyzeChart && m.lastAutoAnalyzeAgo > 0 {
155 m.hasLastAutoAnalyzeChart = true
156 c.addTableLastAutoAnalyzeAgoChart(m)
157 }
158 if !m.hasLastAnalyzeChart && m.lastAnalyzeAgo > 0 {
159 m.hasLastAnalyzeChart = true
160 c.addTableLastAnalyzeAgoChart(m)
161 }
162 if !m.hasTableIOCharts && m.heapBlksRead.last != -1 {
163 m.hasTableIOCharts = true
164 c.addTableIOChartsCharts(m)
165 }
166 if !m.hasTableIdxIOCharts && m.idxBlksRead.last != -1 {
167 m.hasTableIdxIOCharts = true
168 c.addTableIndexIOCharts(m)
169 }
170 if !m.hasTableTOASTIOCharts && m.toastBlksRead.last != -1 {
171 m.hasTableTOASTIOCharts = true
172 c.addTableTOASTIOCharts(m)
173 }
174 if !m.hasTableTOASTIdxIOCharts && m.tidxBlksRead.last != -1 {
175 m.hasTableTOASTIdxIOCharts = true
176 c.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 c.mx.indexes {
238 if !m.updated {
239 delete(c.mx.indexes, name)
240 c.removeIndexCharts(m)
241 continue
242 }
243 if !m.hasCharts {
244 m.hasCharts = true
245 c.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 c.mx.replApps {
262 if !m.updated {
263 delete(c.mx.replApps, name)
264 c.removeReplicationStandbyAppCharts(name)
265 continue
266 }
267 if !m.hasCharts {
268 m.hasCharts = true
269 c.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 c.mx.replSlots {
282 if !m.updated {
283 delete(c.mx.replSlots, name)
284 c.removeReplicationSlotCharts(name)
285 continue
286 }
287 if !m.hasCharts {
288 m.hasCharts = true
289 c.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 (c *Collector) resetMetrics() {
298 c.mx.srvMetrics = srvMetrics{
299 xactTimeHist: c.mx.xactTimeHist,
300 queryTimeHist: c.mx.queryTimeHist,
301 maxConnections: c.mx.maxConnections,
302 maxLocksHeld: c.mx.maxLocksHeld,
303 }
304 for name, m := range c.mx.dbs {
305 c.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 c.mx.tables {
315 c.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 c.mx.indexes {
344 c.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 c.mx.replApps {
356 c.mx.replApps[name] = &replStandbyAppMetrics{
357 name: m.name,
358 hasCharts: m.hasCharts,
359 }
360 }
361 for name, m := range c.mx.replSlots {
362 c.mx.replSlots[name] = &replSlotMetrics{
363 name: m.name,
364 hasCharts: m.hasCharts,
365 }
366 }
367 }