Skip to content

Commit 90fbacf

Browse files
authored
Merge branch 'master' into master
2 parents 682a12e + 1fa394d commit 90fbacf

10 files changed

+407
-119
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ postgres_exporter_integration_test
88
*.iml
99
cover.out
1010
cover.*.out
11-
11+
*.prom

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ env:
3434
- secure: WP96T7yshE03XsPVc9ICbwZXZ6nVsQDCQ9NGKnIEQa4T1Swu5uLVzxjGeowHPykKbKphQmT8inMniBxB48OLc3VVqNxVI+00ppLPEf7n79w2wVbwFOEa6TiOdws+0wOphkeSYc0L+o2aSfoMKJHF+rVW9tmM2tszVjofYHhdWjqloc2pqsfOnqbR7icfpmzMWKyezIE20YOIBsiKZJTKXiZ1SaG9ExkNwuZ7L+HRF1yeI0OdAM4VfEzBK1Gwicy2BtrbyHnl4zgcSoIBmuzo+pNuvqyGmBn3C221M6ki7NoDJDfW5brcvDmiMODWGnka7iW0nt5aUbVtURM8BhWZR0uINo30aYjr4j39UBq8y+mqYV0dp/dMEmy2fa1mogr+DuHUNVSg59Au45AZeom8N6FT03nlg+RcG/tV1skvP/mn9n9CKsyfvC4Rf3jp4+LTiJ9JIch74MecRYVwlpKM+i8s6uDftt3mvxeIYdK+NEMcfwKMv8KTwuxRo/3KRhif7z2cOE+oMbT5POWO19bfboRPCs4xiMTcqpx8dJVs41SacY52PPgjFSnyVrKvzAyjn6mePjLhpoPZueHZuJYPNa9QC8JcASMlCI7lf2Eq+2Dmp2JxmndkRs/cIfHgmO4gtiNM7Vb/rlML1D/8LYPWU/Rdp82/yDffC0ugMNovXt0=
3535
- secure: RRQH4Tr94OblZoqls50BIoyK1OvK9fALs4pAq1Uk5dksY1NWnomheQzOaHzbVfMfXc4zXAzppZIqxUDGn8GiSLbtJL6pnxsxYNGoCGdS8lMjjKWXbCAs8TBJobi3krOOjqgbhOWTpyluTEShnBcg7CjrRQUa/ChS3uE5kl21/4eIl9Be6Q08Eqm3p1yvMAyAgIL6Y6oPAAtBa6zIsi2MSNlryz3RKHJO7AheilppYx3E8B03A+a/oqvTTcw6w/RwBYxB8MYfSLC0jSssZz5pUSX/byUaklGFhQLnKAzJyhrMOvRyMVcO4PHaLgVi1eAKQz6eLQh7uEiIqKh19cuvTbZHDgu8zMpLDTxOW9U95e4kbjOZ5pWZ7E5QTrb24RZIt42JGbmme7PWOvy3zNbWHwfwiOF1qwYwISUcj2KFCpes8mDGt6iv46LfdlU0uoZdZu3MAiTiW0u2SD5hIeFq4XYesPtkS/TKFoAbB5Tu1qbxdmYu5NqmfvmxsmeNEm4inFJ5ap3fRRCVo668Z6qRMuQ1URcEfOz8iEftP9CnwSOXRuiuMo+W9GgckRuDZcPyQMCftq8+PhB+SjK57zrAd4Kxqf6kVHV16tcWqmFjfJJUFqmL+gpjT/VMEVDY2FOnbOARjkeLTjVC4dADBjxfJ6wmlLrfHdUm4GinbaHq0iA=
3636
deploy:
37+
skip_cleanup: true
3738
provider: releases
3839
api_key:
3940
secure: rwlge/Rs3wnWyfKRhD9fd5GviVe0foYUp20DY3AjKdDjhtwScA1EeR9QHOkB3raze52en0+KkpqlLCWbt3q4CRT7+ku1DNKhd6VWALdTZ1RPJYvNlU6CKJdRnWUJsECmSBsShXlbiYR8axqNVedzFPFGKzS9gYlFN6rr7pez/JZhxqucopZ6I+TkRHMELrFXyQK7/Y2bNRCLC4a+rGsjKeLLtYXbRXCmS0G4BSJEBRk7d69fIRzBApCMfrcLftgHzPuPth616yyUusQSCQYvaZ5tlwrPP8/E0wG3SVJVeDCMuDOSBZ9M6vNzR8W8VR/hxQamegn1OQgC5kNOaLZCTcJ5xguRouqb+FNFBqrd/Zi6vESo7RiVLULawzwxkh9sIPa3WZYDb3VK/Z/cpggUeR7wAu0S5ZYEvJHRefIZpqofZEHzDE3Blqp5yErz05e/zmjpd6HHK3f/UHmRRYfbulkvGT3aL/dlq5GcFvuxVC/vTL2VPvg9cGbqtf7PakC5IhoHpDs35tOyLxifOBLHvkwtGSxEfsCohIG8Hz2XFD83EsxgOiKSXVPLNd6yxjdqZj7OeAKFFU3bzGndnRbDIXaf987IN1imgUtP6wegfImoRStqxN4gEwwIMFsZCF86Ug4eLhlajLbWhudriDxDPBM/F9950aVxLwmWh9l5cRI=

pg_setting.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package main
2+
3+
import (
4+
"database/sql"
5+
"errors"
6+
"fmt"
7+
"math"
8+
"strconv"
9+
"strings"
10+
11+
"github.com/prometheus/client_golang/prometheus"
12+
"github.com/prometheus/common/log"
13+
)
14+
15+
// Query the pg_settings view containing runtime variables
16+
func querySettings(ch chan<- prometheus.Metric, db *sql.DB) error {
17+
log.Debugln("Querying pg_setting view")
18+
19+
// pg_settings docs: https://www.postgresql.org/docs/current/static/view-pg-settings.html
20+
//
21+
// NOTE: If you add more vartypes here, you must update the supported
22+
// types in normaliseUnit() below
23+
query := "SELECT name, setting, COALESCE(unit, ''), short_desc, vartype FROM pg_settings WHERE vartype IN ('bool', 'integer', 'real');"
24+
25+
rows, err := db.Query(query)
26+
if err != nil {
27+
return errors.New(fmt.Sprintln("Error running query on database: ", namespace, err))
28+
}
29+
defer rows.Close()
30+
31+
for rows.Next() {
32+
s := &pgSetting{}
33+
err = rows.Scan(&s.name, &s.setting, &s.unit, &s.shortDesc, &s.vartype)
34+
if err != nil {
35+
return errors.New(fmt.Sprintln("Error retrieving rows:", namespace, err))
36+
}
37+
38+
ch <- s.metric()
39+
}
40+
41+
return nil
42+
}
43+
44+
// pgSetting is represents a PostgreSQL runtime variable as returned by the
45+
// pg_settings view.
46+
type pgSetting struct {
47+
name, setting, unit, shortDesc, vartype string
48+
}
49+
50+
func (s *pgSetting) metric() prometheus.Metric {
51+
var (
52+
err error
53+
name = strings.Replace(s.name, ".", "_", -1)
54+
unit = s.unit
55+
shortDesc = s.shortDesc
56+
subsystem = "settings"
57+
val float64
58+
)
59+
60+
switch s.vartype {
61+
case "bool":
62+
if s.setting == "on" {
63+
val = 1
64+
}
65+
case "integer", "real":
66+
if val, unit, err = s.normaliseUnit(); err != nil {
67+
// Panic, since we should recognise all units
68+
// and don't want to silently exlude metrics
69+
panic(err)
70+
}
71+
72+
if len(unit) > 0 {
73+
name = fmt.Sprintf("%s_%s", name, unit)
74+
shortDesc = fmt.Sprintf("%s [Units converted to %s.]", shortDesc, unit)
75+
}
76+
default:
77+
// Panic because we got a type we didn't ask for
78+
panic(fmt.Sprintf("Unsupported vartype %q", s.vartype))
79+
}
80+
81+
desc := newDesc(subsystem, name, shortDesc)
82+
return prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, val)
83+
}
84+
85+
func (s *pgSetting) normaliseUnit() (val float64, unit string, err error) {
86+
val, err = strconv.ParseFloat(s.setting, 64)
87+
if err != nil {
88+
return val, unit, errors.New(fmt.Sprintf("Error converting setting %q value %q to float: %s", s.name, s.setting, err))
89+
}
90+
91+
// Units defined in: https://www.postgresql.org/docs/current/static/config-setting.html
92+
switch s.unit {
93+
case "":
94+
return
95+
case "ms", "s", "min", "h", "d":
96+
unit = "seconds"
97+
case "kB", "MB", "GB", "TB", "8kB", "16MB":
98+
unit = "bytes"
99+
default:
100+
err = errors.New(fmt.Sprintf("Unknown unit for runtime variable: %q", s.unit))
101+
return
102+
}
103+
104+
// -1 is special, don't modify the value
105+
if val == -1 {
106+
return
107+
}
108+
109+
switch s.unit {
110+
case "ms":
111+
val /= 1000
112+
case "min":
113+
val *= 60
114+
case "h":
115+
val *= 60 * 60
116+
case "d":
117+
val *= 60 * 60 * 24
118+
case "kB":
119+
val *= math.Pow(2, 10)
120+
case "MB":
121+
val *= math.Pow(2, 20)
122+
case "GB":
123+
val *= math.Pow(2, 30)
124+
case "TB":
125+
val *= math.Pow(2, 40)
126+
case "8kB":
127+
val *= math.Pow(2, 13)
128+
case "16MB":
129+
val *= math.Pow(2, 24)
130+
}
131+
132+
return
133+
}

pg_setting_test.go

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
// +build !integration
2+
3+
package main
4+
5+
import (
6+
dto "github.com/prometheus/client_model/go"
7+
. "gopkg.in/check.v1"
8+
)
9+
10+
type PgSettingSuite struct{}
11+
12+
var _ = Suite(&PgSettingSuite{})
13+
14+
var fixtures = []fixture{
15+
fixture{
16+
p: pgSetting{
17+
name: "seconds_fixture_metric",
18+
setting: "5",
19+
unit: "s",
20+
shortDesc: "Foo foo foo",
21+
vartype: "integer",
22+
},
23+
n: normalised{
24+
val: 5,
25+
unit: "seconds",
26+
err: "",
27+
},
28+
d: "Desc{fqName: \"pg_settings_seconds_fixture_metric_seconds\", help: \"Foo foo foo [Units converted to seconds.]\", constLabels: {}, variableLabels: []}",
29+
v: 5,
30+
},
31+
fixture{
32+
p: pgSetting{
33+
name: "milliseconds_fixture_metric",
34+
setting: "5000",
35+
unit: "ms",
36+
shortDesc: "Foo foo foo",
37+
vartype: "integer",
38+
},
39+
n: normalised{
40+
val: 5,
41+
unit: "seconds",
42+
err: "",
43+
},
44+
d: "Desc{fqName: \"pg_settings_milliseconds_fixture_metric_seconds\", help: \"Foo foo foo [Units converted to seconds.]\", constLabels: {}, variableLabels: []}",
45+
v: 5,
46+
},
47+
fixture{
48+
p: pgSetting{
49+
name: "eight_kb_fixture_metric",
50+
setting: "17",
51+
unit: "8kB",
52+
shortDesc: "Foo foo foo",
53+
vartype: "integer",
54+
},
55+
n: normalised{
56+
val: 139264,
57+
unit: "bytes",
58+
err: "",
59+
},
60+
d: "Desc{fqName: \"pg_settings_eight_kb_fixture_metric_bytes\", help: \"Foo foo foo [Units converted to bytes.]\", constLabels: {}, variableLabels: []}",
61+
v: 139264,
62+
},
63+
fixture{
64+
p: pgSetting{
65+
name: "16_mb_real_fixture_metric",
66+
setting: "3.0",
67+
unit: "16MB",
68+
shortDesc: "Foo foo foo",
69+
vartype: "real",
70+
},
71+
n: normalised{
72+
val: 5.0331648e+07,
73+
unit: "bytes",
74+
err: "",
75+
},
76+
d: "Desc{fqName: \"pg_settings_16_mb_real_fixture_metric_bytes\", help: \"Foo foo foo [Units converted to bytes.]\", constLabels: {}, variableLabels: []}",
77+
v: 5.0331648e+07,
78+
},
79+
fixture{
80+
p: pgSetting{
81+
name: "bool_on_fixture_metric",
82+
setting: "on",
83+
unit: "",
84+
shortDesc: "Foo foo foo",
85+
vartype: "bool",
86+
},
87+
n: normalised{
88+
val: 1,
89+
unit: "",
90+
err: "",
91+
},
92+
d: "Desc{fqName: \"pg_settings_bool_on_fixture_metric\", help: \"Foo foo foo\", constLabels: {}, variableLabels: []}",
93+
v: 1,
94+
},
95+
fixture{
96+
p: pgSetting{
97+
name: "bool_off_fixture_metric",
98+
setting: "off",
99+
unit: "",
100+
shortDesc: "Foo foo foo",
101+
vartype: "bool",
102+
},
103+
n: normalised{
104+
val: 0,
105+
unit: "",
106+
err: "",
107+
},
108+
d: "Desc{fqName: \"pg_settings_bool_off_fixture_metric\", help: \"Foo foo foo\", constLabels: {}, variableLabels: []}",
109+
v: 0,
110+
},
111+
fixture{
112+
p: pgSetting{
113+
name: "special_minus_one_value",
114+
setting: "-1",
115+
unit: "d",
116+
shortDesc: "foo foo foo",
117+
vartype: "integer",
118+
},
119+
n: normalised{
120+
val: -1,
121+
unit: "seconds",
122+
err: "",
123+
},
124+
d: "Desc{fqName: \"pg_settings_special_minus_one_value_seconds\", help: \"foo foo foo [Units converted to seconds.]\", constLabels: {}, variableLabels: []}",
125+
v: -1,
126+
},
127+
fixture{
128+
p: pgSetting{
129+
name: "rds.rds_superuser_reserved_connections",
130+
setting: "2",
131+
unit: "",
132+
shortDesc: "Sets the number of connection slots reserved for rds_superusers.",
133+
vartype: "integer",
134+
},
135+
n: normalised{
136+
val: 2,
137+
unit: "",
138+
err: "",
139+
},
140+
d: "Desc{fqName: \"pg_settings_rds_rds_superuser_reserved_connections\", help: \"Sets the number of connection slots reserved for rds_superusers.\", constLabels: {}, variableLabels: []}",
141+
v: 2,
142+
},
143+
fixture{
144+
p: pgSetting{
145+
name: "unknown_unit",
146+
setting: "10",
147+
unit: "nonexistent",
148+
shortDesc: "foo foo foo",
149+
vartype: "integer",
150+
},
151+
n: normalised{
152+
val: 10,
153+
unit: "",
154+
err: `Unknown unit for runtime variable: "nonexistent"`,
155+
},
156+
},
157+
}
158+
159+
func (s *PgSettingSuite) TestNormaliseUnit(c *C) {
160+
for _, f := range fixtures {
161+
switch f.p.vartype {
162+
case "integer", "real":
163+
val, unit, err := f.p.normaliseUnit()
164+
165+
c.Check(val, Equals, f.n.val)
166+
c.Check(unit, Equals, f.n.unit)
167+
168+
if err == nil {
169+
c.Check("", Equals, f.n.err)
170+
} else {
171+
c.Check(err.Error(), Equals, f.n.err)
172+
}
173+
}
174+
}
175+
}
176+
177+
func (s *PgSettingSuite) TestMetric(c *C) {
178+
defer func() {
179+
if r := recover(); r != nil {
180+
if r.(error).Error() != `Unknown unit for runtime variable: "nonexistent"` {
181+
panic(r)
182+
}
183+
}
184+
}()
185+
186+
for _, f := range fixtures {
187+
d := &dto.Metric{}
188+
m := f.p.metric()
189+
m.Write(d)
190+
191+
c.Check(m.Desc().String(), Equals, f.d)
192+
c.Check(d.GetGauge().GetValue(), Equals, f.v)
193+
}
194+
}
195+
196+
type normalised struct {
197+
val float64
198+
unit string
199+
err string
200+
}
201+
202+
type fixture struct {
203+
p pgSetting
204+
n normalised
205+
d string
206+
v float64
207+
}

0 commit comments

Comments
 (0)