master
go 285 lines 7.13 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package postgres
4
5 import (
6 "fmt"
7 "strconv"
8 )
9
10 func (c *Collector) doQueryGlobalMetrics() error {
11 if err := c.doQueryConnectionsUsed(); err != nil {
12 return fmt.Errorf("querying server connections used error: %v", err)
13 }
14 if err := c.doQueryConnectionsState(); err != nil {
15 return fmt.Errorf("querying server connections state error: %v", err)
16 }
17 if err := c.doQueryCheckpoints(); err != nil {
18 return fmt.Errorf("querying database conflicts error: %v", err)
19 }
20 if err := c.doQueryUptime(); err != nil {
21 return fmt.Errorf("querying server uptime error: %v", err)
22 }
23 if err := c.doQueryTXIDWraparound(); err != nil {
24 return fmt.Errorf("querying txid wraparound error: %v", err)
25 }
26 if err := c.doQueryWALWrites(); err != nil {
27 return fmt.Errorf("querying wal writes error: %v", err)
28 }
29 if err := c.doQueryCatalogRelations(); err != nil {
30 return fmt.Errorf("querying catalog relations error: %v", err)
31 }
32 if c.pgVersion >= pgVersion94 {
33 if err := c.doQueryAutovacuumWorkers(); err != nil {
34 return fmt.Errorf("querying autovacuum workers error: %v", err)
35 }
36 }
37 if c.pgVersion >= pgVersion10 {
38 if err := c.doQueryXactQueryRunningTime(); err != nil {
39 return fmt.Errorf("querying xact/query running time: %v", err)
40 }
41 }
42
43 if !c.isSuperUser() {
44 return nil
45 }
46
47 if c.pgVersion >= pgVersion94 {
48 if err := c.doQueryWALFiles(); err != nil {
49 return fmt.Errorf("querying wal files error: %v", err)
50 }
51 }
52 if err := c.doQueryWALArchiveFiles(); err != nil {
53 return fmt.Errorf("querying wal archive files error: %v", err)
54 }
55
56 return nil
57 }
58
59 func (c *Collector) doQueryConnectionsUsed() error {
60 q := queryServerCurrentConnectionsUsed()
61
62 var v string
63 if err := c.doQueryRow(q, &v); err != nil {
64 return err
65 }
66
67 c.mx.connUsed = parseInt(v)
68
69 return nil
70 }
71
72 func (c *Collector) doQueryConnectionsState() error {
73 q := queryServerConnectionsState()
74
75 var state string
76 return c.doQuery(q, func(column, value string, rowEnd bool) {
77 switch column {
78 case "state":
79 state = value
80 case "count":
81 switch state {
82 case "active":
83 c.mx.connStateActive = parseInt(value)
84 case "idle":
85 c.mx.connStateIdle = parseInt(value)
86 case "idle in transaction":
87 c.mx.connStateIdleInTrans = parseInt(value)
88 case "idle in transaction (aborted)":
89 c.mx.connStateIdleInTransAborted = parseInt(value)
90 case "fastpath function call":
91 c.mx.connStateFastpathFunctionCall = parseInt(value)
92 case "disabled":
93 c.mx.connStateDisabled = parseInt(value)
94 }
95 }
96 })
97 }
98
99 func (c *Collector) doQueryCheckpoints() error {
100 q := queryCheckpoints(c.pgVersion)
101
102 return c.doQuery(q, func(column, value string, _ bool) {
103 switch column {
104 case "checkpoints_timed":
105 c.mx.checkpointsTimed = parseInt(value)
106 case "checkpoints_req":
107 c.mx.checkpointsReq = parseInt(value)
108 case "checkpoint_write_time":
109 c.mx.checkpointWriteTime = parseInt(value)
110 case "checkpoint_sync_time":
111 c.mx.checkpointSyncTime = parseInt(value)
112 case "buffers_checkpoint_bytes":
113 c.mx.buffersCheckpoint = parseInt(value)
114 case "buffers_clean_bytes":
115 c.mx.buffersClean = parseInt(value)
116 case "maxwritten_clean":
117 c.mx.maxwrittenClean = parseInt(value)
118 case "buffers_backend_bytes":
119 c.mx.buffersBackend = parseInt(value)
120 case "buffers_backend_fsync":
121 c.mx.buffersBackendFsync = parseInt(value)
122 case "buffers_alloc_bytes":
123 c.mx.buffersAlloc = parseInt(value)
124 }
125 })
126 }
127
128 func (c *Collector) doQueryUptime() error {
129 q := queryServerUptime()
130
131 var s string
132 if err := c.doQueryRow(q, &s); err != nil {
133 return err
134 }
135
136 c.mx.uptime = parseFloat(s)
137
138 return nil
139 }
140
141 func (c *Collector) doQueryTXIDWraparound() error {
142 q := queryTXIDWraparound()
143
144 return c.doQuery(q, func(column, value string, _ bool) {
145 switch column {
146 case "oldest_current_xid":
147 c.mx.oldestXID = parseInt(value)
148 case "percent_towards_wraparound":
149 c.mx.percentTowardsWraparound = parseInt(value)
150 case "percent_towards_emergency_autovacuum":
151 c.mx.percentTowardsEmergencyAutovacuum = parseInt(value)
152 }
153 })
154 }
155
156 func (c *Collector) doQueryWALWrites() error {
157 q := queryWALWrites(c.pgVersion)
158
159 var v int64
160 if err := c.doQueryRow(q, &v); err != nil {
161 return err
162 }
163
164 c.mx.walWrites = v
165
166 return nil
167 }
168
169 func (c *Collector) doQueryWALFiles() error {
170 q := queryWALFiles(c.pgVersion)
171
172 return c.doQuery(q, func(column, value string, _ bool) {
173 switch column {
174 case "wal_recycled_files":
175 c.mx.walRecycledFiles = parseInt(value)
176 case "wal_written_files":
177 c.mx.walWrittenFiles = parseInt(value)
178 }
179 })
180 }
181
182 func (c *Collector) doQueryWALArchiveFiles() error {
183 q := queryWALArchiveFiles(c.pgVersion)
184
185 return c.doQuery(q, func(column, value string, _ bool) {
186 switch column {
187 case "wal_archive_files_ready_count":
188 c.mx.walArchiveFilesReady = parseInt(value)
189 case "wal_archive_files_done_count":
190 c.mx.walArchiveFilesDone = parseInt(value)
191 }
192 })
193 }
194
195 func (c *Collector) doQueryCatalogRelations() error {
196 q := queryCatalogRelations()
197
198 var kind string
199 var count, size int64
200 return c.doQuery(q, func(column, value string, rowEnd bool) {
201 switch column {
202 case "relkind":
203 kind = value
204 case "count":
205 count = parseInt(value)
206 case "size":
207 size = parseInt(value)
208 }
209 if !rowEnd {
210 return
211 }
212 // https://www.postgresql.org/docs/current/catalog-pg-class.html
213 switch kind {
214 case "r":
215 c.mx.relkindOrdinaryTable = count
216 c.mx.relkindOrdinaryTableSize = size
217 case "i":
218 c.mx.relkindIndex = count
219 c.mx.relkindIndexSize = size
220 case "S":
221 c.mx.relkindSequence = count
222 c.mx.relkindSequenceSize = size
223 case "t":
224 c.mx.relkindTOASTTable = count
225 c.mx.relkindTOASTTableSize = size
226 case "v":
227 c.mx.relkindView = count
228 c.mx.relkindViewSize = size
229 case "m":
230 c.mx.relkindMatView = count
231 c.mx.relkindMatViewSize = size
232 case "c":
233 c.mx.relkindCompositeType = count
234 c.mx.relkindCompositeTypeSize = size
235 case "f":
236 c.mx.relkindForeignTable = count
237 c.mx.relkindForeignTableSize = size
238 case "p":
239 c.mx.relkindPartitionedTable = count
240 c.mx.relkindPartitionedTableSize = size
241 case "I":
242 c.mx.relkindPartitionedIndex = count
243 c.mx.relkindPartitionedIndexSize = size
244 }
245 })
246 }
247
248 func (c *Collector) doQueryAutovacuumWorkers() error {
249 q := queryAutovacuumWorkers()
250
251 return c.doQuery(q, func(column, value string, _ bool) {
252 switch column {
253 case "autovacuum_analyze":
254 c.mx.autovacuumWorkersAnalyze = parseInt(value)
255 case "autovacuum_vacuum_analyze":
256 c.mx.autovacuumWorkersVacuumAnalyze = parseInt(value)
257 case "autovacuum_vacuum":
258 c.mx.autovacuumWorkersVacuum = parseInt(value)
259 case "autovacuum_vacuum_freeze":
260 c.mx.autovacuumWorkersVacuumFreeze = parseInt(value)
261 case "autovacuum_brin_summarize":
262 c.mx.autovacuumWorkersBrinSummarize = parseInt(value)
263 }
264 })
265 }
266
267 func (c *Collector) doQueryXactQueryRunningTime() error {
268 q := queryXactQueryRunningTime()
269
270 var state string
271 return c.doQuery(q, func(column, value string, _ bool) {
272 switch column {
273 case "state":
274 state = value
275 case "xact_running_time":
276 v, _ := strconv.ParseFloat(value, 64)
277 c.mx.xactTimeHist.Observe(v)
278 case "query_running_time":
279 if state == "active" {
280 v, _ := strconv.ParseFloat(value, 64)
281 c.mx.queryTimeHist.Observe(v)
282 }
283 }
284 })
285 }