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  }