From d27b514bb9a123b22349ff95ba2eeab27359fdef Mon Sep 17 00:00:00 2001 From: Christoph Berg Date: Tue, 29 Mar 2022 17:55:50 +0200 Subject: [PATCH] WIP: pg_stat_database by PG version support --- collector/models/pgStatDatabase.go | 20 ++++++++++---------- collector/models/pgStatDatabase_gen.go | 20 ++++++++++---------- collector/stat_database.go | 20 +++++++++++++++++--- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/collector/models/pgStatDatabase.go b/collector/models/pgStatDatabase.go index bc2d3ec..b12eeae 100644 --- a/collector/models/pgStatDatabase.go +++ b/collector/models/pgStatDatabase.go @@ -6,7 +6,7 @@ import ( // +metric=slice type PgStatDatabase struct { - tableName struct{} `pg:"pg_stat_database,discard_unknown_columns"` + tableName struct{} `pg:"pg_stat_database"` DatID int64 `pg:"datid" help:"OID of a database" metric:"database_id,type:label"` DatName string `pg:"datname" help:"Name of this database" metric:"database,type:label"` NumBackends int `pg:"numbackends" help:"Number of backends currently connected to this database" metric:"backends,type:gauge"` @@ -23,16 +23,16 @@ type PgStatDatabase struct { TempFiles int64 `pg:"temp_files" help:"Number of temporary files created by queries in this database" metric:"temp_files_total"` TempBytes int64 `pg:"temp_bytes" help:"Total amount of data written to temporary files by queries in this database" metric:"temp_bytes_total"` Deadlocks int64 `pg:"deadlocks" help:"Number of deadlocks detected in this database" metric:"deadlocks_total"` - checksumFailures int64 `pg:"checksum_failures" help:"Number of data page checksum failures detected in this database" metric:"checksum_failures_count"` // new in PG12 - checksumLastFailure time.Time `pg:"checksum_last_failure" help:"Time at which the last data page checksum failure was detected in this database" metric:"checksum_last_failure"` // new in PG12 + ChecksumFailures int64 `pg:"checksum_failures" help:"Number of data page checksum failures detected in this database" metric:"checksum_failures_count"` // new in PG12 + ChecksumLastFailure time.Time `pg:"checksum_last_failure" help:"Time at which the last data page checksum failure was detected in this database" metric:"checksum_last_failure"` // new in PG12 BlkReadTime Milliseconds `pg:"blk_read_time" help:"Time spent reading data file blocks by backends in this database" metric:"blk_read_seconds_total"` BlkWriteTime Milliseconds `pg:"blk_write_time" help:"Time spent writing data file blocks by backends in this database" metric:"blk_write_seconds_total"` - sessionTime Milliseconds `pg:"session_time" help:"Time spent by database sessions in this database, in milliseconds" metric:"session_time_total"` // new in PG14 - activeTime Milliseconds `pg:"active_time" help:"Time spent executing SQL statements in this database, in milliseconds" metric:"active_time_total"` // new in PG14 - idleInTransactionTime Milliseconds `pg:"idle_in_transaction_time" help:"Time spent idling while in a transaction in this database, in milliseconds" metric:"idle_in_transaction_time_total"` // new in PG14 - sessions int64 `pg:"sessions" help:"Total number of sessions established to this database" metric:"sessions_count"` // new in PG14 - sessionsAbandoned int64 `pg:"sessions_abandoned" help:"Number of database sessions to this database that were terminated because connection to the client was lost" metric:"sessions_abandoned_count"` // new in PG14 - sessionsFatal int64 `pg:"sessions_fatal" help:"Number of database sessions to this database that were terminated by fatal errors" metric:"sessions_fatal_count"` // new in PG14 - sessionsKilled int64 `pg:"sessions_killed" help:"Number of database sessions to this database that were terminated by operator intervention" metric:"sessions_killed_count"` // new in PG14 + SessionTime Milliseconds `pg:"session_time" help:"Time spent by database sessions in this database, in milliseconds" metric:"session_time_total"` // new in PG14 + ActiveTime Milliseconds `pg:"active_time" help:"Time spent executing SQL statements in this database, in milliseconds" metric:"active_time_total"` // new in PG14 + IdleInTransactionTime Milliseconds `pg:"idle_in_transaction_time" help:"Time spent idling while in a transaction in this database, in milliseconds" metric:"idle_in_transaction_time_total"` // new in PG14 + Sessions int64 `pg:"sessions" help:"Total number of sessions established to this database" metric:"sessions_count"` // new in PG14 + SessionsAbandoned int64 `pg:"sessions_abandoned" help:"Number of database sessions to this database that were terminated because connection to the client was lost" metric:"sessions_abandoned_count"` // new in PG14 + SessionsFatal int64 `pg:"sessions_fatal" help:"Number of database sessions to this database that were terminated by fatal errors" metric:"sessions_fatal_count"` // new in PG14 + SessionsKilled int64 `pg:"sessions_killed" help:"Number of database sessions to this database that were terminated by operator intervention" metric:"sessions_killed_count"` // new in PG14 StatsReset time.Time `pg:"stats_reset" help:"Time at which these statistics were last reset"` } diff --git a/collector/models/pgStatDatabase_gen.go b/collector/models/pgStatDatabase_gen.go index d461669..d3d19ca 100644 --- a/collector/models/pgStatDatabase_gen.go +++ b/collector/models/pgStatDatabase_gen.go @@ -140,7 +140,7 @@ func (r *PgStatDatabase) ToMetrics(namespace string, subsystem string, ch chan<- ) // checksum_failures_count (CounterValue) - checksumFailuresCount := float64(r.checksumFailures) + checksumFailuresCount := float64(r.ChecksumFailures) ch <- prometheus.MustNewConstMetric( prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, `checksum_failures_count`), `Number of data page checksum failures detected in this database`, nil, labels, @@ -149,10 +149,10 @@ func (r *PgStatDatabase) ToMetrics(namespace string, subsystem string, ch chan<- // checksum_last_failure (CounterValue) var checksumLastFailure float64 - if r.checksumLastFailure.IsZero() { + if r.ChecksumLastFailure.IsZero() { checksumLastFailure = float64(0) } else { - checksumLastFailure = float64(r.checksumLastFailure.Unix()) + checksumLastFailure = float64(r.ChecksumLastFailure.Unix()) } ch <- prometheus.MustNewConstMetric( prometheus.NewDesc( @@ -177,7 +177,7 @@ func (r *PgStatDatabase) ToMetrics(namespace string, subsystem string, ch chan<- ) // session_time_total (CounterValue) - sessionTimeTotal := r.sessionTime.Seconds() + sessionTimeTotal := r.SessionTime.Seconds() ch <- prometheus.MustNewConstMetric( prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, `session_time_total`), `Time spent by database sessions in this database, in milliseconds`, nil, labels, @@ -185,7 +185,7 @@ func (r *PgStatDatabase) ToMetrics(namespace string, subsystem string, ch chan<- ) // active_time_total (CounterValue) - activeTimeTotal := r.activeTime.Seconds() + activeTimeTotal := r.ActiveTime.Seconds() ch <- prometheus.MustNewConstMetric( prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, `active_time_total`), `Time spent executing SQL statements in this database, in milliseconds`, nil, labels, @@ -193,7 +193,7 @@ func (r *PgStatDatabase) ToMetrics(namespace string, subsystem string, ch chan<- ) // idle_in_transaction_time_total (CounterValue) - idleInTransactionTimeTotal := r.idleInTransactionTime.Seconds() + idleInTransactionTimeTotal := r.IdleInTransactionTime.Seconds() ch <- prometheus.MustNewConstMetric( prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, `idle_in_transaction_time_total`), `Time spent idling while in a transaction in this database, in milliseconds`, nil, labels, @@ -201,7 +201,7 @@ func (r *PgStatDatabase) ToMetrics(namespace string, subsystem string, ch chan<- ) // sessions_count (CounterValue) - sessionsCount := float64(r.sessions) + sessionsCount := float64(r.Sessions) ch <- prometheus.MustNewConstMetric( prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, `sessions_count`), `Total number of sessions established to this database`, nil, labels, @@ -209,7 +209,7 @@ func (r *PgStatDatabase) ToMetrics(namespace string, subsystem string, ch chan<- ) // sessions_abandoned_count (CounterValue) - sessionsAbandonedCount := float64(r.sessionsAbandoned) + sessionsAbandonedCount := float64(r.SessionsAbandoned) ch <- prometheus.MustNewConstMetric( prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, `sessions_abandoned_count`), `Number of database sessions to this database that were terminated because connection to the client was lost`, nil, labels, @@ -217,7 +217,7 @@ func (r *PgStatDatabase) ToMetrics(namespace string, subsystem string, ch chan<- ) // sessions_fatal_count (CounterValue) - sessionsFatalCount := float64(r.sessionsFatal) + sessionsFatalCount := float64(r.SessionsFatal) ch <- prometheus.MustNewConstMetric( prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, `sessions_fatal_count`), `Number of database sessions to this database that were terminated by fatal errors`, nil, labels, @@ -225,7 +225,7 @@ func (r *PgStatDatabase) ToMetrics(namespace string, subsystem string, ch chan<- ) // sessions_killed_count (CounterValue) - sessionsKilledCount := float64(r.sessionsKilled) + sessionsKilledCount := float64(r.SessionsKilled) ch <- prometheus.MustNewConstMetric( prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, `sessions_killed_count`), `Number of database sessions to this database that were terminated by operator intervention`, nil, labels, diff --git a/collector/stat_database.go b/collector/stat_database.go index 9c83eab..72561f1 100644 --- a/collector/stat_database.go +++ b/collector/stat_database.go @@ -2,6 +2,7 @@ package collector import ( "context" + "fmt" "github.com/go-pg/pg/v9" "github.com/prometheus/client_golang/prometheus" @@ -39,12 +40,25 @@ func (ScrapeDatabase) Type() ScrapeType { // Scrape collects data from database connection and sends it over channel as prometheus metric. func (ScrapeDatabase) Scrape(ctx context.Context, db *pg.DB, ch chan<- prometheus.Metric) error { + // we create a query based on the given commandline flags + columns := "numbackends, xact_commit, xact_rollback, blks_read, blks_hit, tup_returned, tup_fetched, tup_inserted, tup_updated, tup_deleted, conflicts, temp_files, temp_bytes, deadlocks, blk_read_time, blk_write_time" + + if pgversion >= 120000 { + columns += ", checksum_failures, checksum_last_failure" + } + + if pgversion >= 140000 { + columns += ", session_time, active_time, idle_in_transaction_time, sessions, sessions_abandoned, sessions_fatal, sessions_killed" + } + + qs := fmt.Sprintf(`SELECT datid, datname, %s, stats_reset FROM pg_stat_database`+ + ` WHERE datname IN (?)`, + columns) + var statDatabase models.PgStatDatabaseSlice - if err := db.ModelContext(ctx, &statDatabase).Where("datname IN (?)", pg.In(collectDatabases)). - Select(); err != nil { + if _, err := db.QueryContext(ctx, &statDatabase, qs, pg.In(collectDatabases)); err != nil { return err } - if err := statDatabase.ToMetrics(namespace, statdatabase, ch); err != nil { return err }