Skip to content

Commit 2ca1798

Browse files
committed
Add a collector to gather metrics on WAL size
Signed-off-by: Tom Hughes <[email protected]>
1 parent 099d3dd commit 2ca1798

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed

collector/pg_wal.go

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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+
14+
package collector
15+
16+
import (
17+
"context"
18+
19+
"github.com/prometheus/client_golang/prometheus"
20+
)
21+
22+
const walSubsystem = "wal"
23+
24+
func init() {
25+
registerCollector(walSubsystem, defaultEnabled, NewPGWALCollector)
26+
}
27+
28+
type PGWALCollector struct {
29+
}
30+
31+
func NewPGWALCollector(config collectorConfig) (Collector, error) {
32+
return &PGWALCollector{}, nil
33+
}
34+
35+
var (
36+
pgWALSegments = prometheus.NewDesc(
37+
prometheus.BuildFQName(
38+
namespace,
39+
walSubsystem,
40+
"segments",
41+
),
42+
"Number of WAL segments",
43+
[]string{}, nil,
44+
)
45+
pgWALSize = prometheus.NewDesc(
46+
prometheus.BuildFQName(
47+
namespace,
48+
walSubsystem,
49+
"size_bytes",
50+
),
51+
"Total size of WAL segments",
52+
[]string{}, nil,
53+
)
54+
55+
pgWALQuery = `
56+
SELECT
57+
COUNT(*) AS segments,
58+
SUM(size) AS size
59+
FROM pg_ls_waldir()
60+
WHERE name ~ '^[0-9A-F]{24}$'`
61+
)
62+
63+
func (c PGWALCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
64+
db := instance.getDB()
65+
row := db.QueryRowContext(ctx,
66+
pgWALQuery,
67+
)
68+
69+
var segments uint64
70+
var size uint64
71+
err := row.Scan(&segments, &size)
72+
if err != nil {
73+
return err
74+
}
75+
ch <- prometheus.MustNewConstMetric(
76+
pgWALSegments,
77+
prometheus.GaugeValue, float64(segments),
78+
)
79+
ch <- prometheus.MustNewConstMetric(
80+
pgWALSize,
81+
prometheus.GaugeValue, float64(size),
82+
)
83+
return nil
84+
}

collector/pg_wal_test.go

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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+
package collector
14+
15+
import (
16+
"context"
17+
"testing"
18+
19+
"github.com/DATA-DOG/go-sqlmock"
20+
"github.com/prometheus/client_golang/prometheus"
21+
dto "github.com/prometheus/client_model/go"
22+
"github.com/smartystreets/goconvey/convey"
23+
)
24+
25+
func TestPgWALCollector(t *testing.T) {
26+
db, mock, err := sqlmock.New()
27+
if err != nil {
28+
t.Fatalf("Error opening a stub db connection: %s", err)
29+
}
30+
defer db.Close()
31+
32+
inst := &instance{db: db}
33+
34+
columns := []string{"segments", "size"}
35+
rows := sqlmock.NewRows(columns).
36+
AddRow(47, 788529152)
37+
mock.ExpectQuery(sanitizeQuery(pgWALQuery)).WillReturnRows(rows)
38+
39+
ch := make(chan prometheus.Metric)
40+
go func() {
41+
defer close(ch)
42+
c := PGWALCollector{}
43+
44+
if err := c.Update(context.Background(), inst, ch); err != nil {
45+
t.Errorf("Error calling PGWALCollector.Update: %s", err)
46+
}
47+
}()
48+
49+
expected := []MetricResult{
50+
{labels: labelMap{}, value: 47, metricType: dto.MetricType_GAUGE},
51+
{labels: labelMap{}, value: 788529152, metricType: dto.MetricType_GAUGE},
52+
}
53+
54+
convey.Convey("Metrics comparison", t, func() {
55+
for _, expect := range expected {
56+
m := readMetric(<-ch)
57+
convey.So(expect, convey.ShouldResemble, m)
58+
}
59+
})
60+
if err := mock.ExpectationsWereMet(); err != nil {
61+
t.Errorf("there were unfulfilled exceptions: %s", err)
62+
}
63+
}

0 commit comments

Comments
 (0)