Skip to content

Commit 1e3373c

Browse files
authored
Merge branch 'master' into patch-1
2 parents a3a4c66 + 3864bbc commit 1e3373c

File tree

5 files changed

+119
-42
lines changed

5 files changed

+119
-42
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,18 @@ AS
255255
SELECT * FROM get_pg_stat_replication();
256256

257257
GRANT SELECT ON postgres_exporter.pg_stat_replication TO postgres_exporter;
258+
259+
CREATE OR REPLACE FUNCTION get_pg_stat_statements() RETURNS SETOF pg_stat_statements AS
260+
$$ SELECT * FROM public.pg_stat_statements; $$
261+
LANGUAGE sql
262+
VOLATILE
263+
SECURITY DEFINER;
264+
265+
CREATE OR REPLACE VIEW postgres_exporter.pg_stat_statements
266+
AS
267+
SELECT * FROM get_pg_stat_statements();
268+
269+
GRANT SELECT ON postgres_exporter.pg_stat_statements TO postgres_exporter;
258270
```
259271

260272
> **NOTE**

cmd/postgres_exporter/postgres_exporter.go

Lines changed: 65 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,16 @@ var builtinMetricMaps = map[string]intermediateMetricMap{
315315
true,
316316
0,
317317
},
318+
"pg_replication_slots": {
319+
map[string]ColumnMapping{
320+
"slot_name": {LABEL, "Name of the replication slot", nil, nil},
321+
"database": {LABEL, "Name of the database", nil, nil},
322+
"active": {GAUGE, "Flag indicating if the slot is active", nil, nil},
323+
"pg_wal_lsn_diff": {GAUGE, "Replication lag in bytes", nil, nil},
324+
},
325+
true,
326+
0,
327+
},
318328
"pg_stat_archiver": {
319329
map[string]ColumnMapping{
320330
"archived_count": {COUNTER, "Number of WAL files that have been successfully archived", nil, nil},
@@ -408,6 +418,16 @@ var queryOverrides = map[string][]OverrideQuery{
408418
},
409419
},
410420

421+
"pg_replication_slots": {
422+
{
423+
semver.MustParseRange(">=9.4.0"),
424+
`
425+
SELECT slot_name, database, active, pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)
426+
FROM pg_replication_slots
427+
`,
428+
},
429+
},
430+
411431
"pg_stat_archiver": {
412432
{
413433
semver.MustParseRange(">=0.0.0"),
@@ -1562,50 +1582,51 @@ func (e *Exporter) scrapeDSN(ch chan<- prometheus.Metric, dsn string) error {
15621582
// DATA_SOURCE_NAME always wins so we do not break older versions
15631583
// reading secrets from files wins over secrets in environment variables
15641584
// DATA_SOURCE_NAME > DATA_SOURCE_{USER|PASS}_FILE > DATA_SOURCE_{USER|PASS}
1565-
func getDataSources() []string {
1585+
func getDataSources() ([]string, error) {
15661586
var dsn = os.Getenv("DATA_SOURCE_NAME")
1567-
if len(dsn) == 0 {
1568-
var user string
1569-
var pass string
1570-
var uri string
1587+
if len(dsn) != 0 {
1588+
return strings.Split(dsn, ","), nil
1589+
}
15711590

1572-
if len(os.Getenv("DATA_SOURCE_USER_FILE")) != 0 {
1573-
fileContents, err := ioutil.ReadFile(os.Getenv("DATA_SOURCE_USER_FILE"))
1574-
if err != nil {
1575-
panic(err)
1576-
}
1577-
user = strings.TrimSpace(string(fileContents))
1578-
} else {
1579-
user = os.Getenv("DATA_SOURCE_USER")
1580-
}
1591+
var user, pass, uri string
15811592

1582-
if len(os.Getenv("DATA_SOURCE_PASS_FILE")) != 0 {
1583-
fileContents, err := ioutil.ReadFile(os.Getenv("DATA_SOURCE_PASS_FILE"))
1584-
if err != nil {
1585-
panic(err)
1586-
}
1587-
pass = strings.TrimSpace(string(fileContents))
1588-
} else {
1589-
pass = os.Getenv("DATA_SOURCE_PASS")
1593+
dataSourceUserFile := os.Getenv("DATA_SOURCE_USER_FILE")
1594+
if len(dataSourceUserFile) != 0 {
1595+
fileContents, err := ioutil.ReadFile(dataSourceUserFile)
1596+
if err != nil {
1597+
return nil, fmt.Errorf("failed loading data source user file %s: %s", dataSourceUserFile, err.Error())
15901598
}
1599+
user = strings.TrimSpace(string(fileContents))
1600+
} else {
1601+
user = os.Getenv("DATA_SOURCE_USER")
1602+
}
15911603

1592-
ui := url.UserPassword(user, pass).String()
1604+
dataSourcePassFile := os.Getenv("DATA_SOURCE_PASS_FILE")
1605+
if len(dataSourcePassFile) != 0 {
1606+
fileContents, err := ioutil.ReadFile(dataSourcePassFile)
1607+
if err != nil {
1608+
return nil, fmt.Errorf("failed loading data source pass file %s: %s", dataSourcePassFile, err.Error())
1609+
}
1610+
pass = strings.TrimSpace(string(fileContents))
1611+
} else {
1612+
pass = os.Getenv("DATA_SOURCE_PASS")
1613+
}
15931614

1594-
if len(os.Getenv("DATA_SOURCE_URI_FILE")) != 0 {
1595-
fileContents, err := ioutil.ReadFile(os.Getenv("DATA_SOURCE_URI_FILE"))
1596-
if err != nil {
1597-
panic(err)
1598-
}
1599-
uri = strings.TrimSpace(string(fileContents))
1600-
} else {
1601-
uri = os.Getenv("DATA_SOURCE_URI")
1615+
ui := url.UserPassword(user, pass).String()
1616+
dataSrouceURIFile := os.Getenv("DATA_SOURCE_URI_FILE")
1617+
if len(dataSrouceURIFile) != 0 {
1618+
fileContents, err := ioutil.ReadFile(dataSrouceURIFile)
1619+
if err != nil {
1620+
return nil, fmt.Errorf("failed loading data source URI file %s: %s", dataSrouceURIFile, err.Error())
16021621
}
1622+
uri = strings.TrimSpace(string(fileContents))
1623+
} else {
1624+
uri = os.Getenv("DATA_SOURCE_URI")
1625+
}
16031626

1604-
dsn = "postgresql://" + ui + "@" + uri
1627+
dsn = "postgresql://" + ui + "@" + uri
16051628

1606-
return []string{dsn}
1607-
}
1608-
return strings.Split(dsn, ",")
1629+
return []string{dsn}, nil
16091630
}
16101631

16111632
func contains(a []string, x string) bool {
@@ -1638,19 +1659,25 @@ func main() {
16381659
return
16391660
}
16401661

1641-
dsn := getDataSources()
1662+
dsn, err := getDataSources()
1663+
if err != nil {
1664+
log.Fatalf("failed reading data sources: %s", err.Error())
1665+
}
1666+
16421667
if len(dsn) == 0 {
16431668
log.Fatal("couldn't find environment variables describing the datasource to use")
16441669
}
16451670

1646-
exporter := NewExporter(dsn,
1671+
opts := []ExporterOpt{
16471672
DisableDefaultMetrics(*disableDefaultMetrics),
16481673
DisableSettingsMetrics(*disableSettingsMetrics),
16491674
AutoDiscoverDatabases(*autoDiscoverDatabases),
16501675
WithUserQueriesPath(*queriesPath),
16511676
WithConstantLabels(*constantLabelsList),
16521677
ExcludeDatabases(*excludeDatabases),
1653-
)
1678+
}
1679+
1680+
exporter := NewExporter(dsn, opts...)
16541681
defer func() {
16551682
exporter.servers.Close()
16561683
}()

cmd/postgres_exporter/postgres_exporter_test.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,11 @@ func (s *FunctionalSuite) TestEnvironmentSettingWithSecretsFiles(c *C) {
111111

112112
var expected = "postgresql://custom_username$&+,%2F%3A;=%3F%40:custom_password$&+,%2F%3A;=%3F%40@localhost:5432/?sslmode=disable"
113113

114-
dsn := getDataSources()
114+
dsn, err := getDataSources()
115+
if err != nil {
116+
c.Errorf("Unexpected error reading datasources")
117+
}
118+
115119
if len(dsn) == 0 {
116120
c.Errorf("Expected one data source, zero found")
117121
}
@@ -127,7 +131,11 @@ func (s *FunctionalSuite) TestEnvironmentSettingWithDns(c *C) {
127131
c.Assert(err, IsNil)
128132
defer UnsetEnvironment(c, "DATA_SOURCE_NAME")
129133

130-
dsn := getDataSources()
134+
dsn, err := getDataSources()
135+
if err != nil {
136+
c.Errorf("Unexpected error reading datasources")
137+
}
138+
131139
if len(dsn) == 0 {
132140
c.Errorf("Expected one data source, zero found")
133141
}
@@ -151,7 +159,11 @@ func (s *FunctionalSuite) TestEnvironmentSettingWithDnsAndSecrets(c *C) {
151159
c.Assert(err, IsNil)
152160
defer UnsetEnvironment(c, "DATA_SOURCE_PASS")
153161

154-
dsn := getDataSources()
162+
dsn, err := getDataSources()
163+
if err != nil {
164+
c.Errorf("Unexpected error reading datasources")
165+
}
166+
155167
if len(dsn) == 0 {
156168
c.Errorf("Expected one data source, zero found")
157169
}

magefile.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ var platforms []Platform = []Platform{
9898
{"linux", "amd64", ""},
9999
{"linux", "386", ""},
100100
{"linux", "arm64", ""},
101+
{"linux", "mips64le", ""},
101102
{"darwin", "amd64", ""},
102103
{"darwin", "386", ""},
103104
{"windows", "amd64", ".exe"},

queries.yaml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,32 @@ pg_postmaster:
1515
description: "Time at which postmaster started"
1616

1717
pg_stat_user_tables:
18-
query: "SELECT current_database() datname, schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze, COALESCE(last_vacuum, '1970-01-01Z'), COALESCE(last_vacuum, '1970-01-01Z') as last_vacuum, COALESCE(last_autovacuum, '1970-01-01Z') as last_autovacuum, COALESCE(last_analyze, '1970-01-01Z') as last_analyze, COALESCE(last_autoanalyze, '1970-01-01Z') as last_autoanalyze, vacuum_count, autovacuum_count, analyze_count, autoanalyze_count FROM pg_stat_user_tables"
18+
query: |
19+
SELECT
20+
current_database() datname,
21+
schemaname,
22+
relname,
23+
seq_scan,
24+
seq_tup_read,
25+
idx_scan,
26+
idx_tup_fetch,
27+
n_tup_ins,
28+
n_tup_upd,
29+
n_tup_del,
30+
n_tup_hot_upd,
31+
n_live_tup,
32+
n_dead_tup,
33+
n_mod_since_analyze,
34+
COALESCE(last_vacuum, '1970-01-01Z') as last_vacuum,
35+
COALESCE(last_autovacuum, '1970-01-01Z') as last_autovacuum,
36+
COALESCE(last_analyze, '1970-01-01Z') as last_analyze,
37+
COALESCE(last_autoanalyze, '1970-01-01Z') as last_autoanalyze,
38+
vacuum_count,
39+
autovacuum_count,
40+
analyze_count,
41+
autoanalyze_count
42+
FROM
43+
pg_stat_user_tables
1944
metrics:
2045
- datname:
2146
usage: "LABEL"

0 commit comments

Comments
 (0)