Skip to content

Commit 57a4425

Browse files
feat(lumos): add settings as collector
1 parent 8445a22 commit 57a4425

File tree

6 files changed

+222
-7
lines changed

6 files changed

+222
-7
lines changed

cmd/postgres_exporter/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ import (
2222
"github.com/alecthomas/kingpin/v2"
2323
"github.com/go-kit/log"
2424
"github.com/go-kit/log/level"
25-
"github.com/prometheus-community/postgres_exporter/collector"
26-
"github.com/prometheus-community/postgres_exporter/config"
2725
"github.com/prometheus/client_golang/prometheus"
2826
"github.com/prometheus/client_golang/prometheus/promhttp"
2927
"github.com/prometheus/common/promlog"
3028
"github.com/prometheus/common/promlog/flag"
3129
"github.com/prometheus/common/version"
3230
"github.com/prometheus/exporter-toolkit/web"
3331
"github.com/prometheus/exporter-toolkit/web/kingpinflag"
32+
"github.com/zeet-dev/postgres_exporter/collector"
33+
"github.com/zeet-dev/postgres_exporter/config"
3434
)
3535

3636
var (

cmd/postgres_exporter/pg_setting.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func (s *pgSetting) metric(labels prometheus.Labels) prometheus.Metric {
102102

103103
// Removes units from any of the setting values.
104104
// This is mostly because of a irregularity regarding AWS RDS Aurora
105-
// https://github.com/prometheus-community/postgres_exporter/issues/619
105+
// https://github.com/zeet-dev/postgres_exporter/issues/619
106106
func (s *pgSetting) sanitizeValue() {
107107
for _, unit := range settingUnits {
108108
if strings.HasSuffix(s.setting, unit) {

cmd/postgres_exporter/postgres_exporter_integration_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func (s *IntegrationSuite) TestAllNamespacesReturnResults(c *C) {
8989
}
9090

9191
// TestInvalidDsnDoesntCrash tests that specifying an invalid DSN doesn't crash
92-
// the exporter. Related to https://github.com/prometheus-community/postgres_exporter/issues/93
92+
// the exporter. Related to https://github.com/zeet-dev/postgres_exporter/issues/93
9393
// although not a replication of the scenario.
9494
func (s *IntegrationSuite) TestInvalidDsnDoesntCrash(c *C) {
9595
// Setup a dummy channel to consume metrics

cmd/postgres_exporter/probe.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ import (
1919

2020
"github.com/go-kit/log"
2121
"github.com/go-kit/log/level"
22-
"github.com/prometheus-community/postgres_exporter/collector"
23-
"github.com/prometheus-community/postgres_exporter/config"
2422
"github.com/prometheus/client_golang/prometheus"
2523
"github.com/prometheus/client_golang/prometheus/promhttp"
24+
"github.com/zeet-dev/postgres_exporter/collector"
25+
"github.com/zeet-dev/postgres_exporter/config"
2626
)
2727

2828
func handleProbe(logger log.Logger, excludeDatabases []string) http.HandlerFunc {

collector/pg_setting.go

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
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+
"fmt"
19+
"math"
20+
"strconv"
21+
"strings"
22+
23+
"github.com/go-kit/log"
24+
"github.com/go-kit/log/level"
25+
"github.com/prometheus/client_golang/prometheus"
26+
)
27+
28+
const settingSubsystem = "setting"
29+
30+
func init() {
31+
registerCollector(settingSubsystem, defaultEnabled, NewPGSettingCollector)
32+
}
33+
34+
type PGSettingCollector struct {
35+
log log.Logger
36+
}
37+
38+
func NewPGSettingCollector(config collectorConfig) (Collector, error) {
39+
return &PGSettingCollector{
40+
log: config.logger,
41+
}, nil
42+
}
43+
44+
var (
45+
settingUnits = []string{
46+
"ms", "s", "min", "h", "d",
47+
"B", "kB", "MB", "GB", "TB",
48+
}
49+
)
50+
51+
// Query the pg_settings view containing runtime variables
52+
func querySettings(ch chan<- prometheus.Metric, instance *instance, logger log.Logger) error {
53+
level.Debug(logger).Log("msg", "Querying pg_setting view", "instance", instance)
54+
55+
// pg_settings docs: https://www.postgresql.org/docs/current/static/view-pg-settings.html
56+
//
57+
// NOTE: If you add more vartypes here, you must update the supported
58+
// types in normaliseUnit() below
59+
query := "SELECT name, setting, COALESCE(unit, ''), short_desc, vartype FROM pg_settings WHERE vartype IN ('bool', 'integer', 'real') AND name != 'sync_commit_cancel_wait';"
60+
61+
rows, err := instance.db.Query(query)
62+
if err != nil {
63+
return fmt.Errorf("Error running query on database %q: %s %v", instance, namespace, err)
64+
}
65+
defer rows.Close() // nolint: errcheck
66+
67+
for rows.Next() {
68+
s := &pgSetting{}
69+
err = rows.Scan(&s.name, &s.setting, &s.unit, &s.shortDesc, &s.vartype)
70+
if err != nil {
71+
return fmt.Errorf("Error retrieving rows on %q: %s %v", instance, namespace, err)
72+
}
73+
74+
ch <- s.metric(prometheus.Labels{})
75+
}
76+
77+
return nil
78+
}
79+
80+
func (c *PGSettingCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
81+
return querySettings(ch, instance, c.log)
82+
}
83+
84+
// pgSetting is represents a PostgreSQL runtime variable as returned by the
85+
// pg_settings view.
86+
type pgSetting struct {
87+
name, setting, unit, shortDesc, vartype string
88+
}
89+
90+
func (s *pgSetting) metric(labels prometheus.Labels) prometheus.Metric {
91+
var (
92+
err error
93+
name = strings.Replace(s.name, ".", "_", -1)
94+
unit = s.unit // nolint: ineffassign
95+
shortDesc = fmt.Sprintf("Server Parameter: %s", s.name)
96+
subsystem = "settings"
97+
val float64
98+
)
99+
100+
switch s.vartype {
101+
case "bool":
102+
if s.setting == "on" {
103+
val = 1
104+
}
105+
case "integer", "real":
106+
if val, unit, err = s.normaliseUnit(); err != nil {
107+
// Panic, since we should recognise all units
108+
// and don't want to silently exlude metrics
109+
panic(err)
110+
}
111+
112+
if len(unit) > 0 {
113+
name = fmt.Sprintf("%s_%s", name, unit)
114+
shortDesc = fmt.Sprintf("%s [Units converted to %s.]", shortDesc, unit)
115+
}
116+
default:
117+
// Panic because we got a type we didn't ask for
118+
panic(fmt.Sprintf("Unsupported vartype %q", s.vartype))
119+
}
120+
121+
desc := prometheus.NewDesc(
122+
prometheus.BuildFQName(
123+
namespace,
124+
subsystem,
125+
name,
126+
),
127+
shortDesc,
128+
[]string{}, labels,
129+
)
130+
131+
return prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, val)
132+
}
133+
134+
// Removes units from any of the setting values.
135+
// This is mostly because of a irregularity regarding AWS RDS Aurora
136+
// https://github.com/zeet-dev/postgres_exporter/issues/619
137+
func (s *pgSetting) sanitizeValue() {
138+
for _, unit := range settingUnits {
139+
if strings.HasSuffix(s.setting, unit) {
140+
endPos := len(s.setting) - len(unit) - 1
141+
s.setting = s.setting[:endPos]
142+
return
143+
}
144+
}
145+
}
146+
147+
// TODO: fix linter override
148+
// nolint: nakedret
149+
func (s *pgSetting) normaliseUnit() (val float64, unit string, err error) {
150+
s.sanitizeValue()
151+
152+
val, err = strconv.ParseFloat(s.setting, 64)
153+
if err != nil {
154+
return val, unit, fmt.Errorf("Error converting setting %q value %q to float: %s", s.name, s.setting, err)
155+
}
156+
157+
// Units defined in: https://www.postgresql.org/docs/current/static/config-setting.html
158+
switch s.unit {
159+
case "":
160+
return
161+
case "ms", "s", "min", "h", "d":
162+
unit = "seconds"
163+
case "B", "kB", "MB", "GB", "TB", "1kB", "2kB", "4kB", "8kB", "16kB", "32kB", "64kB", "16MB", "32MB", "64MB":
164+
unit = "bytes"
165+
default:
166+
err = fmt.Errorf("Unknown unit for runtime variable: %q", s.unit)
167+
return
168+
}
169+
170+
// -1 is special, don't modify the value
171+
if val == -1 {
172+
return
173+
}
174+
175+
switch s.unit {
176+
case "ms":
177+
val /= 1000
178+
case "min":
179+
val *= 60
180+
case "h":
181+
val *= 60 * 60
182+
case "d":
183+
val *= 60 * 60 * 24
184+
case "kB":
185+
val *= math.Pow(2, 10)
186+
case "MB":
187+
val *= math.Pow(2, 20)
188+
case "GB":
189+
val *= math.Pow(2, 30)
190+
case "TB":
191+
val *= math.Pow(2, 40)
192+
case "1kB":
193+
val *= math.Pow(2, 10)
194+
case "2kB":
195+
val *= math.Pow(2, 11)
196+
case "4kB":
197+
val *= math.Pow(2, 12)
198+
case "8kB":
199+
val *= math.Pow(2, 13)
200+
case "16kB":
201+
val *= math.Pow(2, 14)
202+
case "32kB":
203+
val *= math.Pow(2, 15)
204+
case "64kB":
205+
val *= math.Pow(2, 16)
206+
case "16MB":
207+
val *= math.Pow(2, 24)
208+
case "32MB":
209+
val *= math.Pow(2, 25)
210+
case "64MB":
211+
val *= math.Pow(2, 26)
212+
}
213+
214+
return
215+
}

collector/probe.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import (
1919

2020
"github.com/go-kit/log"
2121
"github.com/go-kit/log/level"
22-
"github.com/prometheus-community/postgres_exporter/config"
2322
"github.com/prometheus/client_golang/prometheus"
23+
"github.com/zeet-dev/postgres_exporter/config"
2424
)
2525

2626
type ProbeCollector struct {

0 commit comments

Comments
 (0)