| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package postgres |
| 4 | |
| 5 | import ( |
| 6 | "fmt" |
| 7 | "strings" |
| 8 | "time" |
| 9 | |
| 10 | "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi" |
| 11 | ) |
| 12 | |
| 13 | const ( |
| 14 | prioConnectionsUtilization = collectorapi.Priority + iota |
| 15 | prioConnectionsUsage |
| 16 | prioConnectionsStateCount |
| 17 | prioDBConnectionsUtilization |
| 18 | prioDBConnectionsCount |
| 19 | |
| 20 | prioTransactionsDuration |
| 21 | prioDBTransactionsRatio |
| 22 | prioDBTransactionsRate |
| 23 | |
| 24 | prioQueriesDuration |
| 25 | |
| 26 | prioDBOpsFetchedRowsRatio |
| 27 | prioDBOpsReadRowsRate |
| 28 | prioDBOpsWriteRowsRate |
| 29 | prioDBTempFilesCreatedRate |
| 30 | prioDBTempFilesIORate |
| 31 | prioTableOpsRowsRate |
| 32 | prioTableOpsRowsHOTRatio |
| 33 | prioTableOpsRowsHOTRate |
| 34 | prioTableScansRate |
| 35 | prioTableScansRowsRate |
| 36 | |
| 37 | prioDBCacheIORatio |
| 38 | prioDBIORate |
| 39 | prioTableCacheIORatio |
| 40 | prioTableIORate |
| 41 | prioTableIndexCacheIORatio |
| 42 | prioTableIndexIORate |
| 43 | prioTableToastCacheIORatio |
| 44 | prioTableToastIORate |
| 45 | prioTableToastIndexCacheIORatio |
| 46 | prioTableToastIndexIORate |
| 47 | |
| 48 | prioDBSize |
| 49 | prioTableTotalSize |
| 50 | prioIndexSize |
| 51 | |
| 52 | prioTableBloatSizePerc |
| 53 | prioTableBloatSize |
| 54 | prioIndexBloatSizePerc |
| 55 | prioIndexBloatSize |
| 56 | |
| 57 | prioLocksUtilization |
| 58 | prioDBLocksHeldCount |
| 59 | prioDBLocksAwaitedCount |
| 60 | prioDBDeadlocksRate |
| 61 | |
| 62 | prioAutovacuumWorkersCount |
| 63 | prioTableAutovacuumSinceTime |
| 64 | prioTableVacuumSinceTime |
| 65 | prioTableAutoAnalyzeSinceTime |
| 66 | prioTableLastAnalyzeAgo |
| 67 | |
| 68 | prioCheckpointsRate |
| 69 | prioCheckpointsTime |
| 70 | prioBGWriterHaltsRate |
| 71 | prioBuffersIORate |
| 72 | prioBuffersBackendFsyncRate |
| 73 | prioBuffersAllocRate |
| 74 | prioTXIDExhaustionTowardsAutovacuumPerc |
| 75 | prioTXIDExhaustionPerc |
| 76 | prioTXIDExhaustionOldestTXIDNum |
| 77 | prioTableRowsDeadRatio |
| 78 | prioTableRowsCount |
| 79 | prioTableNullColumns |
| 80 | prioIndexUsageStatus |
| 81 | |
| 82 | prioReplicationAppWALLagSize |
| 83 | prioReplicationAppWALLagTime |
| 84 | prioReplicationSlotFilesCount |
| 85 | prioDBConflictsRate |
| 86 | prioDBConflictsReasonRate |
| 87 | |
| 88 | prioWALIORate |
| 89 | prioWALFilesCount |
| 90 | prioWALArchivingFilesCount |
| 91 | |
| 92 | prioDatabasesCount |
| 93 | prioCatalogRelationsCount |
| 94 | prioCatalogRelationsSize |
| 95 | |
| 96 | prioUptime |
| 97 | ) |
| 98 | |
| 99 | var baseCharts = collectorapi.Charts{ |
| 100 | serverConnectionsUtilizationChart.Copy(), |
| 101 | serverConnectionsUsageChart.Copy(), |
| 102 | serverConnectionsStateCount.Copy(), |
| 103 | locksUtilization.Copy(), |
| 104 | checkpointsChart.Copy(), |
| 105 | checkpointWriteChart.Copy(), |
| 106 | buffersIORateChart.Copy(), |
| 107 | buffersAllocRateChart.Copy(), |
| 108 | bgWriterHaltsRateChart.Copy(), |
| 109 | buffersBackendFsyncRateChart.Copy(), |
| 110 | walIORateChart.Copy(), |
| 111 | autovacuumWorkersCountChart.Copy(), |
| 112 | txidExhaustionTowardsAutovacuumPercChart.Copy(), |
| 113 | txidExhaustionPercChart.Copy(), |
| 114 | txidExhaustionOldestTXIDNumChart.Copy(), |
| 115 | |
| 116 | catalogRelationSCountChart.Copy(), |
| 117 | catalogRelationsSizeChart.Copy(), |
| 118 | serverUptimeChart.Copy(), |
| 119 | databasesCountChart.Copy(), |
| 120 | } |
| 121 | |
| 122 | var walFilesCharts = collectorapi.Charts{ |
| 123 | walFilesCountChart.Copy(), |
| 124 | walArchivingFilesCountChart.Copy(), |
| 125 | } |
| 126 | |
| 127 | func (c *Collector) addWALFilesCharts() { |
| 128 | charts := walFilesCharts.Copy() |
| 129 | |
| 130 | if err := c.Charts().Add(*charts...); err != nil { |
| 131 | c.Warning(err) |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | var ( |
| 136 | serverConnectionsUtilizationChart = collectorapi.Chart{ |
| 137 | ID: "connections_utilization", |
| 138 | Title: "Connections utilization", |
| 139 | Units: "percentage", |
| 140 | Fam: "connections", |
| 141 | Ctx: "postgres.connections_utilization", |
| 142 | Priority: prioConnectionsUtilization, |
| 143 | Dims: collectorapi.Dims{ |
| 144 | {ID: "server_connections_utilization", Name: "used"}, |
| 145 | }, |
| 146 | } |
| 147 | serverConnectionsUsageChart = collectorapi.Chart{ |
| 148 | ID: "connections_usage", |
| 149 | Title: "Connections usage", |
| 150 | Units: "connections", |
| 151 | Fam: "connections", |
| 152 | Ctx: "postgres.connections_usage", |
| 153 | Priority: prioConnectionsUsage, |
| 154 | Type: collectorapi.Stacked, |
| 155 | Dims: collectorapi.Dims{ |
| 156 | {ID: "server_connections_available", Name: "available"}, |
| 157 | {ID: "server_connections_used", Name: "used"}, |
| 158 | }, |
| 159 | } |
| 160 | serverConnectionsStateCount = collectorapi.Chart{ |
| 161 | ID: "connections_state", |
| 162 | Title: "Connections in each state", |
| 163 | Units: "connections", |
| 164 | Fam: "connections", |
| 165 | Ctx: "postgres.connections_state_count", |
| 166 | Priority: prioConnectionsStateCount, |
| 167 | Type: collectorapi.Stacked, |
| 168 | Dims: collectorapi.Dims{ |
| 169 | {ID: "server_connections_state_active", Name: "active"}, |
| 170 | {ID: "server_connections_state_idle", Name: "idle"}, |
| 171 | {ID: "server_connections_state_idle_in_transaction", Name: "idle_in_transaction"}, |
| 172 | {ID: "server_connections_state_idle_in_transaction_aborted", Name: "idle_in_transaction_aborted"}, |
| 173 | {ID: "server_connections_state_fastpath_function_call", Name: "fastpath_function_call"}, |
| 174 | {ID: "server_connections_state_disabled", Name: "disabled"}, |
| 175 | }, |
| 176 | } |
| 177 | |
| 178 | locksUtilization = collectorapi.Chart{ |
| 179 | ID: "locks_utilization", |
| 180 | Title: "Acquired locks utilization", |
| 181 | Units: "percentage", |
| 182 | Fam: "locks", |
| 183 | Ctx: "postgres.locks_utilization", |
| 184 | Priority: prioLocksUtilization, |
| 185 | Dims: collectorapi.Dims{ |
| 186 | {ID: "locks_utilization", Name: "used"}, |
| 187 | }, |
| 188 | } |
| 189 | |
| 190 | checkpointsChart = collectorapi.Chart{ |
| 191 | ID: "checkpoints_rate", |
| 192 | Title: "Checkpoints", |
| 193 | Units: "checkpoints/s", |
| 194 | Fam: "maintenance", |
| 195 | Ctx: "postgres.checkpoints_rate", |
| 196 | Priority: prioCheckpointsRate, |
| 197 | Type: collectorapi.Stacked, |
| 198 | Dims: collectorapi.Dims{ |
| 199 | {ID: "checkpoints_timed", Name: "scheduled", Algo: collectorapi.Incremental}, |
| 200 | {ID: "checkpoints_req", Name: "requested", Algo: collectorapi.Incremental}, |
| 201 | }, |
| 202 | } |
| 203 | // TODO: should be seconds, also it is units/s when using incremental... |
| 204 | checkpointWriteChart = collectorapi.Chart{ |
| 205 | ID: "checkpoints_time", |
| 206 | Title: "Checkpoint time", |
| 207 | Units: "milliseconds", |
| 208 | Fam: "maintenance", |
| 209 | Ctx: "postgres.checkpoints_time", |
| 210 | Priority: prioCheckpointsTime, |
| 211 | Type: collectorapi.Stacked, |
| 212 | Dims: collectorapi.Dims{ |
| 213 | {ID: "checkpoint_write_time", Name: "write", Algo: collectorapi.Incremental}, |
| 214 | {ID: "checkpoint_sync_time", Name: "sync", Algo: collectorapi.Incremental}, |
| 215 | }, |
| 216 | } |
| 217 | bgWriterHaltsRateChart = collectorapi.Chart{ |
| 218 | ID: "bgwriter_halts_rate", |
| 219 | Title: "Background writer scan halts", |
| 220 | Units: "halts/s", |
| 221 | Fam: "maintenance", |
| 222 | Ctx: "postgres.bgwriter_halts_rate", |
| 223 | Priority: prioBGWriterHaltsRate, |
| 224 | Dims: collectorapi.Dims{ |
| 225 | {ID: "maxwritten_clean", Name: "maxwritten", Algo: collectorapi.Incremental}, |
| 226 | }, |
| 227 | } |
| 228 | |
| 229 | buffersIORateChart = collectorapi.Chart{ |
| 230 | ID: "buffers_io_rate", |
| 231 | Title: "Buffers written rate", |
| 232 | Units: "B/s", |
| 233 | Fam: "maintenance", |
| 234 | Ctx: "postgres.buffers_io_rate", |
| 235 | Priority: prioBuffersIORate, |
| 236 | Type: collectorapi.Area, |
| 237 | Dims: collectorapi.Dims{ |
| 238 | {ID: "buffers_checkpoint", Name: "checkpoint", Algo: collectorapi.Incremental}, |
| 239 | {ID: "buffers_backend", Name: "backend", Algo: collectorapi.Incremental}, |
| 240 | {ID: "buffers_clean", Name: "bgwriter", Algo: collectorapi.Incremental}, |
| 241 | }, |
| 242 | } |
| 243 | buffersBackendFsyncRateChart = collectorapi.Chart{ |
| 244 | ID: "buffers_backend_fsync_rate", |
| 245 | Title: "Backend fsync calls", |
| 246 | Units: "calls/s", |
| 247 | Fam: "maintenance", |
| 248 | Ctx: "postgres.buffers_backend_fsync_rate", |
| 249 | Priority: prioBuffersBackendFsyncRate, |
| 250 | Dims: collectorapi.Dims{ |
| 251 | {ID: "buffers_backend_fsync", Name: "fsync", Algo: collectorapi.Incremental}, |
| 252 | }, |
| 253 | } |
| 254 | buffersAllocRateChart = collectorapi.Chart{ |
| 255 | ID: "buffers_alloc_rate", |
| 256 | Title: "Buffers allocated", |
| 257 | Units: "B/s", |
| 258 | Fam: "maintenance", |
| 259 | Ctx: "postgres.buffers_allocated_rate", |
| 260 | Priority: prioBuffersAllocRate, |
| 261 | Dims: collectorapi.Dims{ |
| 262 | {ID: "buffers_alloc", Name: "allocated", Algo: collectorapi.Incremental}, |
| 263 | }, |
| 264 | } |
| 265 | |
| 266 | walIORateChart = collectorapi.Chart{ |
| 267 | ID: "wal_io_rate", |
| 268 | Title: "Write-Ahead Log writes", |
| 269 | Units: "B/s", |
| 270 | Fam: "wal", |
| 271 | Ctx: "postgres.wal_io_rate", |
| 272 | Priority: prioWALIORate, |
| 273 | Dims: collectorapi.Dims{ |
| 274 | {ID: "wal_writes", Name: "written", Algo: collectorapi.Incremental}, |
| 275 | }, |
| 276 | } |
| 277 | walFilesCountChart = collectorapi.Chart{ |
| 278 | ID: "wal_files_count", |
| 279 | Title: "Write-Ahead Log files", |
| 280 | Units: "files", |
| 281 | Fam: "wal", |
| 282 | Ctx: "postgres.wal_files_count", |
| 283 | Priority: prioWALFilesCount, |
| 284 | Type: collectorapi.Stacked, |
| 285 | Dims: collectorapi.Dims{ |
| 286 | {ID: "wal_written_files", Name: "written"}, |
| 287 | {ID: "wal_recycled_files", Name: "recycled"}, |
| 288 | }, |
| 289 | } |
| 290 | |
| 291 | walArchivingFilesCountChart = collectorapi.Chart{ |
| 292 | ID: "wal_archiving_files_count", |
| 293 | Title: "Write-Ahead Log archived files", |
| 294 | Units: "files/s", |
| 295 | Fam: "wal", |
| 296 | Ctx: "postgres.wal_archiving_files_count", |
| 297 | Priority: prioWALArchivingFilesCount, |
| 298 | Type: collectorapi.Stacked, |
| 299 | Dims: collectorapi.Dims{ |
| 300 | {ID: "wal_archive_files_ready_count", Name: "ready"}, |
| 301 | {ID: "wal_archive_files_done_count", Name: "done"}, |
| 302 | }, |
| 303 | } |
| 304 | |
| 305 | autovacuumWorkersCountChart = collectorapi.Chart{ |
| 306 | ID: "autovacuum_workers_count", |
| 307 | Title: "Autovacuum workers", |
| 308 | Units: "workers", |
| 309 | Fam: "vacuum and analyze", |
| 310 | Ctx: "postgres.autovacuum_workers_count", |
| 311 | Priority: prioAutovacuumWorkersCount, |
| 312 | Dims: collectorapi.Dims{ |
| 313 | {ID: "autovacuum_analyze", Name: "analyze"}, |
| 314 | {ID: "autovacuum_vacuum_analyze", Name: "vacuum_analyze"}, |
| 315 | {ID: "autovacuum_vacuum", Name: "vacuum"}, |
| 316 | {ID: "autovacuum_vacuum_freeze", Name: "vacuum_freeze"}, |
| 317 | {ID: "autovacuum_brin_summarize", Name: "brin_summarize"}, |
| 318 | }, |
| 319 | } |
| 320 | |
| 321 | txidExhaustionTowardsAutovacuumPercChart = collectorapi.Chart{ |
| 322 | ID: "txid_exhaustion_towards_autovacuum_perc", |
| 323 | Title: "Percent towards emergency autovacuum", |
| 324 | Units: "percentage", |
| 325 | Fam: "maintenance", |
| 326 | Ctx: "postgres.txid_exhaustion_towards_autovacuum_perc", |
| 327 | Priority: prioTXIDExhaustionTowardsAutovacuumPerc, |
| 328 | Dims: collectorapi.Dims{ |
| 329 | {ID: "percent_towards_emergency_autovacuum", Name: "emergency_autovacuum"}, |
| 330 | }, |
| 331 | } |
| 332 | txidExhaustionPercChart = collectorapi.Chart{ |
| 333 | ID: "txid_exhaustion_perc", |
| 334 | Title: "Percent towards transaction ID wraparound", |
| 335 | Units: "percentage", |
| 336 | Fam: "maintenance", |
| 337 | Ctx: "postgres.txid_exhaustion_perc", |
| 338 | Priority: prioTXIDExhaustionPerc, |
| 339 | Dims: collectorapi.Dims{ |
| 340 | {ID: "percent_towards_wraparound", Name: "txid_exhaustion"}, |
| 341 | }, |
| 342 | } |
| 343 | txidExhaustionOldestTXIDNumChart = collectorapi.Chart{ |
| 344 | ID: "txid_exhaustion_oldest_txid_num", |
| 345 | Title: "Oldest transaction XID", |
| 346 | Units: "xid", |
| 347 | Fam: "maintenance", |
| 348 | Ctx: "postgres.txid_exhaustion_oldest_txid_num", |
| 349 | Priority: prioTXIDExhaustionOldestTXIDNum, |
| 350 | Dims: collectorapi.Dims{ |
| 351 | {ID: "oldest_current_xid", Name: "xid"}, |
| 352 | }, |
| 353 | } |
| 354 | |
| 355 | catalogRelationSCountChart = collectorapi.Chart{ |
| 356 | ID: "catalog_relations_count", |
| 357 | Title: "Relation count", |
| 358 | Units: "relations", |
| 359 | Fam: "catalog", |
| 360 | Ctx: "postgres.catalog_relations_count", |
| 361 | Priority: prioCatalogRelationsCount, |
| 362 | Type: collectorapi.Stacked, |
| 363 | Dims: collectorapi.Dims{ |
| 364 | {ID: "catalog_relkind_r_count", Name: "ordinary_table"}, |
| 365 | {ID: "catalog_relkind_i_count", Name: "index"}, |
| 366 | {ID: "catalog_relkind_S_count", Name: "sequence"}, |
| 367 | {ID: "catalog_relkind_t_count", Name: "toast_table"}, |
| 368 | {ID: "catalog_relkind_v_count", Name: "view"}, |
| 369 | {ID: "catalog_relkind_m_count", Name: "materialized_view"}, |
| 370 | {ID: "catalog_relkind_c_count", Name: "composite_type"}, |
| 371 | {ID: "catalog_relkind_f_count", Name: "foreign_table"}, |
| 372 | {ID: "catalog_relkind_p_count", Name: "partitioned_table"}, |
| 373 | {ID: "catalog_relkind_I_count", Name: "partitioned_index"}, |
| 374 | }, |
| 375 | } |
| 376 | catalogRelationsSizeChart = collectorapi.Chart{ |
| 377 | ID: "catalog_relations_size", |
| 378 | Title: "Relation size", |
| 379 | Units: "B", |
| 380 | Fam: "catalog", |
| 381 | Ctx: "postgres.catalog_relations_size", |
| 382 | Priority: prioCatalogRelationsSize, |
| 383 | Type: collectorapi.Stacked, |
| 384 | Dims: collectorapi.Dims{ |
| 385 | {ID: "catalog_relkind_r_size", Name: "ordinary_table"}, |
| 386 | {ID: "catalog_relkind_i_size", Name: "index"}, |
| 387 | {ID: "catalog_relkind_S_size", Name: "sequence"}, |
| 388 | {ID: "catalog_relkind_t_size", Name: "toast_table"}, |
| 389 | {ID: "catalog_relkind_v_size", Name: "view"}, |
| 390 | {ID: "catalog_relkind_m_size", Name: "materialized_view"}, |
| 391 | {ID: "catalog_relkind_c_size", Name: "composite_type"}, |
| 392 | {ID: "catalog_relkind_f_size", Name: "foreign_table"}, |
| 393 | {ID: "catalog_relkind_p_size", Name: "partitioned_table"}, |
| 394 | {ID: "catalog_relkind_I_size", Name: "partitioned_index"}, |
| 395 | }, |
| 396 | } |
| 397 | |
| 398 | serverUptimeChart = collectorapi.Chart{ |
| 399 | ID: "server_uptime", |
| 400 | Title: "Uptime", |
| 401 | Units: "seconds", |
| 402 | Fam: "uptime", |
| 403 | Ctx: "postgres.uptime", |
| 404 | Priority: prioUptime, |
| 405 | Dims: collectorapi.Dims{ |
| 406 | {ID: "server_uptime", Name: "uptime"}, |
| 407 | }, |
| 408 | } |
| 409 | |
| 410 | databasesCountChart = collectorapi.Chart{ |
| 411 | ID: "databases_count", |
| 412 | Title: "Number of databases", |
| 413 | Units: "databases", |
| 414 | Fam: "catalog", |
| 415 | Ctx: "postgres.databases_count", |
| 416 | Priority: prioDatabasesCount, |
| 417 | Dims: collectorapi.Dims{ |
| 418 | {ID: "databases_count", Name: "databases"}, |
| 419 | }, |
| 420 | } |
| 421 | |
| 422 | transactionsDurationChartTmpl = collectorapi.Chart{ |
| 423 | ID: "transactions_duration", |
| 424 | Title: "Observed transactions time", |
| 425 | Units: "transactions/s", |
| 426 | Fam: "transactions", |
| 427 | Ctx: "postgres.transactions_duration", |
| 428 | Priority: prioTransactionsDuration, |
| 429 | Type: collectorapi.Stacked, |
| 430 | } |
| 431 | queriesDurationChartTmpl = collectorapi.Chart{ |
| 432 | ID: "queries_duration", |
| 433 | Title: "Observed active queries time", |
| 434 | Units: "queries/s", |
| 435 | Fam: "queries", |
| 436 | Ctx: "postgres.queries_duration", |
| 437 | Priority: prioQueriesDuration, |
| 438 | Type: collectorapi.Stacked, |
| 439 | } |
| 440 | ) |
| 441 | |
| 442 | func newRunningTimeHistogramChart(tmpl collectorapi.Chart, prefix string, buckets []float64) (*collectorapi.Chart, error) { |
| 443 | chart := tmpl.Copy() |
| 444 | |
| 445 | for i, v := range buckets { |
| 446 | dim := &collectorapi.Dim{ |
| 447 | ID: fmt.Sprintf("%s_hist_bucket_%d", prefix, i+1), |
| 448 | Name: time.Duration(v * float64(time.Second)).String(), |
| 449 | Algo: collectorapi.Incremental, |
| 450 | } |
| 451 | if err := chart.AddDim(dim); err != nil { |
| 452 | return nil, err |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | dim := &collectorapi.Dim{ |
| 457 | ID: fmt.Sprintf("%s_hist_bucket_inf", prefix), |
| 458 | Name: "+Inf", |
| 459 | Algo: collectorapi.Incremental, |
| 460 | } |
| 461 | if err := chart.AddDim(dim); err != nil { |
| 462 | return nil, err |
| 463 | } |
| 464 | |
| 465 | return chart, nil |
| 466 | } |
| 467 | |
| 468 | func (c *Collector) addTransactionsRunTimeHistogramChart() { |
| 469 | chart, err := newRunningTimeHistogramChart( |
| 470 | transactionsDurationChartTmpl, |
| 471 | "transaction_running_time", |
| 472 | c.XactTimeHistogram, |
| 473 | ) |
| 474 | if err != nil { |
| 475 | c.Warning(err) |
| 476 | return |
| 477 | } |
| 478 | if err := c.Charts().Add(chart); err != nil { |
| 479 | c.Warning(err) |
| 480 | } |
| 481 | } |
| 482 | |
| 483 | func (c *Collector) addQueriesRunTimeHistogramChart() { |
| 484 | chart, err := newRunningTimeHistogramChart( |
| 485 | queriesDurationChartTmpl, |
| 486 | "query_running_time", |
| 487 | c.QueryTimeHistogram, |
| 488 | ) |
| 489 | if err != nil { |
| 490 | c.Warning(err) |
| 491 | return |
| 492 | } |
| 493 | if err := c.Charts().Add(chart); err != nil { |
| 494 | c.Warning(err) |
| 495 | } |
| 496 | } |
| 497 | |
| 498 | var ( |
| 499 | replicationStandbyAppCharts = collectorapi.Charts{ |
| 500 | replicationAppWALLagSizeChartTmpl.Copy(), |
| 501 | replicationAppWALLagTimeChartTmpl.Copy(), |
| 502 | } |
| 503 | replicationAppWALLagSizeChartTmpl = collectorapi.Chart{ |
| 504 | ID: "replication_app_%s_wal_lag_size", |
| 505 | Title: "Standby application WAL lag size", |
| 506 | Units: "B", |
| 507 | Fam: "replication", |
| 508 | Ctx: "postgres.replication_app_wal_lag_size", |
| 509 | Priority: prioReplicationAppWALLagSize, |
| 510 | Dims: collectorapi.Dims{ |
| 511 | {ID: "repl_standby_app_%s_wal_sent_lag_size", Name: "sent_lag"}, |
| 512 | {ID: "repl_standby_app_%s_wal_write_lag_size", Name: "write_lag"}, |
| 513 | {ID: "repl_standby_app_%s_wal_flush_lag_size", Name: "flush_lag"}, |
| 514 | {ID: "repl_standby_app_%s_wal_replay_lag_size", Name: "replay_lag"}, |
| 515 | }, |
| 516 | } |
| 517 | replicationAppWALLagTimeChartTmpl = collectorapi.Chart{ |
| 518 | ID: "replication_app_%s_wal_lag_time", |
| 519 | Title: "Standby application WAL lag time", |
| 520 | Units: "seconds", |
| 521 | Fam: "replication", |
| 522 | Ctx: "postgres.replication_app_wal_lag_time", |
| 523 | Priority: prioReplicationAppWALLagTime, |
| 524 | Dims: collectorapi.Dims{ |
| 525 | {ID: "repl_standby_app_%s_wal_write_lag_time", Name: "write_lag"}, |
| 526 | {ID: "repl_standby_app_%s_wal_flush_lag_time", Name: "flush_lag"}, |
| 527 | {ID: "repl_standby_app_%s_wal_replay_lag_time", Name: "replay_lag"}, |
| 528 | }, |
| 529 | } |
| 530 | ) |
| 531 | |
| 532 | func newReplicationStandbyAppCharts(app string) *collectorapi.Charts { |
| 533 | charts := replicationStandbyAppCharts.Copy() |
| 534 | for _, c := range *charts { |
| 535 | c.ID = fmt.Sprintf(c.ID, app) |
| 536 | c.Labels = []collectorapi.Label{ |
| 537 | {Key: "application", Value: app}, |
| 538 | } |
| 539 | for _, d := range c.Dims { |
| 540 | d.ID = fmt.Sprintf(d.ID, app) |
| 541 | } |
| 542 | } |
| 543 | return charts |
| 544 | } |
| 545 | |
| 546 | func (c *Collector) addNewReplicationStandbyAppCharts(app string) { |
| 547 | charts := newReplicationStandbyAppCharts(app) |
| 548 | if err := c.Charts().Add(*charts...); err != nil { |
| 549 | c.Warning(err) |
| 550 | } |
| 551 | } |
| 552 | |
| 553 | func (c *Collector) removeReplicationStandbyAppCharts(app string) { |
| 554 | prefix := fmt.Sprintf("replication_standby_app_%s_", app) |
| 555 | for _, c := range *c.Charts() { |
| 556 | if strings.HasPrefix(c.ID, prefix) { |
| 557 | c.MarkRemove() |
| 558 | c.MarkNotCreated() |
| 559 | } |
| 560 | } |
| 561 | } |
| 562 | |
| 563 | var ( |
| 564 | replicationSlotCharts = collectorapi.Charts{ |
| 565 | replicationSlotFilesCountChartTmpl.Copy(), |
| 566 | } |
| 567 | replicationSlotFilesCountChartTmpl = collectorapi.Chart{ |
| 568 | ID: "replication_slot_%s_files_count", |
| 569 | Title: "Replication slot files", |
| 570 | Units: "files", |
| 571 | Fam: "replication", |
| 572 | Ctx: "postgres.replication_slot_files_count", |
| 573 | Priority: prioReplicationSlotFilesCount, |
| 574 | Dims: collectorapi.Dims{ |
| 575 | {ID: "repl_slot_%s_replslot_wal_keep", Name: "wal_keep"}, |
| 576 | {ID: "repl_slot_%s_replslot_files", Name: "pg_replslot_files"}, |
| 577 | }, |
| 578 | } |
| 579 | ) |
| 580 | |
| 581 | func newReplicationSlotCharts(slot string) *collectorapi.Charts { |
| 582 | charts := replicationSlotCharts.Copy() |
| 583 | for _, c := range *charts { |
| 584 | c.ID = fmt.Sprintf(c.ID, slot) |
| 585 | c.Labels = []collectorapi.Label{ |
| 586 | {Key: "slot", Value: slot}, |
| 587 | } |
| 588 | for _, d := range c.Dims { |
| 589 | d.ID = fmt.Sprintf(d.ID, slot) |
| 590 | } |
| 591 | } |
| 592 | return charts |
| 593 | } |
| 594 | |
| 595 | func (c *Collector) addNewReplicationSlotCharts(slot string) { |
| 596 | charts := newReplicationSlotCharts(slot) |
| 597 | if err := c.Charts().Add(*charts...); err != nil { |
| 598 | c.Warning(err) |
| 599 | } |
| 600 | } |
| 601 | |
| 602 | func (c *Collector) removeReplicationSlotCharts(slot string) { |
| 603 | prefix := fmt.Sprintf("replication_slot_%s_", slot) |
| 604 | for _, c := range *c.Charts() { |
| 605 | if strings.HasPrefix(c.ID, prefix) { |
| 606 | c.MarkRemove() |
| 607 | c.MarkNotCreated() |
| 608 | } |
| 609 | } |
| 610 | } |
| 611 | |
| 612 | var ( |
| 613 | dbChartsTmpl = collectorapi.Charts{ |
| 614 | dbTransactionsRatioChartTmpl.Copy(), |
| 615 | dbTransactionsRateChartTmpl.Copy(), |
| 616 | dbConnectionsUtilizationChartTmpl.Copy(), |
| 617 | dbConnectionsCountChartTmpl.Copy(), |
| 618 | dbCacheIORatioChartTmpl.Copy(), |
| 619 | dbIORateChartTmpl.Copy(), |
| 620 | dbOpsFetchedRowsRatioChartTmpl.Copy(), |
| 621 | dbOpsReadRowsRateChartTmpl.Copy(), |
| 622 | dbOpsWriteRowsRateChartTmpl.Copy(), |
| 623 | dbDeadlocksRateChartTmpl.Copy(), |
| 624 | dbLocksHeldCountChartTmpl.Copy(), |
| 625 | dbLocksAwaitedCountChartTmpl.Copy(), |
| 626 | dbTempFilesCreatedRateChartTmpl.Copy(), |
| 627 | dbTempFilesIORateChartTmpl.Copy(), |
| 628 | dbSizeChartTmpl.Copy(), |
| 629 | } |
| 630 | dbTransactionsRatioChartTmpl = collectorapi.Chart{ |
| 631 | ID: "db_%s_transactions_ratio", |
| 632 | Title: "Database transactions ratio", |
| 633 | Units: "percentage", |
| 634 | Fam: "transactions", |
| 635 | Ctx: "postgres.db_transactions_ratio", |
| 636 | Priority: prioDBTransactionsRatio, |
| 637 | Type: collectorapi.Stacked, |
| 638 | Dims: collectorapi.Dims{ |
| 639 | {ID: "db_%s_xact_commit", Name: "committed", Algo: collectorapi.PercentOfIncremental}, |
| 640 | {ID: "db_%s_xact_rollback", Name: "rollback", Algo: collectorapi.PercentOfIncremental}, |
| 641 | }, |
| 642 | } |
| 643 | dbTransactionsRateChartTmpl = collectorapi.Chart{ |
| 644 | ID: "db_%s_transactions_rate", |
| 645 | Title: "Database transactions", |
| 646 | Units: "transactions/s", |
| 647 | Fam: "transactions", |
| 648 | Ctx: "postgres.db_transactions_rate", |
| 649 | Priority: prioDBTransactionsRate, |
| 650 | Dims: collectorapi.Dims{ |
| 651 | {ID: "db_%s_xact_commit", Name: "committed", Algo: collectorapi.Incremental}, |
| 652 | {ID: "db_%s_xact_rollback", Name: "rollback", Algo: collectorapi.Incremental}, |
| 653 | }, |
| 654 | } |
| 655 | dbConnectionsUtilizationChartTmpl = collectorapi.Chart{ |
| 656 | ID: "db_%s_connections_utilization", |
| 657 | Title: "Database connections utilization", |
| 658 | Units: "percentage", |
| 659 | Fam: "connections", |
| 660 | Ctx: "postgres.db_connections_utilization", |
| 661 | Priority: prioDBConnectionsUtilization, |
| 662 | Dims: collectorapi.Dims{ |
| 663 | {ID: "db_%s_numbackends_utilization", Name: "used"}, |
| 664 | }, |
| 665 | } |
| 666 | dbConnectionsCountChartTmpl = collectorapi.Chart{ |
| 667 | ID: "db_%s_connections", |
| 668 | Title: "Database connections", |
| 669 | Units: "connections", |
| 670 | Fam: "connections", |
| 671 | Ctx: "postgres.db_connections_count", |
| 672 | Priority: prioDBConnectionsCount, |
| 673 | Dims: collectorapi.Dims{ |
| 674 | {ID: "db_%s_numbackends", Name: "connections"}, |
| 675 | }, |
| 676 | } |
| 677 | dbCacheIORatioChartTmpl = collectorapi.Chart{ |
| 678 | ID: "db_%s_cache_io_ratio", |
| 679 | Title: "Database buffer cache miss ratio", |
| 680 | Units: "percentage", |
| 681 | Fam: "cache", |
| 682 | Ctx: "postgres.db_cache_io_ratio", |
| 683 | Priority: prioDBCacheIORatio, |
| 684 | Dims: collectorapi.Dims{ |
| 685 | {ID: "db_%s_blks_read_perc", Name: "miss"}, |
| 686 | }, |
| 687 | } |
| 688 | dbIORateChartTmpl = collectorapi.Chart{ |
| 689 | ID: "db_%s_io_rate", |
| 690 | Title: "Database reads", |
| 691 | Units: "B/s", |
| 692 | Fam: "cache", |
| 693 | Ctx: "postgres.db_io_rate", |
| 694 | Priority: prioDBIORate, |
| 695 | Type: collectorapi.Area, |
| 696 | Dims: collectorapi.Dims{ |
| 697 | {ID: "db_%s_blks_hit", Name: "memory", Algo: collectorapi.Incremental}, |
| 698 | {ID: "db_%s_blks_read", Name: "disk", Algo: collectorapi.Incremental}, |
| 699 | }, |
| 700 | } |
| 701 | dbOpsFetchedRowsRatioChartTmpl = collectorapi.Chart{ |
| 702 | ID: "db_%s_db_ops_fetched_rows_ratio", |
| 703 | Title: "Database rows fetched ratio", |
| 704 | Units: "percentage", |
| 705 | Fam: "throughput", |
| 706 | Ctx: "postgres.db_ops_fetched_rows_ratio", |
| 707 | Priority: prioDBOpsFetchedRowsRatio, |
| 708 | Dims: collectorapi.Dims{ |
| 709 | {ID: "db_%s_tup_fetched_perc", Name: "fetched"}, |
| 710 | }, |
| 711 | } |
| 712 | dbOpsReadRowsRateChartTmpl = collectorapi.Chart{ |
| 713 | ID: "db_%s_ops_read_rows_rate", |
| 714 | Title: "Database rows read", |
| 715 | Units: "rows/s", |
| 716 | Fam: "throughput", |
| 717 | Ctx: "postgres.db_ops_read_rows_rate", |
| 718 | Priority: prioDBOpsReadRowsRate, |
| 719 | Dims: collectorapi.Dims{ |
| 720 | {ID: "db_%s_tup_returned", Name: "returned", Algo: collectorapi.Incremental}, |
| 721 | {ID: "db_%s_tup_fetched", Name: "fetched", Algo: collectorapi.Incremental}, |
| 722 | }, |
| 723 | } |
| 724 | dbOpsWriteRowsRateChartTmpl = collectorapi.Chart{ |
| 725 | ID: "db_%s_ops_write_rows_rate", |
| 726 | Title: "Database rows written", |
| 727 | Units: "rows/s", |
| 728 | Fam: "throughput", |
| 729 | Ctx: "postgres.db_ops_write_rows_rate", |
| 730 | Priority: prioDBOpsWriteRowsRate, |
| 731 | Dims: collectorapi.Dims{ |
| 732 | {ID: "db_%s_tup_inserted", Name: "inserted", Algo: collectorapi.Incremental}, |
| 733 | {ID: "db_%s_tup_deleted", Name: "deleted", Algo: collectorapi.Incremental}, |
| 734 | {ID: "db_%s_tup_updated", Name: "updated", Algo: collectorapi.Incremental}, |
| 735 | }, |
| 736 | } |
| 737 | dbConflictsRateChartTmpl = collectorapi.Chart{ |
| 738 | ID: "db_%s_conflicts_rate", |
| 739 | Title: "Database canceled queries", |
| 740 | Units: "queries/s", |
| 741 | Fam: "replication", |
| 742 | Ctx: "postgres.db_conflicts_rate", |
| 743 | Priority: prioDBConflictsRate, |
| 744 | Dims: collectorapi.Dims{ |
| 745 | {ID: "db_%s_conflicts", Name: "conflicts", Algo: collectorapi.Incremental}, |
| 746 | }, |
| 747 | } |
| 748 | dbConflictsReasonRateChartTmpl = collectorapi.Chart{ |
| 749 | ID: "db_%s_conflicts_reason_rate", |
| 750 | Title: "Database canceled queries by reason", |
| 751 | Units: "queries/s", |
| 752 | Fam: "replication", |
| 753 | Ctx: "postgres.db_conflicts_reason_rate", |
| 754 | Priority: prioDBConflictsReasonRate, |
| 755 | Dims: collectorapi.Dims{ |
| 756 | {ID: "db_%s_confl_tablespace", Name: "tablespace", Algo: collectorapi.Incremental}, |
| 757 | {ID: "db_%s_confl_lock", Name: "lock", Algo: collectorapi.Incremental}, |
| 758 | {ID: "db_%s_confl_snapshot", Name: "snapshot", Algo: collectorapi.Incremental}, |
| 759 | {ID: "db_%s_confl_bufferpin", Name: "bufferpin", Algo: collectorapi.Incremental}, |
| 760 | {ID: "db_%s_confl_deadlock", Name: "deadlock", Algo: collectorapi.Incremental}, |
| 761 | }, |
| 762 | } |
| 763 | dbDeadlocksRateChartTmpl = collectorapi.Chart{ |
| 764 | ID: "db_%s_deadlocks_rate", |
| 765 | Title: "Database deadlocks", |
| 766 | Units: "deadlocks/s", |
| 767 | Fam: "locks", |
| 768 | Ctx: "postgres.db_deadlocks_rate", |
| 769 | Priority: prioDBDeadlocksRate, |
| 770 | Dims: collectorapi.Dims{ |
| 771 | {ID: "db_%s_deadlocks", Name: "deadlocks", Algo: collectorapi.Incremental}, |
| 772 | }, |
| 773 | } |
| 774 | dbLocksHeldCountChartTmpl = collectorapi.Chart{ |
| 775 | ID: "db_%s_locks_held", |
| 776 | Title: "Database locks held", |
| 777 | Units: "locks", |
| 778 | Fam: "locks", |
| 779 | Ctx: "postgres.db_locks_held_count", |
| 780 | Priority: prioDBLocksHeldCount, |
| 781 | Type: collectorapi.Stacked, |
| 782 | Dims: collectorapi.Dims{ |
| 783 | {ID: "db_%s_lock_mode_AccessShareLock_held", Name: "access_share"}, |
| 784 | {ID: "db_%s_lock_mode_RowShareLock_held", Name: "row_share"}, |
| 785 | {ID: "db_%s_lock_mode_RowExclusiveLock_held", Name: "row_exclusive"}, |
| 786 | {ID: "db_%s_lock_mode_ShareUpdateExclusiveLock_held", Name: "share_update"}, |
| 787 | {ID: "db_%s_lock_mode_ShareLock_held", Name: "share"}, |
| 788 | {ID: "db_%s_lock_mode_ShareRowExclusiveLock_held", Name: "share_row_exclusive"}, |
| 789 | {ID: "db_%s_lock_mode_ExclusiveLock_held", Name: "exclusive"}, |
| 790 | {ID: "db_%s_lock_mode_AccessExclusiveLock_held", Name: "access_exclusive"}, |
| 791 | }, |
| 792 | } |
| 793 | dbLocksAwaitedCountChartTmpl = collectorapi.Chart{ |
| 794 | ID: "db_%s_locks_awaited_count", |
| 795 | Title: "Database locks awaited", |
| 796 | Units: "locks", |
| 797 | Fam: "locks", |
| 798 | Ctx: "postgres.db_locks_awaited_count", |
| 799 | Priority: prioDBLocksAwaitedCount, |
| 800 | Type: collectorapi.Stacked, |
| 801 | Dims: collectorapi.Dims{ |
| 802 | {ID: "db_%s_lock_mode_AccessShareLock_awaited", Name: "access_share"}, |
| 803 | {ID: "db_%s_lock_mode_RowShareLock_awaited", Name: "row_share"}, |
| 804 | {ID: "db_%s_lock_mode_RowExclusiveLock_awaited", Name: "row_exclusive"}, |
| 805 | {ID: "db_%s_lock_mode_ShareUpdateExclusiveLock_awaited", Name: "share_update"}, |
| 806 | {ID: "db_%s_lock_mode_ShareLock_awaited", Name: "share"}, |
| 807 | {ID: "db_%s_lock_mode_ShareRowExclusiveLock_awaited", Name: "share_row_exclusive"}, |
| 808 | {ID: "db_%s_lock_mode_ExclusiveLock_awaited", Name: "exclusive"}, |
| 809 | {ID: "db_%s_lock_mode_AccessExclusiveLock_awaited", Name: "access_exclusive"}, |
| 810 | }, |
| 811 | } |
| 812 | dbTempFilesCreatedRateChartTmpl = collectorapi.Chart{ |
| 813 | ID: "db_%s_temp_files_files_created_rate", |
| 814 | Title: "Database created temporary files", |
| 815 | Units: "files/s", |
| 816 | Fam: "throughput", |
| 817 | Ctx: "postgres.db_temp_files_created_rate", |
| 818 | Priority: prioDBTempFilesCreatedRate, |
| 819 | Dims: collectorapi.Dims{ |
| 820 | {ID: "db_%s_temp_files", Name: "created", Algo: collectorapi.Incremental}, |
| 821 | }, |
| 822 | } |
| 823 | dbTempFilesIORateChartTmpl = collectorapi.Chart{ |
| 824 | ID: "db_%s_temp_files_io_rate", |
| 825 | Title: "Database temporary files data written to disk", |
| 826 | Units: "B/s", |
| 827 | Fam: "throughput", |
| 828 | Ctx: "postgres.db_temp_files_io_rate", |
| 829 | Priority: prioDBTempFilesIORate, |
| 830 | Dims: collectorapi.Dims{ |
| 831 | {ID: "db_%s_temp_bytes", Name: "written", Algo: collectorapi.Incremental}, |
| 832 | }, |
| 833 | } |
| 834 | dbSizeChartTmpl = collectorapi.Chart{ |
| 835 | ID: "db_%s_size", |
| 836 | Title: "Database size", |
| 837 | Units: "B", |
| 838 | Fam: "size", |
| 839 | Ctx: "postgres.db_size", |
| 840 | Priority: prioDBSize, |
| 841 | Dims: collectorapi.Dims{ |
| 842 | {ID: "db_%s_size", Name: "size"}, |
| 843 | }, |
| 844 | } |
| 845 | ) |
| 846 | |
| 847 | func (c *Collector) addDBConflictsCharts(db *dbMetrics) { |
| 848 | tmpl := collectorapi.Charts{ |
| 849 | dbConflictsRateChartTmpl.Copy(), |
| 850 | dbConflictsReasonRateChartTmpl.Copy(), |
| 851 | } |
| 852 | charts := newDatabaseCharts(tmpl.Copy(), db) |
| 853 | |
| 854 | if err := c.Charts().Add(*charts...); err != nil { |
| 855 | c.Warning(err) |
| 856 | } |
| 857 | } |
| 858 | |
| 859 | func newDatabaseCharts(tmpl *collectorapi.Charts, db *dbMetrics) *collectorapi.Charts { |
| 860 | charts := tmpl.Copy() |
| 861 | for _, c := range *charts { |
| 862 | c.ID = fmt.Sprintf(c.ID, db.name) |
| 863 | c.Labels = []collectorapi.Label{ |
| 864 | {Key: "database", Value: db.name}, |
| 865 | } |
| 866 | for _, d := range c.Dims { |
| 867 | d.ID = fmt.Sprintf(d.ID, db.name) |
| 868 | } |
| 869 | } |
| 870 | return charts |
| 871 | } |
| 872 | |
| 873 | func (c *Collector) addNewDatabaseCharts(db *dbMetrics) { |
| 874 | charts := newDatabaseCharts(dbChartsTmpl.Copy(), db) |
| 875 | |
| 876 | if db.size == nil { |
| 877 | _ = charts.Remove(fmt.Sprintf(dbSizeChartTmpl.ID, db.name)) |
| 878 | } |
| 879 | |
| 880 | if err := c.Charts().Add(*charts...); err != nil { |
| 881 | c.Warning(err) |
| 882 | } |
| 883 | } |
| 884 | |
| 885 | func (c *Collector) removeDatabaseCharts(db *dbMetrics) { |
| 886 | prefix := fmt.Sprintf("db_%s_", db.name) |
| 887 | for _, c := range *c.Charts() { |
| 888 | if strings.HasPrefix(c.ID, prefix) { |
| 889 | c.MarkRemove() |
| 890 | c.MarkNotCreated() |
| 891 | } |
| 892 | } |
| 893 | } |
| 894 | |
| 895 | var ( |
| 896 | tableChartsTmpl = collectorapi.Charts{ |
| 897 | tableRowsCountChartTmpl.Copy(), |
| 898 | tableDeadRowsDeadRatioChartTmpl.Copy(), |
| 899 | tableOpsRowsRateChartTmpl.Copy(), |
| 900 | tableOpsRowsHOTRatioChartTmpl.Copy(), |
| 901 | tableOpsRowsHOTRateChartTmpl.Copy(), |
| 902 | tableScansRateChartTmpl.Copy(), |
| 903 | tableScansRowsRateChartTmpl.Copy(), |
| 904 | tableNullColumnsCountChartTmpl.Copy(), |
| 905 | tableTotalSizeChartTmpl.Copy(), |
| 906 | tableBloatSizePercChartTmpl.Copy(), |
| 907 | tableBloatSizeChartTmpl.Copy(), |
| 908 | } |
| 909 | |
| 910 | tableDeadRowsDeadRatioChartTmpl = collectorapi.Chart{ |
| 911 | ID: "table_%s_db_%s_schema_%s_rows_dead_ratio", |
| 912 | Title: "Table dead rows", |
| 913 | Units: "%", |
| 914 | Fam: "maintenance", |
| 915 | Ctx: "postgres.table_rows_dead_ratio", |
| 916 | Priority: prioTableRowsDeadRatio, |
| 917 | Dims: collectorapi.Dims{ |
| 918 | {ID: "table_%s_db_%s_schema_%s_n_dead_tup_perc", Name: "dead"}, |
| 919 | }, |
| 920 | } |
| 921 | tableRowsCountChartTmpl = collectorapi.Chart{ |
| 922 | ID: "table_%s_db_%s_schema_%s_rows_count", |
| 923 | Title: "Table total rows", |
| 924 | Units: "rows", |
| 925 | Fam: "maintenance", |
| 926 | Ctx: "postgres.table_rows_count", |
| 927 | Priority: prioTableRowsCount, |
| 928 | Type: collectorapi.Stacked, |
| 929 | Dims: collectorapi.Dims{ |
| 930 | {ID: "table_%s_db_%s_schema_%s_n_live_tup", Name: "live"}, |
| 931 | {ID: "table_%s_db_%s_schema_%s_n_dead_tup", Name: "dead"}, |
| 932 | }, |
| 933 | } |
| 934 | tableOpsRowsRateChartTmpl = collectorapi.Chart{ |
| 935 | ID: "table_%s_db_%s_schema_%s_ops_rows_rate", |
| 936 | Title: "Table throughput", |
| 937 | Units: "rows/s", |
| 938 | Fam: "throughput", |
| 939 | Ctx: "postgres.table_ops_rows_rate", |
| 940 | Priority: prioTableOpsRowsRate, |
| 941 | Type: collectorapi.Stacked, |
| 942 | Dims: collectorapi.Dims{ |
| 943 | {ID: "table_%s_db_%s_schema_%s_n_tup_ins", Name: "inserted", Algo: collectorapi.Incremental}, |
| 944 | {ID: "table_%s_db_%s_schema_%s_n_tup_del", Name: "deleted", Algo: collectorapi.Incremental}, |
| 945 | {ID: "table_%s_db_%s_schema_%s_n_tup_upd", Name: "updated", Algo: collectorapi.Incremental}, |
| 946 | }, |
| 947 | } |
| 948 | tableOpsRowsHOTRatioChartTmpl = collectorapi.Chart{ |
| 949 | ID: "table_%s_db_%s_schema_%s_ops_rows_hot_ratio", |
| 950 | Title: "Table HOT updates ratio", |
| 951 | Units: "percentage", |
| 952 | Fam: "throughput", |
| 953 | Ctx: "postgres.table_ops_rows_hot_ratio", |
| 954 | Priority: prioTableOpsRowsHOTRatio, |
| 955 | Dims: collectorapi.Dims{ |
| 956 | {ID: "table_%s_db_%s_schema_%s_n_tup_hot_upd_perc", Name: "hot"}, |
| 957 | }, |
| 958 | } |
| 959 | tableOpsRowsHOTRateChartTmpl = collectorapi.Chart{ |
| 960 | ID: "table_%s_db_%s_schema_%s_ops_rows_hot_rate", |
| 961 | Title: "Table HOT updates", |
| 962 | Units: "rows/s", |
| 963 | Fam: "throughput", |
| 964 | Ctx: "postgres.table_ops_rows_hot_rate", |
| 965 | Priority: prioTableOpsRowsHOTRate, |
| 966 | Dims: collectorapi.Dims{ |
| 967 | {ID: "table_%s_db_%s_schema_%s_n_tup_hot_upd", Name: "hot", Algo: collectorapi.Incremental}, |
| 968 | }, |
| 969 | } |
| 970 | tableCacheIORatioChartTmpl = collectorapi.Chart{ |
| 971 | ID: "table_%s_db_%s_schema_%s_cache_io_ratio", |
| 972 | Title: "Table I/O cache miss ratio", |
| 973 | Units: "percentage", |
| 974 | Fam: "cache", |
| 975 | Ctx: "postgres.table_cache_io_ratio", |
| 976 | Priority: prioTableCacheIORatio, |
| 977 | Dims: collectorapi.Dims{ |
| 978 | {ID: "table_%s_db_%s_schema_%s_heap_blks_read_perc", Name: "miss"}, |
| 979 | }, |
| 980 | } |
| 981 | tableIORateChartTmpl = collectorapi.Chart{ |
| 982 | ID: "table_%s_db_%s_schema_%s_io_rate", |
| 983 | Title: "Table I/O", |
| 984 | Units: "B/s", |
| 985 | Fam: "cache", |
| 986 | Ctx: "postgres.table_io_rate", |
| 987 | Priority: prioTableIORate, |
| 988 | Dims: collectorapi.Dims{ |
| 989 | {ID: "table_%s_db_%s_schema_%s_heap_blks_hit", Name: "memory", Algo: collectorapi.Incremental}, |
| 990 | {ID: "table_%s_db_%s_schema_%s_heap_blks_read", Name: "disk", Algo: collectorapi.Incremental}, |
| 991 | }, |
| 992 | } |
| 993 | tableIndexCacheIORatioChartTmpl = collectorapi.Chart{ |
| 994 | ID: "table_%s_db_%s_schema_%s_index_cache_io_ratio", |
| 995 | Title: "Table index I/O cache miss ratio", |
| 996 | Units: "percentage", |
| 997 | Fam: "cache", |
| 998 | Ctx: "postgres.table_index_cache_io_ratio", |
| 999 | Priority: prioTableIndexCacheIORatio, |
| 1000 | Dims: collectorapi.Dims{ |
| 1001 | {ID: "table_%s_db_%s_schema_%s_idx_blks_read_perc", Name: "miss", Algo: collectorapi.Incremental}, |
| 1002 | }, |
| 1003 | } |
| 1004 | tableIndexIORateChartTmpl = collectorapi.Chart{ |
| 1005 | ID: "table_%s_db_%s_schema_%s_index_io_rate", |
| 1006 | Title: "Table index I/O", |
| 1007 | Units: "B/s", |
| 1008 | Fam: "cache", |
| 1009 | Ctx: "postgres.table_index_io_rate", |
| 1010 | Priority: prioTableIndexIORate, |
| 1011 | Dims: collectorapi.Dims{ |
| 1012 | {ID: "table_%s_db_%s_schema_%s_idx_blks_hit", Name: "memory", Algo: collectorapi.Incremental}, |
| 1013 | {ID: "table_%s_db_%s_schema_%s_idx_blks_read", Name: "disk", Algo: collectorapi.Incremental}, |
| 1014 | }, |
| 1015 | } |
| 1016 | tableTOASCacheIORatioChartTmpl = collectorapi.Chart{ |
| 1017 | ID: "table_%s_db_%s_schema_%s_toast_cache_io_ratio", |
| 1018 | Title: "Table TOAST I/O cache miss ratio", |
| 1019 | Units: "percentage", |
| 1020 | Fam: "cache", |
| 1021 | Ctx: "postgres.table_toast_cache_io_ratio", |
| 1022 | Priority: prioTableToastCacheIORatio, |
| 1023 | Dims: collectorapi.Dims{ |
| 1024 | {ID: "table_%s_db_%s_schema_%s_toast_blks_read_perc", Name: "miss", Algo: collectorapi.Incremental}, |
| 1025 | }, |
| 1026 | } |
| 1027 | tableTOASTIORateChartTmpl = collectorapi.Chart{ |
| 1028 | ID: "table_%s_db_%s_schema_%s_toast_io_rate", |
| 1029 | Title: "Table TOAST I/O", |
| 1030 | Units: "B/s", |
| 1031 | Fam: "cache", |
| 1032 | Ctx: "postgres.table_toast_io_rate", |
| 1033 | Priority: prioTableToastIORate, |
| 1034 | Dims: collectorapi.Dims{ |
| 1035 | {ID: "table_%s_db_%s_schema_%s_toast_blks_hit", Name: "memory", Algo: collectorapi.Incremental}, |
| 1036 | {ID: "table_%s_db_%s_schema_%s_toast_blks_read", Name: "disk", Algo: collectorapi.Incremental}, |
| 1037 | }, |
| 1038 | } |
| 1039 | tableTOASTIndexCacheIORatioChartTmpl = collectorapi.Chart{ |
| 1040 | ID: "table_%s_db_%s_schema_%s_toast_index_cache_io_ratio", |
| 1041 | Title: "Table TOAST index I/O cache miss ratio", |
| 1042 | Units: "percentage", |
| 1043 | Fam: "cache", |
| 1044 | Ctx: "postgres.table_toast_index_cache_io_ratio", |
| 1045 | Priority: prioTableToastIndexCacheIORatio, |
| 1046 | Dims: collectorapi.Dims{ |
| 1047 | {ID: "table_%s_db_%s_schema_%s_tidx_blks_read_perc", Name: "miss", Algo: collectorapi.Incremental}, |
| 1048 | }, |
| 1049 | } |
| 1050 | tableTOASTIndexIORateChartTmpl = collectorapi.Chart{ |
| 1051 | ID: "table_%s_db_%s_schema_%s_toast_index_io_rate", |
| 1052 | Title: "Table TOAST index I/O", |
| 1053 | Units: "B/s", |
| 1054 | Fam: "cache", |
| 1055 | Ctx: "postgres.table_toast_index_io_rate", |
| 1056 | Priority: prioTableToastIndexIORate, |
| 1057 | Dims: collectorapi.Dims{ |
| 1058 | {ID: "table_%s_db_%s_schema_%s_tidx_blks_hit", Name: "memory", Algo: collectorapi.Incremental}, |
| 1059 | {ID: "table_%s_db_%s_schema_%s_tidx_blks_read", Name: "disk", Algo: collectorapi.Incremental}, |
| 1060 | }, |
| 1061 | } |
| 1062 | tableScansRateChartTmpl = collectorapi.Chart{ |
| 1063 | ID: "table_%s_db_%s_schema_%s_scans_rate", |
| 1064 | Title: "Table scans", |
| 1065 | Units: "scans/s", |
| 1066 | Fam: "throughput", |
| 1067 | Ctx: "postgres.table_scans_rate", |
| 1068 | Priority: prioTableScansRate, |
| 1069 | Dims: collectorapi.Dims{ |
| 1070 | {ID: "table_%s_db_%s_schema_%s_idx_scan", Name: "index", Algo: collectorapi.Incremental}, |
| 1071 | {ID: "table_%s_db_%s_schema_%s_seq_scan", Name: "sequential", Algo: collectorapi.Incremental}, |
| 1072 | }, |
| 1073 | } |
| 1074 | tableScansRowsRateChartTmpl = collectorapi.Chart{ |
| 1075 | ID: "table_%s_db_%s_schema_%s_scans_rows_rate", |
| 1076 | Title: "Table live rows fetched by scans", |
| 1077 | Units: "rows/s", |
| 1078 | Fam: "throughput", |
| 1079 | Ctx: "postgres.table_scans_rows_rate", |
| 1080 | Priority: prioTableScansRowsRate, |
| 1081 | Dims: collectorapi.Dims{ |
| 1082 | {ID: "table_%s_db_%s_schema_%s_idx_tup_fetch", Name: "index", Algo: collectorapi.Incremental}, |
| 1083 | {ID: "table_%s_db_%s_schema_%s_seq_tup_read", Name: "sequential", Algo: collectorapi.Incremental}, |
| 1084 | }, |
| 1085 | } |
| 1086 | tableAutoVacuumSinceTimeChartTmpl = collectorapi.Chart{ |
| 1087 | ID: "table_%s_db_%s_schema_%s_autovacuum_since_time", |
| 1088 | Title: "Table time since last auto VACUUM", |
| 1089 | Units: "seconds", |
| 1090 | Fam: "vacuum and analyze", |
| 1091 | Ctx: "postgres.table_autovacuum_since_time", |
| 1092 | Priority: prioTableAutovacuumSinceTime, |
| 1093 | Dims: collectorapi.Dims{ |
| 1094 | {ID: "table_%s_db_%s_schema_%s_last_autovacuum_ago", Name: "time"}, |
| 1095 | }, |
| 1096 | } |
| 1097 | tableVacuumSinceTimeChartTmpl = collectorapi.Chart{ |
| 1098 | ID: "table_%s_db_%s_schema_%s_vacuum_since_time", |
| 1099 | Title: "Table time since last manual VACUUM", |
| 1100 | Units: "seconds", |
| 1101 | Fam: "vacuum and analyze", |
| 1102 | Ctx: "postgres.table_vacuum_since_time", |
| 1103 | Priority: prioTableVacuumSinceTime, |
| 1104 | Dims: collectorapi.Dims{ |
| 1105 | {ID: "table_%s_db_%s_schema_%s_last_vacuum_ago", Name: "time"}, |
| 1106 | }, |
| 1107 | } |
| 1108 | tableAutoAnalyzeSinceTimeChartTmpl = collectorapi.Chart{ |
| 1109 | ID: "table_%s_db_%s_schema_%s_autoanalyze_since_time", |
| 1110 | Title: "Table time since last auto ANALYZE", |
| 1111 | Units: "seconds", |
| 1112 | Fam: "vacuum and analyze", |
| 1113 | Ctx: "postgres.table_autoanalyze_since_time", |
| 1114 | Priority: prioTableAutoAnalyzeSinceTime, |
| 1115 | Dims: collectorapi.Dims{ |
| 1116 | {ID: "table_%s_db_%s_schema_%s_last_autoanalyze_ago", Name: "time"}, |
| 1117 | }, |
| 1118 | } |
| 1119 | tableAnalyzeSinceTimeChartTmpl = collectorapi.Chart{ |
| 1120 | ID: "table_%s_db_%s_schema_%s_analyze_since_time", |
| 1121 | Title: "Table time since last manual ANALYZE", |
| 1122 | Units: "seconds", |
| 1123 | Fam: "vacuum and analyze", |
| 1124 | Ctx: "postgres.table_analyze_since_time", |
| 1125 | Priority: prioTableLastAnalyzeAgo, |
| 1126 | Dims: collectorapi.Dims{ |
| 1127 | {ID: "table_%s_db_%s_schema_%s_last_analyze_ago", Name: "time"}, |
| 1128 | }, |
| 1129 | } |
| 1130 | tableNullColumnsCountChartTmpl = collectorapi.Chart{ |
| 1131 | ID: "table_%s_db_%s_schema_%s_null_columns_count", |
| 1132 | Title: "Table null columns", |
| 1133 | Units: "columns", |
| 1134 | Fam: "maintenance", |
| 1135 | Ctx: "postgres.table_null_columns_count", |
| 1136 | Priority: prioTableNullColumns, |
| 1137 | Dims: collectorapi.Dims{ |
| 1138 | {ID: "table_%s_db_%s_schema_%s_null_columns", Name: "null"}, |
| 1139 | }, |
| 1140 | } |
| 1141 | tableTotalSizeChartTmpl = collectorapi.Chart{ |
| 1142 | ID: "table_%s_db_%s_schema_%s_total_size", |
| 1143 | Title: "Table total size", |
| 1144 | Units: "B", |
| 1145 | Fam: "size", |
| 1146 | Ctx: "postgres.table_total_size", |
| 1147 | Priority: prioTableTotalSize, |
| 1148 | Dims: collectorapi.Dims{ |
| 1149 | {ID: "table_%s_db_%s_schema_%s_total_size", Name: "size"}, |
| 1150 | }, |
| 1151 | } |
| 1152 | tableBloatSizePercChartTmpl = collectorapi.Chart{ |
| 1153 | ID: "table_%s_db_%s_schema_%s_bloat_size_perc", |
| 1154 | Title: "Table bloat size percentage", |
| 1155 | Units: "percentage", |
| 1156 | Fam: "bloat", |
| 1157 | Ctx: "postgres.table_bloat_size_perc", |
| 1158 | Priority: prioTableBloatSizePerc, |
| 1159 | Dims: collectorapi.Dims{ |
| 1160 | {ID: "table_%s_db_%s_schema_%s_bloat_size_perc", Name: "bloat"}, |
| 1161 | }, |
| 1162 | Vars: collectorapi.Vars{ |
| 1163 | {ID: "table_%s_db_%s_schema_%s_total_size", Name: "table_size"}, |
| 1164 | }, |
| 1165 | } |
| 1166 | tableBloatSizeChartTmpl = collectorapi.Chart{ |
| 1167 | ID: "table_%s_db_%s_schema_%s_bloat_size", |
| 1168 | Title: "Table bloat size", |
| 1169 | Units: "B", |
| 1170 | Fam: "bloat", |
| 1171 | Ctx: "postgres.table_bloat_size", |
| 1172 | Priority: prioTableBloatSize, |
| 1173 | Dims: collectorapi.Dims{ |
| 1174 | {ID: "table_%s_db_%s_schema_%s_bloat_size", Name: "bloat"}, |
| 1175 | }, |
| 1176 | } |
| 1177 | ) |
| 1178 | |
| 1179 | func newTableCharts(tbl *tableMetrics) *collectorapi.Charts { |
| 1180 | charts := tableChartsTmpl.Copy() |
| 1181 | |
| 1182 | if tbl.bloatSize == nil { |
| 1183 | _ = charts.Remove(tableBloatSizeChartTmpl.ID) |
| 1184 | _ = charts.Remove(tableBloatSizePercChartTmpl.ID) |
| 1185 | } |
| 1186 | |
| 1187 | for i, chart := range *charts { |
| 1188 | (*charts)[i] = newTableChart(chart, tbl) |
| 1189 | } |
| 1190 | |
| 1191 | return charts |
| 1192 | } |
| 1193 | |
| 1194 | func newTableChart(chart *collectorapi.Chart, tbl *tableMetrics) *collectorapi.Chart { |
| 1195 | chart = chart.Copy() |
| 1196 | chart.ID = fmt.Sprintf(chart.ID, tbl.name, tbl.db, tbl.schema) |
| 1197 | chart.Labels = []collectorapi.Label{ |
| 1198 | {Key: "database", Value: tbl.db}, |
| 1199 | {Key: "schema", Value: tbl.schema}, |
| 1200 | {Key: "table", Value: tbl.name}, |
| 1201 | {Key: "parent_table", Value: tbl.parentName}, |
| 1202 | } |
| 1203 | for _, d := range chart.Dims { |
| 1204 | d.ID = fmt.Sprintf(d.ID, tbl.name, tbl.db, tbl.schema) |
| 1205 | } |
| 1206 | for _, v := range chart.Vars { |
| 1207 | v.ID = fmt.Sprintf(v.ID, tbl.name, tbl.db, tbl.schema) |
| 1208 | } |
| 1209 | return chart |
| 1210 | } |
| 1211 | |
| 1212 | func (c *Collector) addNewTableCharts(tbl *tableMetrics) { |
| 1213 | charts := newTableCharts(tbl) |
| 1214 | if err := c.Charts().Add(*charts...); err != nil { |
| 1215 | c.Warning(err) |
| 1216 | } |
| 1217 | } |
| 1218 | |
| 1219 | func (c *Collector) addTableLastAutoVacuumAgoChart(tbl *tableMetrics) { |
| 1220 | chart := newTableChart(tableAutoVacuumSinceTimeChartTmpl.Copy(), tbl) |
| 1221 | |
| 1222 | if err := c.Charts().Add(chart); err != nil { |
| 1223 | c.Warning(err) |
| 1224 | } |
| 1225 | } |
| 1226 | |
| 1227 | func (c *Collector) addTableLastVacuumAgoChart(tbl *tableMetrics) { |
| 1228 | chart := newTableChart(tableVacuumSinceTimeChartTmpl.Copy(), tbl) |
| 1229 | |
| 1230 | if err := c.Charts().Add(chart); err != nil { |
| 1231 | c.Warning(err) |
| 1232 | } |
| 1233 | } |
| 1234 | |
| 1235 | func (c *Collector) addTableLastAutoAnalyzeAgoChart(tbl *tableMetrics) { |
| 1236 | chart := newTableChart(tableAutoAnalyzeSinceTimeChartTmpl.Copy(), tbl) |
| 1237 | |
| 1238 | if err := c.Charts().Add(chart); err != nil { |
| 1239 | c.Warning(err) |
| 1240 | } |
| 1241 | } |
| 1242 | |
| 1243 | func (c *Collector) addTableLastAnalyzeAgoChart(tbl *tableMetrics) { |
| 1244 | chart := newTableChart(tableAnalyzeSinceTimeChartTmpl.Copy(), tbl) |
| 1245 | |
| 1246 | if err := c.Charts().Add(chart); err != nil { |
| 1247 | c.Warning(err) |
| 1248 | } |
| 1249 | } |
| 1250 | |
| 1251 | func (c *Collector) addTableIOChartsCharts(tbl *tableMetrics) { |
| 1252 | charts := collectorapi.Charts{ |
| 1253 | newTableChart(tableCacheIORatioChartTmpl.Copy(), tbl), |
| 1254 | newTableChart(tableIORateChartTmpl.Copy(), tbl), |
| 1255 | } |
| 1256 | |
| 1257 | if err := c.Charts().Add(charts...); err != nil { |
| 1258 | c.Warning(err) |
| 1259 | } |
| 1260 | } |
| 1261 | |
| 1262 | func (c *Collector) addTableIndexIOCharts(tbl *tableMetrics) { |
| 1263 | charts := collectorapi.Charts{ |
| 1264 | newTableChart(tableIndexCacheIORatioChartTmpl.Copy(), tbl), |
| 1265 | newTableChart(tableIndexIORateChartTmpl.Copy(), tbl), |
| 1266 | } |
| 1267 | |
| 1268 | if err := c.Charts().Add(charts...); err != nil { |
| 1269 | c.Warning(err) |
| 1270 | } |
| 1271 | } |
| 1272 | |
| 1273 | func (c *Collector) addTableTOASTIOCharts(tbl *tableMetrics) { |
| 1274 | charts := collectorapi.Charts{ |
| 1275 | newTableChart(tableTOASCacheIORatioChartTmpl.Copy(), tbl), |
| 1276 | newTableChart(tableTOASTIORateChartTmpl.Copy(), tbl), |
| 1277 | } |
| 1278 | |
| 1279 | if err := c.Charts().Add(charts...); err != nil { |
| 1280 | c.Warning(err) |
| 1281 | } |
| 1282 | } |
| 1283 | |
| 1284 | func (c *Collector) addTableTOASTIndexIOCharts(tbl *tableMetrics) { |
| 1285 | charts := collectorapi.Charts{ |
| 1286 | newTableChart(tableTOASTIndexCacheIORatioChartTmpl.Copy(), tbl), |
| 1287 | newTableChart(tableTOASTIndexIORateChartTmpl.Copy(), tbl), |
| 1288 | } |
| 1289 | |
| 1290 | if err := c.Charts().Add(charts...); err != nil { |
| 1291 | c.Warning(err) |
| 1292 | } |
| 1293 | } |
| 1294 | |
| 1295 | func (c *Collector) removeTableCharts(tbl *tableMetrics) { |
| 1296 | prefix := fmt.Sprintf("table_%s_db_%s_schema_%s", tbl.name, tbl.db, tbl.schema) |
| 1297 | for _, c := range *c.Charts() { |
| 1298 | if strings.HasPrefix(c.ID, prefix) { |
| 1299 | c.MarkRemove() |
| 1300 | c.MarkNotCreated() |
| 1301 | } |
| 1302 | } |
| 1303 | } |
| 1304 | |
| 1305 | var ( |
| 1306 | indexChartsTmpl = collectorapi.Charts{ |
| 1307 | indexSizeChartTmpl.Copy(), |
| 1308 | indexBloatSizePercChartTmpl.Copy(), |
| 1309 | indexBloatSizeChartTmpl.Copy(), |
| 1310 | indexUsageStatusChartTmpl.Copy(), |
| 1311 | } |
| 1312 | indexSizeChartTmpl = collectorapi.Chart{ |
| 1313 | ID: "index_%s_table_%s_db_%s_schema_%s_size", |
| 1314 | Title: "Index size", |
| 1315 | Units: "B", |
| 1316 | Fam: "size", |
| 1317 | Ctx: "postgres.index_size", |
| 1318 | Priority: prioIndexSize, |
| 1319 | Dims: collectorapi.Dims{ |
| 1320 | {ID: "index_%s_table_%s_db_%s_schema_%s_size", Name: "size"}, |
| 1321 | }, |
| 1322 | } |
| 1323 | indexBloatSizePercChartTmpl = collectorapi.Chart{ |
| 1324 | ID: "index_%s_table_%s_db_%s_schema_%s_bloat_size_perc", |
| 1325 | Title: "Index bloat size percentage", |
| 1326 | Units: "percentage", |
| 1327 | Fam: "bloat", |
| 1328 | Ctx: "postgres.index_bloat_size_perc", |
| 1329 | Priority: prioIndexBloatSizePerc, |
| 1330 | Dims: collectorapi.Dims{ |
| 1331 | {ID: "index_%s_table_%s_db_%s_schema_%s_bloat_size_perc", Name: "bloat"}, |
| 1332 | }, |
| 1333 | Vars: collectorapi.Vars{ |
| 1334 | {ID: "index_%s_table_%s_db_%s_schema_%s_size", Name: "index_size"}, |
| 1335 | }, |
| 1336 | } |
| 1337 | indexBloatSizeChartTmpl = collectorapi.Chart{ |
| 1338 | ID: "index_%s_table_%s_db_%s_schema_%s_bloat_size", |
| 1339 | Title: "Index bloat size", |
| 1340 | Units: "B", |
| 1341 | Fam: "bloat", |
| 1342 | Ctx: "postgres.index_bloat_size", |
| 1343 | Priority: prioIndexBloatSize, |
| 1344 | Dims: collectorapi.Dims{ |
| 1345 | {ID: "index_%s_table_%s_db_%s_schema_%s_bloat_size", Name: "bloat"}, |
| 1346 | }, |
| 1347 | } |
| 1348 | indexUsageStatusChartTmpl = collectorapi.Chart{ |
| 1349 | ID: "index_%s_table_%s_db_%s_schema_%s_usage_status", |
| 1350 | Title: "Index usage status", |
| 1351 | Units: "status", |
| 1352 | Fam: "maintenance", |
| 1353 | Ctx: "postgres.index_usage_status", |
| 1354 | Priority: prioIndexUsageStatus, |
| 1355 | Dims: collectorapi.Dims{ |
| 1356 | {ID: "index_%s_table_%s_db_%s_schema_%s_usage_status_used", Name: "used"}, |
| 1357 | {ID: "index_%s_table_%s_db_%s_schema_%s_usage_status_unused", Name: "unused"}, |
| 1358 | }, |
| 1359 | } |
| 1360 | ) |
| 1361 | |
| 1362 | func (c *Collector) addNewIndexCharts(idx *indexMetrics) { |
| 1363 | charts := indexChartsTmpl.Copy() |
| 1364 | |
| 1365 | if idx.bloatSize == nil { |
| 1366 | _ = charts.Remove(indexBloatSizeChartTmpl.ID) |
| 1367 | _ = charts.Remove(indexBloatSizePercChartTmpl.ID) |
| 1368 | } |
| 1369 | |
| 1370 | for _, chart := range *charts { |
| 1371 | chart.ID = fmt.Sprintf(chart.ID, idx.name, idx.table, idx.db, idx.schema) |
| 1372 | chart.Labels = []collectorapi.Label{ |
| 1373 | {Key: "database", Value: idx.db}, |
| 1374 | {Key: "schema", Value: idx.schema}, |
| 1375 | {Key: "table", Value: idx.table}, |
| 1376 | {Key: "parent_table", Value: idx.parentTable}, |
| 1377 | {Key: "index", Value: idx.name}, |
| 1378 | } |
| 1379 | for _, d := range chart.Dims { |
| 1380 | d.ID = fmt.Sprintf(d.ID, idx.name, idx.table, idx.db, idx.schema) |
| 1381 | } |
| 1382 | for _, v := range chart.Vars { |
| 1383 | v.ID = fmt.Sprintf(v.ID, idx.name, idx.table, idx.db, idx.schema) |
| 1384 | } |
| 1385 | } |
| 1386 | |
| 1387 | if err := c.Charts().Add(*charts...); err != nil { |
| 1388 | c.Warning(err) |
| 1389 | } |
| 1390 | } |
| 1391 | |
| 1392 | func (c *Collector) removeIndexCharts(idx *indexMetrics) { |
| 1393 | prefix := fmt.Sprintf("index_%s_table_%s_db_%s_schema_%s", idx.name, idx.table, idx.db, idx.schema) |
| 1394 | for _, c := range *c.Charts() { |
| 1395 | if strings.HasPrefix(c.ID, prefix) { |
| 1396 | c.MarkRemove() |
| 1397 | c.MarkNotCreated() |
| 1398 | } |
| 1399 | } |
| 1400 | } |