// 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" "database/sql" "github.com/prometheus/client_golang/prometheus" ) const bgWriterSubsystem = "stat_bgwriter" func init() { registerCollector(bgWriterSubsystem, defaultEnabled, NewPGStatBGWriterCollector) } type PGStatBGWriterCollector struct { } func NewPGStatBGWriterCollector(collectorConfig) (Collector, error) { return &PGStatBGWriterCollector{}, nil } var ( statBGWriterCheckpointsTimedDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_timed_total"), "Number of scheduled checkpoints that have been performed", []string{}, prometheus.Labels{}, ) statBGWriterCheckpointsReqDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_req_total"), "Number of requested checkpoints that have been performed", []string{}, prometheus.Labels{}, ) statBGWriterCheckpointsReqTimeDesc = 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{}, prometheus.Labels{}, ) statBGWriterCheckpointsSyncTimeDesc = 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{}, prometheus.Labels{}, ) statBGWriterBuffersCheckpointDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_checkpoint_total"), "Number of buffers written during checkpoints", []string{}, prometheus.Labels{}, ) statBGWriterBuffersCleanDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_clean_total"), "Number of buffers written by the background writer", []string{}, prometheus.Labels{}, ) statBGWriterMaxwrittenCleanDesc = 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{}, prometheus.Labels{}, ) statBGWriterBuffersBackendDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_backend_total"), "Number of buffers written directly by a backend", []string{}, prometheus.Labels{}, ) statBGWriterBuffersBackendFsyncDesc = 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{}, prometheus.Labels{}, ) statBGWriterBuffersAllocDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_alloc_total"), "Number of buffers allocated", []string{}, prometheus.Labels{}, ) statBGWriterStatsResetDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "stats_reset_total"), "Time at which these statistics were last reset", []string{}, prometheus.Labels{}, ) statBGWriterQuery = `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;` ) func (PGStatBGWriterCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { db := instance.getDB() row := db.QueryRowContext(ctx, statBGWriterQuery) var cpt, cpr, bcp, bc, mwc, bb, bbf, ba sql.NullInt64 var cpwt, cpst sql.NullFloat64 var sr sql.NullTime err := row.Scan(&cpt, &cpr, &cpwt, &cpst, &bcp, &bc, &mwc, &bb, &bbf, &ba, &sr) if err != nil { return err } cptMetric := 0.0 if cpt.Valid { cptMetric = float64(cpt.Int64) } ch <- prometheus.MustNewConstMetric( statBGWriterCheckpointsTimedDesc, prometheus.CounterValue, cptMetric, ) cprMetric := 0.0 if cpr.Valid { cprMetric = float64(cpr.Int64) } ch <- prometheus.MustNewConstMetric( statBGWriterCheckpointsReqDesc, prometheus.CounterValue, cprMetric, ) cpwtMetric := 0.0 if cpwt.Valid { cpwtMetric = float64(cpwt.Float64) } ch <- prometheus.MustNewConstMetric( statBGWriterCheckpointsReqTimeDesc, prometheus.CounterValue, cpwtMetric, ) cpstMetric := 0.0 if cpst.Valid { cpstMetric = float64(cpst.Float64) } ch <- prometheus.MustNewConstMetric( statBGWriterCheckpointsSyncTimeDesc, prometheus.CounterValue, cpstMetric, ) bcpMetric := 0.0 if bcp.Valid { bcpMetric = float64(bcp.Int64) } ch <- prometheus.MustNewConstMetric( statBGWriterBuffersCheckpointDesc, prometheus.CounterValue, bcpMetric, ) bcMetric := 0.0 if bc.Valid { bcMetric = float64(bc.Int64) } ch <- prometheus.MustNewConstMetric( statBGWriterBuffersCleanDesc, prometheus.CounterValue, bcMetric, ) mwcMetric := 0.0 if mwc.Valid { mwcMetric = float64(mwc.Int64) } ch <- prometheus.MustNewConstMetric( statBGWriterMaxwrittenCleanDesc, prometheus.CounterValue, mwcMetric, ) bbMetric := 0.0 if bb.Valid { bbMetric = float64(bb.Int64) } ch <- prometheus.MustNewConstMetric( statBGWriterBuffersBackendDesc, prometheus.CounterValue, bbMetric, ) bbfMetric := 0.0 if bbf.Valid { bbfMetric = float64(bbf.Int64) } ch <- prometheus.MustNewConstMetric( statBGWriterBuffersBackendFsyncDesc, prometheus.CounterValue, bbfMetric, ) baMetric := 0.0 if ba.Valid { baMetric = float64(ba.Int64) } ch <- prometheus.MustNewConstMetric( statBGWriterBuffersAllocDesc, prometheus.CounterValue, baMetric, ) srMetric := 0.0 if sr.Valid { srMetric = float64(sr.Time.Unix()) } ch <- prometheus.MustNewConstMetric( statBGWriterStatsResetDesc, prometheus.CounterValue, srMetric, ) return nil }