Skip to content

Commit

Permalink
pg stat statements
Browse files Browse the repository at this point in the history
  • Loading branch information
jackmarsh committed Feb 9, 2023
1 parent 76b3704 commit b4923b0
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 24 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

scripts.txt

# Entries below this point are managed by Please (DO NOT EDIT)
plz-out
.plzconfig.local
1 change: 1 addition & 0 deletions exporter/collectors/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ go_library(
srcs = [
"collector.go",
"pg_stat_activity.go",
"pg_stat_statements.go",
"pg_stat_user_table.go",
],
visibility = ["PUBLIC"],
Expand Down
4 changes: 3 additions & 1 deletion exporter/collectors/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
namespace = "pg_stat"
userTablesSubSystem = "user_tables"
activitySubSystem = "activity"
statementsSubSystem = "statements"
)

// Collector wraps the prometheus.Collector.
Expand All @@ -21,7 +22,8 @@ type Collector interface {
// DefaultCollectors specifies the list of default collectors.
func DefaultCollectors(db *db.Client) []Collector {
return []Collector{
NewPgStatUserTableCollector(db),
NewPgStatActivityCollector(db),
NewPgStatStatementsCollector(db),
NewPgStatUserTableCollector(db),
}
}
223 changes: 223 additions & 0 deletions exporter/collectors/pg_stat_statements.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
package collectors

import (
"context"
"fmt"
"sync"

"github.com/odonate/postgres-exporter/exporter/db"
"github.com/prometheus/client_golang/prometheus"
)

// PgStatStatementsCollector collects from pg_stat_user_tables.
type PgStatStatementsCollector struct {
db *db.Client
mutex sync.RWMutex

calls *prometheus.Desc
totalTimeSeconds *prometheus.Desc
minTimeSeconds *prometheus.Desc
maxTimeSeconds *prometheus.Desc
meanTimeSeconds *prometheus.Desc
stdDevTimeSeconds *prometheus.Desc
rows *prometheus.Desc
sharedBlksHit *prometheus.Desc
sharedBlksRead *prometheus.Desc
sharedBlksDirtied *prometheus.Desc
sharedBlksWritten *prometheus.Desc
localBlksHit *prometheus.Desc
localBlksRead *prometheus.Desc
localBlksDirtied *prometheus.Desc
localBlksWritten *prometheus.Desc
tempBlksRead *prometheus.Desc
tempBlksWritten *prometheus.Desc
blkReadTimeSeconds *prometheus.Desc
blkWriteTimeSeconds *prometheus.Desc
}

// NewPgStatStatementsCollector instantiates and returns a new PgStatUserTableCollector.
func NewPgStatStatementsCollector(db *db.Client) *PgStatStatementsCollector {
variableLabels := []string{"rolname", "datname", "queryid"}
return &PgStatStatementsCollector{
db: db,

calls: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "calls"),
"",
variableLabels,
nil,
),
totalTimeSeconds: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "total_time_seconds"),
"",
variableLabels,
nil,
),
minTimeSeconds: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "min_time_seconds"),
"",
variableLabels,
nil,
),
maxTimeSeconds: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "max_time_seconds"),
"",
variableLabels,
nil,
),
meanTimeSeconds: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "mean_time_seconds"),
"",
variableLabels,
nil,
),
stdDevTimeSeconds: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "std_dev_time_seconds"),
"",
variableLabels,
nil,
),
rows: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "rows"),
"",
variableLabels,
nil,
),
sharedBlksHit: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "shared_blks_hit"),
"",
variableLabels,
nil,
),
sharedBlksRead: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "shared_blks_read"),
"",
variableLabels,
nil,
),
sharedBlksDirtied: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "shared_blks_dirtied"),
"",
variableLabels,
nil,
),
sharedBlksWritten: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "shared_blks_written"),
"",
variableLabels,
nil,
),
localBlksHit: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "local_blks_hit"),
"",
variableLabels,
nil,
),
localBlksRead: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "local_blks_read"),
"",
variableLabels,
nil,
),
localBlksDirtied: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "local_blks_dirtied"),
"",
variableLabels,
nil,
),
localBlksWritten: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "local_blks_written"),
"",
variableLabels,
nil,
),
tempBlksRead: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "templ_blks_read"),
"",
variableLabels,
nil,
),
tempBlksWritten: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "temp_blks_written"),
"",
variableLabels,
nil,
),
blkReadTimeSeconds: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "blk_read_time_seconds"),
"",
variableLabels,
nil,
),
blkWriteTimeSeconds: prometheus.NewDesc(
prometheus.BuildFQName(namespace, statementsSubSystem, "blk_write_time_seconds"),
"",
variableLabels,
nil,
),
}
}

// Describe implements the prometheus.Collector.
func (c *PgStatStatementsCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.calls
ch <- c.totalTimeSeconds
ch <- c.minTimeSeconds
ch <- c.maxTimeSeconds
ch <- c.meanTimeSeconds
ch <- c.stdDevTimeSeconds
ch <- c.rows
ch <- c.sharedBlksHit
ch <- c.sharedBlksRead
ch <- c.sharedBlksDirtied
ch <- c.sharedBlksWritten
ch <- c.localBlksHit
ch <- c.localBlksRead
ch <- c.localBlksDirtied
ch <- c.localBlksWritten
ch <- c.tempBlksRead
ch <- c.tempBlksWritten
ch <- c.blkReadTimeSeconds
ch <- c.blkWriteTimeSeconds
}

// Collect implements the promtheus.Collector.
func (c *PgStatStatementsCollector) Collect(ch chan<- prometheus.Metric) {
c.mutex.Lock()
defer c.mutex.Unlock()
_ = c.Scrape(ch)
}

// Scrape implements our Scraper interfacc.
func (c *PgStatStatementsCollector) Scrape(ch chan<- prometheus.Metric) error {
c.mutex.Lock()
defer c.mutex.Unlock()

statementStats, err := c.db.SelectPgStatStatements(context.Background())
if err != nil {
return fmt.Errorf("statement stats: %w", err)
}

for _, stat := range statementStats {
ch <- prometheus.MustNewConstMetric(c.calls, prometheus.CounterValue, float64(stat.Calls), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.totalTimeSeconds, prometheus.CounterValue, float64(stat.TotalTimeSeconds), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.minTimeSeconds, prometheus.GaugeValue, float64(stat.MinTimeSeconds), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.maxTimeSeconds, prometheus.GaugeValue, float64(stat.MaxTimeSeconds), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.meanTimeSeconds, prometheus.GaugeValue, float64(stat.MeanTimeSeconds), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.stdDevTimeSeconds, prometheus.GaugeValue, float64(stat.StdDevTimeSeconds), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.rows, prometheus.CounterValue, float64(stat.Rows), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.sharedBlksHit, prometheus.CounterValue, float64(stat.SharedBlksHit), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.sharedBlksRead, prometheus.CounterValue, float64(stat.SharedBlksRead), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.sharedBlksDirtied, prometheus.CounterValue, float64(stat.SharedBlksDirtied), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.sharedBlksWritten, prometheus.CounterValue, float64(stat.SharedBlksWritten), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.localBlksHit, prometheus.CounterValue, float64(stat.LocalBlksHit), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.localBlksRead, prometheus.CounterValue, float64(stat.LocalBlksRead), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.localBlksDirtied, prometheus.CounterValue, float64(stat.LocalBlksDirtied), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.localBlksWritten, prometheus.CounterValue, float64(stat.LocalBlksWritten), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.tempBlksRead, prometheus.CounterValue, float64(stat.TempBlksRead), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.tempBlksWritten, prometheus.CounterValue, float64(stat.TempBlksWritten), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.blkReadTimeSeconds, prometheus.CounterValue, float64(stat.BlkReadTimeSeconds), stat.RolName, stat.DatName, stat.QueryID)
ch <- prometheus.MustNewConstMetric(c.blkWriteTimeSeconds, prometheus.CounterValue, float64(stat.BlkWriteTimeSeconds), stat.RolName, stat.DatName, stat.QueryID)
}
return nil
}
44 changes: 22 additions & 22 deletions exporter/db/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,26 @@ type PgStatUserTable struct {

// PgStatStatement contiains information on user tables.
type PgStatStatement struct {
DatName string `db:"datname"`
SchemaName string `db:"schemaname"`
RelName string `db:"relname"`
SeqScan int `db:"seq_scan"`
SeqTupRead int `db:"seq_tup_read"`
IndexScan int `db:"idx_scan"`
IndexTupFetch int `db:"idx_tup_fetch"`
NTupInsert int `db:"n_tup_ins"`
NTupUpdate int `db:"n_tup_upd"`
NTupDelete int `db:"n_tup_del"`
NTupHotUpdate int `db:"n_tup_hot_upd"`
NLiveTup int `db:"n_live_tup"`
NDeadTup int `db:"n_dead_tup"`
NModSinceAnalyze int `db:"n_mod_since_analyze"`
LastVacuum pgtype.Timestamptz `db:"last_vacuum"`
LastAutoVacuum pgtype.Timestamptz `db:"last_autovacuum"`
LastAnalyze pgtype.Timestamptz `db:"last_analyze"`
LastAutoAnalyze pgtype.Timestamptz `db:"last_autoanalyze"`
VacuumCount int `db:"vacuum_count"`
AutoVacuumCount int `db:"autovacuum_count"`
AnalyzeCount int `db:"analyze_count"`
AutoAnalyzeCount int `db:"autoanalyze_count"`
RolName string `db:"rolname"`
DatName string `db:"datname"`
QueryID string `db:"queryid"`
Calls int `db:"calls"`
TotalTimeSeconds int `db:"total_time_seconds"`
MinTimeSeconds int `db:"min_time_seconds"`
MaxTimeSeconds int `db:"max_time_seconds"`
MeanTimeSeconds int `db:"mean_time_seconds"`
StdDevTimeSeconds int `db:"std_dev_time_seconds"`
Rows int `db:"rows"`
SharedBlksHit int `db:"shared_blks_hit"`
SharedBlksRead int `db:"shared_blks_read"`
SharedBlksDirtied int `db:"shared_blks_dirtied"`
SharedBlksWritten int `db:"shared_blks_written"`
LocalBlksHit int `db:"local_blks_hit"`
LocalBlksRead int `db:"local_blks_read"`
LocalBlksDirtied int `db:"local_blks_dirtied"`
LocalBlksWritten int `db:"local_blks_written"`
TempBlksRead int `db:"temp_blks_read"`
TempBlksWritten int `db:"temp_blks_written"`
BlkReadTimeSeconds int `db:"blk_read_time_seconds"`
BlkWriteTimeSeconds int `db:"blk_write_time_seconds"`
}
6 changes: 5 additions & 1 deletion scripts.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@

### Linting

gofmt -w ~/postgres-exporter/exporter

### Vendorising

gofmt -w ~/postgres-exporter

0 comments on commit b4923b0

Please sign in to comment.