pangolin_exporter
136 строк · 3.6 Кб
1// Copyright 2023 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package collector
15
16import (
17"context"
18"database/sql"
19
20"github.com/go-kit/log"
21"github.com/prometheus/client_golang/prometheus"
22)
23
24const replicationSlotSubsystem = "replication_slot"
25
26func init() {
27registerCollector(replicationSlotSubsystem, defaultEnabled, NewPGReplicationSlotCollector)
28}
29
30type PGReplicationSlotCollector struct {
31log log.Logger
32}
33
34func NewPGReplicationSlotCollector(config collectorConfig) (Collector, error) {
35return &PGReplicationSlotCollector{log: config.logger}, nil
36}
37
38var (
39pgReplicationSlotCurrentWalDesc = prometheus.NewDesc(
40prometheus.BuildFQName(
41namespace,
42replicationSlotSubsystem,
43"slot_current_wal_lsn",
44),
45"current wal lsn value",
46[]string{"slot_name", "slot_type"}, nil,
47)
48pgReplicationSlotCurrentFlushDesc = prometheus.NewDesc(
49prometheus.BuildFQName(
50namespace,
51replicationSlotSubsystem,
52"slot_confirmed_flush_lsn",
53),
54"last lsn confirmed flushed to the replication slot",
55[]string{"slot_name", "slot_type"}, nil,
56)
57pgReplicationSlotIsActiveDesc = prometheus.NewDesc(
58prometheus.BuildFQName(
59namespace,
60replicationSlotSubsystem,
61"slot_is_active",
62),
63"whether the replication slot is active or not",
64[]string{"slot_name", "slot_type"}, nil,
65)
66
67pgReplicationSlotQuery = `SELECT
68slot_name,
69slot_type,
70CASE WHEN pg_is_in_recovery() THEN
71pg_last_wal_receive_lsn() - '0/0'
72ELSE
73pg_current_wal_lsn() - '0/0'
74END AS current_wal_lsn,
75COALESCE(confirmed_flush_lsn, '0/0') - '0/0' AS confirmed_flush_lsn,
76active
77FROM pg_replication_slots;`
78)
79
80func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
81db := instance.getDB()
82rows, err := db.QueryContext(ctx,
83pgReplicationSlotQuery)
84if err != nil {
85return err
86}
87defer rows.Close()
88
89for rows.Next() {
90var slotName sql.NullString
91var slotType sql.NullString
92var walLSN sql.NullFloat64
93var flushLSN sql.NullFloat64
94var isActive sql.NullBool
95if err := rows.Scan(&slotName, &slotType, &walLSN, &flushLSN, &isActive); err != nil {
96return err
97}
98
99isActiveValue := 0.0
100if isActive.Valid && isActive.Bool {
101isActiveValue = 1.0
102}
103slotNameLabel := "unknown"
104if slotName.Valid {
105slotNameLabel = slotName.String
106}
107slotTypeLabel := "unknown"
108if slotType.Valid {
109slotTypeLabel = slotType.String
110}
111
112var walLSNMetric float64
113if walLSN.Valid {
114walLSNMetric = walLSN.Float64
115}
116ch <- prometheus.MustNewConstMetric(
117pgReplicationSlotCurrentWalDesc,
118prometheus.GaugeValue, walLSNMetric, slotNameLabel, slotTypeLabel,
119)
120if isActive.Valid && isActive.Bool {
121var flushLSNMetric float64
122if flushLSN.Valid {
123flushLSNMetric = flushLSN.Float64
124}
125ch <- prometheus.MustNewConstMetric(
126pgReplicationSlotCurrentFlushDesc,
127prometheus.GaugeValue, flushLSNMetric, slotNameLabel, slotTypeLabel,
128)
129}
130ch <- prometheus.MustNewConstMetric(
131pgReplicationSlotIsActiveDesc,
132prometheus.GaugeValue, isActiveValue, slotNameLabel, slotTypeLabel,
133)
134}
135return rows.Err()
136}
137