You've already forked postgres_exporter
mirror of
https://github.com/prometheus-community/postgres_exporter.git
synced 2025-11-25 10:43:13 +03:00
Merge pull request #556 from sysadmind/pg_stat_bgwriter_refactor
refactor pg_stat_bgwriter metrics into standalone collector
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
## master / unreleased
|
## master / unreleased
|
||||||
|
|
||||||
|
* [CHANGE] pg_stat_bgwriter counter metrics had the `_total` suffix added #556
|
||||||
* [ENHANCEMENT] Add pg_database_size_bytes metric #613
|
* [ENHANCEMENT] Add pg_database_size_bytes metric #613
|
||||||
|
|
||||||
## 0.10.1 / 2022-01-14
|
## 0.10.1 / 2022-01-14
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra
|
|||||||
* `help`
|
* `help`
|
||||||
Show context-sensitive help (also try --help-long and --help-man).
|
Show context-sensitive help (also try --help-long and --help-man).
|
||||||
|
|
||||||
|
* `collector.database`
|
||||||
|
Enable the pg_database collector. Default is `enabled`
|
||||||
|
|
||||||
|
* `collector.bgwriter`
|
||||||
|
Enable the pg_stat_bgwriter collector. Default is `enabled`
|
||||||
|
|
||||||
* `web.listen-address`
|
* `web.listen-address`
|
||||||
Address to listen on for web interface and telemetry. Default is `:9187`.
|
Address to listen on for web interface and telemetry. Default is `:9187`.
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,11 @@ func main() {
|
|||||||
|
|
||||||
prometheus.MustRegister(exporter)
|
prometheus.MustRegister(exporter)
|
||||||
|
|
||||||
pe, err := collector.NewPostgresCollector(logger, dsn)
|
pe, err := collector.NewPostgresCollector(
|
||||||
|
logger,
|
||||||
|
dsn,
|
||||||
|
[]string{},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Error(logger).Log("msg", "Failed to create PostgresCollector", "err", err.Error())
|
level.Error(logger).Log("msg", "Failed to create PostgresCollector", "err", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
@@ -163,23 +163,6 @@ func dumpMaps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var builtinMetricMaps = map[string]intermediateMetricMap{
|
var builtinMetricMaps = map[string]intermediateMetricMap{
|
||||||
"pg_stat_bgwriter": {
|
|
||||||
map[string]ColumnMapping{
|
|
||||||
"checkpoints_timed": {COUNTER, "Number of scheduled checkpoints that have been performed", nil, nil},
|
|
||||||
"checkpoints_req": {COUNTER, "Number of requested checkpoints that have been performed", nil, nil},
|
|
||||||
"checkpoint_write_time": {COUNTER, "Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in milliseconds", nil, nil},
|
|
||||||
"checkpoint_sync_time": {COUNTER, "Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in milliseconds", nil, nil},
|
|
||||||
"buffers_checkpoint": {COUNTER, "Number of buffers written during checkpoints", nil, nil},
|
|
||||||
"buffers_clean": {COUNTER, "Number of buffers written by the background writer", nil, nil},
|
|
||||||
"maxwritten_clean": {COUNTER, "Number of times the background writer stopped a cleaning scan because it had written too many buffers", nil, nil},
|
|
||||||
"buffers_backend": {COUNTER, "Number of buffers written directly by a backend", nil, nil},
|
|
||||||
"buffers_backend_fsync": {COUNTER, "Number of times a backend had to execute its own fsync call (normally the background writer handles those even when the backend does its own write)", nil, nil},
|
|
||||||
"buffers_alloc": {COUNTER, "Number of buffers allocated", nil, nil},
|
|
||||||
"stats_reset": {COUNTER, "Time at which these statistics were last reset", nil, nil},
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
0,
|
|
||||||
},
|
|
||||||
"pg_stat_database": {
|
"pg_stat_database": {
|
||||||
map[string]ColumnMapping{
|
map[string]ColumnMapping{
|
||||||
"datid": {LABEL, "OID of a database", nil, nil},
|
"datid": {LABEL, "OID of a database", nil, nil},
|
||||||
|
|||||||
@@ -89,8 +89,21 @@ type PostgresCollector struct {
|
|||||||
servers map[string]*server
|
servers map[string]*server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Option func(*PostgresCollector) error
|
||||||
|
|
||||||
// NewPostgresCollector creates a new PostgresCollector.
|
// NewPostgresCollector creates a new PostgresCollector.
|
||||||
func NewPostgresCollector(logger log.Logger, dsns []string, filters ...string) (*PostgresCollector, error) {
|
func NewPostgresCollector(logger log.Logger, dsns []string, filters []string, options ...Option) (*PostgresCollector, error) {
|
||||||
|
p := &PostgresCollector{
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
// Apply options to customize the collector
|
||||||
|
for _, o := range options {
|
||||||
|
err := o(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
f := make(map[string]bool)
|
f := make(map[string]bool)
|
||||||
for _, filter := range filters {
|
for _, filter := range filters {
|
||||||
enabled, exist := collectorState[filter]
|
enabled, exist := collectorState[filter]
|
||||||
@@ -121,48 +134,49 @@ func NewPostgresCollector(logger log.Logger, dsns []string, filters ...string) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.Collectors = collectors
|
||||||
|
|
||||||
servers := make(map[string]*server)
|
servers := make(map[string]*server)
|
||||||
for _, dsn := range dsns {
|
for _, dsn := range dsns {
|
||||||
s, err := makeServer(dsn)
|
s, err := makeServer(dsn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
servers[dsn] = s
|
servers[dsn] = s
|
||||||
}
|
}
|
||||||
|
|
||||||
return &PostgresCollector{
|
p.servers = servers
|
||||||
Collectors: collectors,
|
|
||||||
logger: logger,
|
return p, nil
|
||||||
servers: servers,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe implements the prometheus.Collector interface.
|
// Describe implements the prometheus.Collector interface.
|
||||||
func (n PostgresCollector) Describe(ch chan<- *prometheus.Desc) {
|
func (p PostgresCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||||
ch <- scrapeDurationDesc
|
ch <- scrapeDurationDesc
|
||||||
ch <- scrapeSuccessDesc
|
ch <- scrapeSuccessDesc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect implements the prometheus.Collector interface.
|
// Collect implements the prometheus.Collector interface.
|
||||||
func (n PostgresCollector) Collect(ch chan<- prometheus.Metric) {
|
func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(n.servers))
|
wg.Add(len(p.servers))
|
||||||
for _, s := range n.servers {
|
for _, s := range p.servers {
|
||||||
go func(s *server) {
|
go func(s *server) {
|
||||||
n.subCollect(ctx, s, ch)
|
p.subCollect(ctx, s, ch)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}(s)
|
}(s)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n PostgresCollector) subCollect(ctx context.Context, server *server, ch chan<- prometheus.Metric) {
|
func (p PostgresCollector) subCollect(ctx context.Context, server *server, ch chan<- prometheus.Metric) {
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(n.Collectors))
|
wg.Add(len(p.Collectors))
|
||||||
for name, c := range n.Collectors {
|
for name, c := range p.Collectors {
|
||||||
go func(name string, c Collector) {
|
go func(name string, c Collector) {
|
||||||
execute(ctx, name, c, server, ch, n.logger)
|
execute(ctx, name, c, server, ch, p.logger)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}(name, c)
|
}(name, c)
|
||||||
}
|
}
|
||||||
|
|||||||
212
collector/pg_stat_bgwriter.go
Normal file
212
collector/pg_stat_bgwriter.go
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
// Copyright 2021 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-kit/log"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registerCollector("bgwriter", defaultEnabled, NewPGStatBGWriterCollector)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PGStatBGWriterCollector struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPGStatBGWriterCollector(logger log.Logger) (Collector, error) {
|
||||||
|
return &PGStatBGWriterCollector{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const bgWriterSubsystem = "stat_bgwriter"
|
||||||
|
|
||||||
|
var statBGWriter = map[string]*prometheus.Desc{
|
||||||
|
"checkpoints_timed": prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_timed_total"),
|
||||||
|
"Number of scheduled checkpoints that have been performed",
|
||||||
|
[]string{"server"},
|
||||||
|
prometheus.Labels{},
|
||||||
|
),
|
||||||
|
"checkpoints_req": prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_req_total"),
|
||||||
|
"Number of requested checkpoints that have been performed",
|
||||||
|
[]string{"server"},
|
||||||
|
prometheus.Labels{},
|
||||||
|
),
|
||||||
|
"checkpoint_write_time": prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoint_write_time_total"),
|
||||||
|
"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in milliseconds",
|
||||||
|
[]string{"server"},
|
||||||
|
prometheus.Labels{},
|
||||||
|
),
|
||||||
|
"checkpoint_sync_time": prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoint_sync_time_total"),
|
||||||
|
"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in milliseconds",
|
||||||
|
[]string{"server"},
|
||||||
|
prometheus.Labels{},
|
||||||
|
),
|
||||||
|
"buffers_checkpoint": prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_checkpoint_total"),
|
||||||
|
"Number of buffers written during checkpoints",
|
||||||
|
[]string{"server"},
|
||||||
|
prometheus.Labels{},
|
||||||
|
),
|
||||||
|
"buffers_clean": prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_clean_total"),
|
||||||
|
"Number of buffers written by the background writer",
|
||||||
|
[]string{"server"},
|
||||||
|
prometheus.Labels{},
|
||||||
|
),
|
||||||
|
"maxwritten_clean": prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, bgWriterSubsystem, "maxwritten_clean_total"),
|
||||||
|
"Number of times the background writer stopped a cleaning scan because it had written too many buffers",
|
||||||
|
[]string{"server"},
|
||||||
|
prometheus.Labels{},
|
||||||
|
),
|
||||||
|
"buffers_backend": prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_backend_total"),
|
||||||
|
"Number of buffers written directly by a backend",
|
||||||
|
[]string{"server"},
|
||||||
|
prometheus.Labels{},
|
||||||
|
),
|
||||||
|
"buffers_backend_fsync": prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_backend_fsync_total"),
|
||||||
|
"Number of times a backend had to execute its own fsync call (normally the background writer handles those even when the backend does its own write)",
|
||||||
|
[]string{"server"},
|
||||||
|
prometheus.Labels{},
|
||||||
|
),
|
||||||
|
"buffers_alloc": prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_alloc_total"),
|
||||||
|
"Number of buffers allocated",
|
||||||
|
[]string{"server"},
|
||||||
|
prometheus.Labels{},
|
||||||
|
),
|
||||||
|
"stats_reset": prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, bgWriterSubsystem, "stats_reset_total"),
|
||||||
|
"Time at which these statistics were last reset",
|
||||||
|
[]string{"server"},
|
||||||
|
prometheus.Labels{},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
func (PGStatBGWriterCollector) Update(ctx context.Context, server *server, ch chan<- prometheus.Metric) error {
|
||||||
|
db, err := server.GetDB()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
row := db.QueryRowContext(ctx,
|
||||||
|
`SELECT
|
||||||
|
checkpoints_timed
|
||||||
|
,checkpoints_req
|
||||||
|
,checkpoint_write_time
|
||||||
|
,checkpoint_sync_time
|
||||||
|
,buffers_checkpoint
|
||||||
|
,buffers_clean
|
||||||
|
,maxwritten_clean
|
||||||
|
,buffers_backend
|
||||||
|
,buffers_backend_fsync
|
||||||
|
,buffers_alloc
|
||||||
|
,stats_reset
|
||||||
|
FROM pg_stat_bgwriter;`)
|
||||||
|
|
||||||
|
var cpt int
|
||||||
|
var cpr int
|
||||||
|
var cpwt int
|
||||||
|
var cpst int
|
||||||
|
var bcp int
|
||||||
|
var bc int
|
||||||
|
var mwc int
|
||||||
|
var bb int
|
||||||
|
var bbf int
|
||||||
|
var ba int
|
||||||
|
var sr time.Time
|
||||||
|
|
||||||
|
err = row.Scan(&cpt, &cpr, &cpwt, &cpst, &bcp, &bc, &mwc, &bb, &bbf, &ba, &sr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
statBGWriter["checkpoints_timed"],
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(cpt),
|
||||||
|
server.GetName(),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
statBGWriter["checkpoints_req"],
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(cpr),
|
||||||
|
server.GetName(),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
statBGWriter["checkpoint_write_time"],
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(cpwt),
|
||||||
|
server.GetName(),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
statBGWriter["checkpoint_sync_time"],
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(cpst),
|
||||||
|
server.GetName(),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
statBGWriter["buffers_checkpoint"],
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(bcp),
|
||||||
|
server.GetName(),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
statBGWriter["buffers_clean"],
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(bc),
|
||||||
|
server.GetName(),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
statBGWriter["maxwritten_clean"],
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(mwc),
|
||||||
|
server.GetName(),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
statBGWriter["buffers_backend"],
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(bb),
|
||||||
|
server.GetName(),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
statBGWriter["buffers_backend_fsync"],
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(bbf),
|
||||||
|
server.GetName(),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
statBGWriter["buffers_alloc"],
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(ba),
|
||||||
|
server.GetName(),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
statBGWriter["stats_reset"],
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(sr.Unix()),
|
||||||
|
server.GetName(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -584,7 +584,7 @@
|
|||||||
{
|
{
|
||||||
"alias": "Buffers Allocated",
|
"alias": "Buffers Allocated",
|
||||||
"dsType": "prometheus",
|
"dsType": "prometheus",
|
||||||
"expr": "irate(pg_stat_bgwriter_buffers_alloc{instance='$instance'}[5m])",
|
"expr": "irate(pg_stat_bgwriter_buffers_alloc_total{instance='$instance'}[5m])",
|
||||||
"format": "time_series",
|
"format": "time_series",
|
||||||
"groupBy": [
|
"groupBy": [
|
||||||
{
|
{
|
||||||
@@ -636,7 +636,7 @@
|
|||||||
{
|
{
|
||||||
"alias": "Buffers Allocated",
|
"alias": "Buffers Allocated",
|
||||||
"dsType": "prometheus",
|
"dsType": "prometheus",
|
||||||
"expr": "irate(pg_stat_bgwriter_buffers_backend_fsync{instance='$instance'}[5m])",
|
"expr": "irate(pg_stat_bgwriter_buffers_backend_fsync_total{instance='$instance'}[5m])",
|
||||||
"format": "time_series",
|
"format": "time_series",
|
||||||
"groupBy": [
|
"groupBy": [
|
||||||
{
|
{
|
||||||
@@ -688,7 +688,7 @@
|
|||||||
{
|
{
|
||||||
"alias": "Buffers Allocated",
|
"alias": "Buffers Allocated",
|
||||||
"dsType": "prometheus",
|
"dsType": "prometheus",
|
||||||
"expr": "irate(pg_stat_bgwriter_buffers_backend{instance='$instance'}[5m])",
|
"expr": "irate(pg_stat_bgwriter_buffers_backend_total{instance='$instance'}[5m])",
|
||||||
"format": "time_series",
|
"format": "time_series",
|
||||||
"groupBy": [
|
"groupBy": [
|
||||||
{
|
{
|
||||||
@@ -740,7 +740,7 @@
|
|||||||
{
|
{
|
||||||
"alias": "Buffers Allocated",
|
"alias": "Buffers Allocated",
|
||||||
"dsType": "prometheus",
|
"dsType": "prometheus",
|
||||||
"expr": "irate(pg_stat_bgwriter_buffers_clean{instance='$instance'}[5m])",
|
"expr": "irate(pg_stat_bgwriter_buffers_clean_total{instance='$instance'}[5m])",
|
||||||
"format": "time_series",
|
"format": "time_series",
|
||||||
"groupBy": [
|
"groupBy": [
|
||||||
{
|
{
|
||||||
@@ -792,7 +792,7 @@
|
|||||||
{
|
{
|
||||||
"alias": "Buffers Allocated",
|
"alias": "Buffers Allocated",
|
||||||
"dsType": "prometheus",
|
"dsType": "prometheus",
|
||||||
"expr": "irate(pg_stat_bgwriter_buffers_checkpoint{instance='$instance'}[5m])",
|
"expr": "irate(pg_stat_bgwriter_buffers_checkpoint_total{instance='$instance'}[5m])",
|
||||||
"format": "time_series",
|
"format": "time_series",
|
||||||
"groupBy": [
|
"groupBy": [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user