github.com/netdata/go.d.plugin@v0.58.1/modules/postgres/charts.go (about) 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/go.d.plugin/agent/module" 11 ) 12 13 const ( 14 prioConnectionsUtilization = module.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 = module.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 = module.Charts{ 123 walFilesCountChart.Copy(), 124 walArchivingFilesCountChart.Copy(), 125 } 126 127 func (p *Postgres) addWALFilesCharts() { 128 charts := walFilesCharts.Copy() 129 130 if err := p.Charts().Add(*charts...); err != nil { 131 p.Warning(err) 132 } 133 } 134 135 var ( 136 serverConnectionsUtilizationChart = module.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: module.Dims{ 144 {ID: "server_connections_utilization", Name: "used"}, 145 }, 146 } 147 serverConnectionsUsageChart = module.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: module.Stacked, 155 Dims: module.Dims{ 156 {ID: "server_connections_available", Name: "available"}, 157 {ID: "server_connections_used", Name: "used"}, 158 }, 159 } 160 serverConnectionsStateCount = module.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: module.Stacked, 168 Dims: module.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 = module.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: module.Dims{ 186 {ID: "locks_utilization", Name: "used"}, 187 }, 188 } 189 190 checkpointsChart = module.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: module.Stacked, 198 Dims: module.Dims{ 199 {ID: "checkpoints_timed", Name: "scheduled", Algo: module.Incremental}, 200 {ID: "checkpoints_req", Name: "requested", Algo: module.Incremental}, 201 }, 202 } 203 // TODO: should be seconds, also it is units/s when using incremental... 204 checkpointWriteChart = module.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: module.Stacked, 212 Dims: module.Dims{ 213 {ID: "checkpoint_write_time", Name: "write", Algo: module.Incremental}, 214 {ID: "checkpoint_sync_time", Name: "sync", Algo: module.Incremental}, 215 }, 216 } 217 bgWriterHaltsRateChart = module.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: module.Dims{ 225 {ID: "maxwritten_clean", Name: "maxwritten", Algo: module.Incremental}, 226 }, 227 } 228 229 buffersIORateChart = module.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: module.Area, 237 Dims: module.Dims{ 238 {ID: "buffers_checkpoint", Name: "checkpoint", Algo: module.Incremental}, 239 {ID: "buffers_backend", Name: "backend", Algo: module.Incremental}, 240 {ID: "buffers_clean", Name: "bgwriter", Algo: module.Incremental}, 241 }, 242 } 243 buffersBackendFsyncRateChart = module.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: module.Dims{ 251 {ID: "buffers_backend_fsync", Name: "fsync", Algo: module.Incremental}, 252 }, 253 } 254 buffersAllocRateChart = module.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: module.Dims{ 262 {ID: "buffers_alloc", Name: "allocated", Algo: module.Incremental}, 263 }, 264 } 265 266 walIORateChart = module.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: module.Dims{ 274 {ID: "wal_writes", Name: "written", Algo: module.Incremental}, 275 }, 276 } 277 walFilesCountChart = module.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: module.Stacked, 285 Dims: module.Dims{ 286 {ID: "wal_written_files", Name: "written"}, 287 {ID: "wal_recycled_files", Name: "recycled"}, 288 }, 289 } 290 291 walArchivingFilesCountChart = module.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: module.Stacked, 299 Dims: module.Dims{ 300 {ID: "wal_archive_files_ready_count", Name: "ready"}, 301 {ID: "wal_archive_files_done_count", Name: "done"}, 302 }, 303 } 304 305 autovacuumWorkersCountChart = module.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: module.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 = module.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: module.Dims{ 329 {ID: "percent_towards_emergency_autovacuum", Name: "emergency_autovacuum"}, 330 }, 331 } 332 txidExhaustionPercChart = module.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: module.Dims{ 340 {ID: "percent_towards_wraparound", Name: "txid_exhaustion"}, 341 }, 342 } 343 txidExhaustionOldestTXIDNumChart = module.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: module.Dims{ 351 {ID: "oldest_current_xid", Name: "xid"}, 352 }, 353 } 354 355 catalogRelationSCountChart = module.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: module.Stacked, 363 Dims: module.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 = module.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: module.Stacked, 384 Dims: module.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 = module.Chart{ 399 ID: "server_uptime", 400 Title: "Uptime", 401 Units: "seconds", 402 Fam: "uptime", 403 Ctx: "postgres.uptime", 404 Priority: prioUptime, 405 Dims: module.Dims{ 406 {ID: "server_uptime", Name: "uptime"}, 407 }, 408 } 409 410 databasesCountChart = module.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: module.Dims{ 418 {ID: "databases_count", Name: "databases"}, 419 }, 420 } 421 422 transactionsDurationChartTmpl = module.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: module.Stacked, 430 } 431 queriesDurationChartTmpl = module.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: module.Stacked, 439 } 440 ) 441 442 func newRunningTimeHistogramChart(tmpl module.Chart, prefix string, buckets []float64) (*module.Chart, error) { 443 chart := tmpl.Copy() 444 445 for i, v := range buckets { 446 dim := &module.Dim{ 447 ID: fmt.Sprintf("%s_hist_bucket_%d", prefix, i+1), 448 Name: time.Duration(v * float64(time.Second)).String(), 449 Algo: module.Incremental, 450 } 451 if err := chart.AddDim(dim); err != nil { 452 return nil, err 453 } 454 } 455 456 dim := &module.Dim{ 457 ID: fmt.Sprintf("%s_hist_bucket_inf", prefix), 458 Name: "+Inf", 459 Algo: module.Incremental, 460 } 461 if err := chart.AddDim(dim); err != nil { 462 return nil, err 463 } 464 465 return chart, nil 466 } 467 468 func (p *Postgres) addTransactionsRunTimeHistogramChart() { 469 chart, err := newRunningTimeHistogramChart( 470 transactionsDurationChartTmpl, 471 "transaction_running_time", 472 p.XactTimeHistogram, 473 ) 474 if err != nil { 475 p.Warning(err) 476 return 477 } 478 if err := p.Charts().Add(chart); err != nil { 479 p.Warning(err) 480 } 481 } 482 483 func (p *Postgres) addQueriesRunTimeHistogramChart() { 484 chart, err := newRunningTimeHistogramChart( 485 queriesDurationChartTmpl, 486 "query_running_time", 487 p.QueryTimeHistogram, 488 ) 489 if err != nil { 490 p.Warning(err) 491 return 492 } 493 if err := p.Charts().Add(chart); err != nil { 494 p.Warning(err) 495 } 496 } 497 498 var ( 499 replicationStandbyAppCharts = module.Charts{ 500 replicationAppWALLagSizeChartTmpl.Copy(), 501 replicationAppWALLagTimeChartTmpl.Copy(), 502 } 503 replicationAppWALLagSizeChartTmpl = module.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: module.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 = module.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: module.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) *module.Charts { 533 charts := replicationStandbyAppCharts.Copy() 534 for _, c := range *charts { 535 c.ID = fmt.Sprintf(c.ID, app) 536 c.Labels = []module.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 (p *Postgres) addNewReplicationStandbyAppCharts(app string) { 547 charts := newReplicationStandbyAppCharts(app) 548 if err := p.Charts().Add(*charts...); err != nil { 549 p.Warning(err) 550 } 551 } 552 553 func (p *Postgres) removeReplicationStandbyAppCharts(app string) { 554 prefix := fmt.Sprintf("replication_standby_app_%s_", app) 555 for _, c := range *p.Charts() { 556 if strings.HasPrefix(c.ID, prefix) { 557 c.MarkRemove() 558 c.MarkNotCreated() 559 } 560 } 561 } 562 563 var ( 564 replicationSlotCharts = module.Charts{ 565 replicationSlotFilesCountChartTmpl.Copy(), 566 } 567 replicationSlotFilesCountChartTmpl = module.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: module.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) *module.Charts { 582 charts := replicationSlotCharts.Copy() 583 for _, c := range *charts { 584 c.ID = fmt.Sprintf(c.ID, slot) 585 c.Labels = []module.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 (p *Postgres) addNewReplicationSlotCharts(slot string) { 596 charts := newReplicationSlotCharts(slot) 597 if err := p.Charts().Add(*charts...); err != nil { 598 p.Warning(err) 599 } 600 } 601 602 func (p *Postgres) removeReplicationSlotCharts(slot string) { 603 prefix := fmt.Sprintf("replication_slot_%s_", slot) 604 for _, c := range *p.Charts() { 605 if strings.HasPrefix(c.ID, prefix) { 606 c.MarkRemove() 607 c.MarkNotCreated() 608 } 609 } 610 } 611 612 var ( 613 dbChartsTmpl = module.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 = module.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: module.Stacked, 638 Dims: module.Dims{ 639 {ID: "db_%s_xact_commit", Name: "committed", Algo: module.PercentOfIncremental}, 640 {ID: "db_%s_xact_rollback", Name: "rollback", Algo: module.PercentOfIncremental}, 641 }, 642 } 643 dbTransactionsRateChartTmpl = module.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: module.Dims{ 651 {ID: "db_%s_xact_commit", Name: "committed", Algo: module.Incremental}, 652 {ID: "db_%s_xact_rollback", Name: "rollback", Algo: module.Incremental}, 653 }, 654 } 655 dbConnectionsUtilizationChartTmpl = module.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: module.Dims{ 663 {ID: "db_%s_numbackends_utilization", Name: "used"}, 664 }, 665 } 666 dbConnectionsCountChartTmpl = module.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: module.Dims{ 674 {ID: "db_%s_numbackends", Name: "connections"}, 675 }, 676 } 677 dbCacheIORatioChartTmpl = module.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: module.Dims{ 685 {ID: "db_%s_blks_read_perc", Name: "miss"}, 686 }, 687 } 688 dbIORateChartTmpl = module.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: module.Area, 696 Dims: module.Dims{ 697 {ID: "db_%s_blks_hit", Name: "memory", Algo: module.Incremental}, 698 {ID: "db_%s_blks_read", Name: "disk", Algo: module.Incremental}, 699 }, 700 } 701 dbOpsFetchedRowsRatioChartTmpl = module.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: module.Dims{ 709 {ID: "db_%s_tup_fetched_perc", Name: "fetched"}, 710 }, 711 } 712 dbOpsReadRowsRateChartTmpl = module.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: module.Dims{ 720 {ID: "db_%s_tup_returned", Name: "returned", Algo: module.Incremental}, 721 {ID: "db_%s_tup_fetched", Name: "fetched", Algo: module.Incremental}, 722 }, 723 } 724 dbOpsWriteRowsRateChartTmpl = module.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: module.Dims{ 732 {ID: "db_%s_tup_inserted", Name: "inserted", Algo: module.Incremental}, 733 {ID: "db_%s_tup_deleted", Name: "deleted", Algo: module.Incremental}, 734 {ID: "db_%s_tup_updated", Name: "updated", Algo: module.Incremental}, 735 }, 736 } 737 dbConflictsRateChartTmpl = module.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: module.Dims{ 745 {ID: "db_%s_conflicts", Name: "conflicts", Algo: module.Incremental}, 746 }, 747 } 748 dbConflictsReasonRateChartTmpl = module.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: module.Dims{ 756 {ID: "db_%s_confl_tablespace", Name: "tablespace", Algo: module.Incremental}, 757 {ID: "db_%s_confl_lock", Name: "lock", Algo: module.Incremental}, 758 {ID: "db_%s_confl_snapshot", Name: "snapshot", Algo: module.Incremental}, 759 {ID: "db_%s_confl_bufferpin", Name: "bufferpin", Algo: module.Incremental}, 760 {ID: "db_%s_confl_deadlock", Name: "deadlock", Algo: module.Incremental}, 761 }, 762 } 763 dbDeadlocksRateChartTmpl = module.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: module.Dims{ 771 {ID: "db_%s_deadlocks", Name: "deadlocks", Algo: module.Incremental}, 772 }, 773 } 774 dbLocksHeldCountChartTmpl = module.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: module.Stacked, 782 Dims: module.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 = module.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: module.Stacked, 801 Dims: module.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 = module.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: module.Dims{ 820 {ID: "db_%s_temp_files", Name: "created", Algo: module.Incremental}, 821 }, 822 } 823 dbTempFilesIORateChartTmpl = module.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: module.Dims{ 831 {ID: "db_%s_temp_bytes", Name: "written", Algo: module.Incremental}, 832 }, 833 } 834 dbSizeChartTmpl = module.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: module.Dims{ 842 {ID: "db_%s_size", Name: "size"}, 843 }, 844 } 845 ) 846 847 func (p *Postgres) addDBConflictsCharts(db *dbMetrics) { 848 tmpl := module.Charts{ 849 dbConflictsRateChartTmpl.Copy(), 850 dbConflictsReasonRateChartTmpl.Copy(), 851 } 852 charts := newDatabaseCharts(tmpl.Copy(), db) 853 854 if err := p.Charts().Add(*charts...); err != nil { 855 p.Warning(err) 856 } 857 } 858 859 func newDatabaseCharts(tmpl *module.Charts, db *dbMetrics) *module.Charts { 860 charts := tmpl.Copy() 861 for _, c := range *charts { 862 c.ID = fmt.Sprintf(c.ID, db.name) 863 c.Labels = []module.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 (p *Postgres) 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 := p.Charts().Add(*charts...); err != nil { 881 p.Warning(err) 882 } 883 } 884 885 func (p *Postgres) removeDatabaseCharts(db *dbMetrics) { 886 prefix := fmt.Sprintf("db_%s_", db.name) 887 for _, c := range *p.Charts() { 888 if strings.HasPrefix(c.ID, prefix) { 889 c.MarkRemove() 890 c.MarkNotCreated() 891 } 892 } 893 } 894 895 var ( 896 tableChartsTmpl = module.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 = module.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: module.Dims{ 918 {ID: "table_%s_db_%s_schema_%s_n_dead_tup_perc", Name: "dead"}, 919 }, 920 } 921 tableRowsCountChartTmpl = module.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: module.Stacked, 929 Dims: module.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 = module.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: module.Stacked, 942 Dims: module.Dims{ 943 {ID: "table_%s_db_%s_schema_%s_n_tup_ins", Name: "inserted", Algo: module.Incremental}, 944 {ID: "table_%s_db_%s_schema_%s_n_tup_del", Name: "deleted", Algo: module.Incremental}, 945 {ID: "table_%s_db_%s_schema_%s_n_tup_upd", Name: "updated", Algo: module.Incremental}, 946 }, 947 } 948 tableOpsRowsHOTRatioChartTmpl = module.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: module.Dims{ 956 {ID: "table_%s_db_%s_schema_%s_n_tup_hot_upd_perc", Name: "hot"}, 957 }, 958 } 959 tableOpsRowsHOTRateChartTmpl = module.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: module.Dims{ 967 {ID: "table_%s_db_%s_schema_%s_n_tup_hot_upd", Name: "hot", Algo: module.Incremental}, 968 }, 969 } 970 tableCacheIORatioChartTmpl = module.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: module.Dims{ 978 {ID: "table_%s_db_%s_schema_%s_heap_blks_read_perc", Name: "miss"}, 979 }, 980 } 981 tableIORateChartTmpl = module.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: module.Dims{ 989 {ID: "table_%s_db_%s_schema_%s_heap_blks_hit", Name: "memory", Algo: module.Incremental}, 990 {ID: "table_%s_db_%s_schema_%s_heap_blks_read", Name: "disk", Algo: module.Incremental}, 991 }, 992 } 993 tableIndexCacheIORatioChartTmpl = module.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: module.Dims{ 1001 {ID: "table_%s_db_%s_schema_%s_idx_blks_read_perc", Name: "miss", Algo: module.Incremental}, 1002 }, 1003 } 1004 tableIndexIORateChartTmpl = module.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: module.Dims{ 1012 {ID: "table_%s_db_%s_schema_%s_idx_blks_hit", Name: "memory", Algo: module.Incremental}, 1013 {ID: "table_%s_db_%s_schema_%s_idx_blks_read", Name: "disk", Algo: module.Incremental}, 1014 }, 1015 } 1016 tableTOASCacheIORatioChartTmpl = module.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: module.Dims{ 1024 {ID: "table_%s_db_%s_schema_%s_toast_blks_read_perc", Name: "miss", Algo: module.Incremental}, 1025 }, 1026 } 1027 tableTOASTIORateChartTmpl = module.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: module.Dims{ 1035 {ID: "table_%s_db_%s_schema_%s_toast_blks_hit", Name: "memory", Algo: module.Incremental}, 1036 {ID: "table_%s_db_%s_schema_%s_toast_blks_read", Name: "disk", Algo: module.Incremental}, 1037 }, 1038 } 1039 tableTOASTIndexCacheIORatioChartTmpl = module.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: module.Dims{ 1047 {ID: "table_%s_db_%s_schema_%s_tidx_blks_read_perc", Name: "miss", Algo: module.Incremental}, 1048 }, 1049 } 1050 tableTOASTIndexIORateChartTmpl = module.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: module.Dims{ 1058 {ID: "table_%s_db_%s_schema_%s_tidx_blks_hit", Name: "memory", Algo: module.Incremental}, 1059 {ID: "table_%s_db_%s_schema_%s_tidx_blks_read", Name: "disk", Algo: module.Incremental}, 1060 }, 1061 } 1062 tableScansRateChartTmpl = module.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: module.Dims{ 1070 {ID: "table_%s_db_%s_schema_%s_idx_scan", Name: "index", Algo: module.Incremental}, 1071 {ID: "table_%s_db_%s_schema_%s_seq_scan", Name: "sequential", Algo: module.Incremental}, 1072 }, 1073 } 1074 tableScansRowsRateChartTmpl = module.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: module.Dims{ 1082 {ID: "table_%s_db_%s_schema_%s_idx_tup_fetch", Name: "index", Algo: module.Incremental}, 1083 {ID: "table_%s_db_%s_schema_%s_seq_tup_read", Name: "sequential", Algo: module.Incremental}, 1084 }, 1085 } 1086 tableAutoVacuumSinceTimeChartTmpl = module.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: module.Dims{ 1094 {ID: "table_%s_db_%s_schema_%s_last_autovacuum_ago", Name: "time"}, 1095 }, 1096 } 1097 tableVacuumSinceTimeChartTmpl = module.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: module.Dims{ 1105 {ID: "table_%s_db_%s_schema_%s_last_vacuum_ago", Name: "time"}, 1106 }, 1107 } 1108 tableAutoAnalyzeSinceTimeChartTmpl = module.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: module.Dims{ 1116 {ID: "table_%s_db_%s_schema_%s_last_autoanalyze_ago", Name: "time"}, 1117 }, 1118 } 1119 tableAnalyzeSinceTimeChartTmpl = module.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: module.Dims{ 1127 {ID: "table_%s_db_%s_schema_%s_last_analyze_ago", Name: "time"}, 1128 }, 1129 } 1130 tableNullColumnsCountChartTmpl = module.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: module.Dims{ 1138 {ID: "table_%s_db_%s_schema_%s_null_columns", Name: "null"}, 1139 }, 1140 } 1141 tableTotalSizeChartTmpl = module.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: module.Dims{ 1149 {ID: "table_%s_db_%s_schema_%s_total_size", Name: "size"}, 1150 }, 1151 } 1152 tableBloatSizePercChartTmpl = module.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: module.Dims{ 1160 {ID: "table_%s_db_%s_schema_%s_bloat_size_perc", Name: "bloat"}, 1161 }, 1162 Vars: module.Vars{ 1163 {ID: "table_%s_db_%s_schema_%s_total_size", Name: "table_size"}, 1164 }, 1165 } 1166 tableBloatSizeChartTmpl = module.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: module.Dims{ 1174 {ID: "table_%s_db_%s_schema_%s_bloat_size", Name: "bloat"}, 1175 }, 1176 } 1177 ) 1178 1179 func newTableCharts(tbl *tableMetrics) *module.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 *module.Chart, tbl *tableMetrics) *module.Chart { 1195 chart = chart.Copy() 1196 chart.ID = fmt.Sprintf(chart.ID, tbl.name, tbl.db, tbl.schema) 1197 chart.Labels = []module.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 (p *Postgres) addNewTableCharts(tbl *tableMetrics) { 1213 charts := newTableCharts(tbl) 1214 if err := p.Charts().Add(*charts...); err != nil { 1215 p.Warning(err) 1216 } 1217 } 1218 1219 func (p *Postgres) addTableLastAutoVacuumAgoChart(tbl *tableMetrics) { 1220 chart := newTableChart(tableAutoVacuumSinceTimeChartTmpl.Copy(), tbl) 1221 1222 if err := p.Charts().Add(chart); err != nil { 1223 p.Warning(err) 1224 } 1225 } 1226 1227 func (p *Postgres) addTableLastVacuumAgoChart(tbl *tableMetrics) { 1228 chart := newTableChart(tableVacuumSinceTimeChartTmpl.Copy(), tbl) 1229 1230 if err := p.Charts().Add(chart); err != nil { 1231 p.Warning(err) 1232 } 1233 } 1234 1235 func (p *Postgres) addTableLastAutoAnalyzeAgoChart(tbl *tableMetrics) { 1236 chart := newTableChart(tableAutoAnalyzeSinceTimeChartTmpl.Copy(), tbl) 1237 1238 if err := p.Charts().Add(chart); err != nil { 1239 p.Warning(err) 1240 } 1241 } 1242 1243 func (p *Postgres) addTableLastAnalyzeAgoChart(tbl *tableMetrics) { 1244 chart := newTableChart(tableAnalyzeSinceTimeChartTmpl.Copy(), tbl) 1245 1246 if err := p.Charts().Add(chart); err != nil { 1247 p.Warning(err) 1248 } 1249 } 1250 1251 func (p *Postgres) addTableIOChartsCharts(tbl *tableMetrics) { 1252 charts := module.Charts{ 1253 newTableChart(tableCacheIORatioChartTmpl.Copy(), tbl), 1254 newTableChart(tableIORateChartTmpl.Copy(), tbl), 1255 } 1256 1257 if err := p.Charts().Add(charts...); err != nil { 1258 p.Warning(err) 1259 } 1260 } 1261 1262 func (p *Postgres) addTableIndexIOCharts(tbl *tableMetrics) { 1263 charts := module.Charts{ 1264 newTableChart(tableIndexCacheIORatioChartTmpl.Copy(), tbl), 1265 newTableChart(tableIndexIORateChartTmpl.Copy(), tbl), 1266 } 1267 1268 if err := p.Charts().Add(charts...); err != nil { 1269 p.Warning(err) 1270 } 1271 } 1272 1273 func (p *Postgres) addTableTOASTIOCharts(tbl *tableMetrics) { 1274 charts := module.Charts{ 1275 newTableChart(tableTOASCacheIORatioChartTmpl.Copy(), tbl), 1276 newTableChart(tableTOASTIORateChartTmpl.Copy(), tbl), 1277 } 1278 1279 if err := p.Charts().Add(charts...); err != nil { 1280 p.Warning(err) 1281 } 1282 } 1283 1284 func (p *Postgres) addTableTOASTIndexIOCharts(tbl *tableMetrics) { 1285 charts := module.Charts{ 1286 newTableChart(tableTOASTIndexCacheIORatioChartTmpl.Copy(), tbl), 1287 newTableChart(tableTOASTIndexIORateChartTmpl.Copy(), tbl), 1288 } 1289 1290 if err := p.Charts().Add(charts...); err != nil { 1291 p.Warning(err) 1292 } 1293 } 1294 1295 func (p *Postgres) removeTableCharts(tbl *tableMetrics) { 1296 prefix := fmt.Sprintf("table_%s_db_%s_schema_%s", tbl.name, tbl.db, tbl.schema) 1297 for _, c := range *p.Charts() { 1298 if strings.HasPrefix(c.ID, prefix) { 1299 c.MarkRemove() 1300 c.MarkNotCreated() 1301 } 1302 } 1303 } 1304 1305 var ( 1306 indexChartsTmpl = module.Charts{ 1307 indexSizeChartTmpl.Copy(), 1308 indexBloatSizePercChartTmpl.Copy(), 1309 indexBloatSizeChartTmpl.Copy(), 1310 indexUsageStatusChartTmpl.Copy(), 1311 } 1312 indexSizeChartTmpl = module.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: module.Dims{ 1320 {ID: "index_%s_table_%s_db_%s_schema_%s_size", Name: "size"}, 1321 }, 1322 } 1323 indexBloatSizePercChartTmpl = module.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: module.Dims{ 1331 {ID: "index_%s_table_%s_db_%s_schema_%s_bloat_size_perc", Name: "bloat"}, 1332 }, 1333 Vars: module.Vars{ 1334 {ID: "index_%s_table_%s_db_%s_schema_%s_size", Name: "index_size"}, 1335 }, 1336 } 1337 indexBloatSizeChartTmpl = module.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: module.Dims{ 1345 {ID: "index_%s_table_%s_db_%s_schema_%s_bloat_size", Name: "bloat"}, 1346 }, 1347 } 1348 indexUsageStatusChartTmpl = module.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: module.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 (p *Postgres) 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 = []module.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 := p.Charts().Add(*charts...); err != nil { 1388 p.Warning(err) 1389 } 1390 } 1391 1392 func (p *Postgres) 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 *p.Charts() { 1395 if strings.HasPrefix(c.ID, prefix) { 1396 c.MarkRemove() 1397 c.MarkNotCreated() 1398 } 1399 } 1400 }