Skip to content

Commit 11587d9

Browse files
authored
Merge pull request #4 from form3tech-oss/english-pull-upstream
Pull in upstream to v0.8.0
2 parents 6ec84c4 + e1d8378 commit 11587d9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+6912
-4417
lines changed

README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ Package vendoring is handled with [`govendor`](https://github.com/kardianos/gove
4343

4444
### Flags
4545

46+
* `help`
47+
Show context-sensitive help (also try --help-long and --help-man).
48+
4649
* `web.listen-address`
4750
Address to listen on for web interface and telemetry. Default is `:9187`.
4851

@@ -55,6 +58,9 @@ Package vendoring is handled with [`govendor`](https://github.com/kardianos/gove
5558
* `disable-settings-metrics`
5659
Use the flag if you don't want to scrape `pg_settings`.
5760

61+
* `auto-discover-databases`
62+
Whether to discover the databases on a server dynamically.
63+
5864
* `extend.query-path`
5965
Path to a YAML file containing custom queries to run. Check out [`queries.yaml`](queries.yaml)
6066
for examples of the format.
@@ -63,16 +69,22 @@ Package vendoring is handled with [`govendor`](https://github.com/kardianos/gove
6369
Do not run - print the internal representation of the metric maps. Useful when debugging a custom
6470
queries file.
6571

72+
* `constantLabels`
73+
Labels to set in all metrics. A list of `label=value` pairs, separated by commas.
74+
75+
* `version`
76+
Show application version.
77+
78+
* `exclude-databases`
79+
A list of databases to remove when autoDiscoverDatabases is enabled.
80+
6681
* `log.level`
6782
Set logging level: one of `debug`, `info`, `warn`, `error`, `fatal`
6883

6984
* `log.format`
7085
Set the log output target and format. e.g. `logger:syslog?appname=bob&local=7` or `logger:stdout?json=true`
7186
Defaults to `logger:stderr`.
7287

73-
* `constantLabels`
74-
Labels to set in all metrics. A list of `label=value` pairs, separated by commas.
75-
7688
### Environment Variables
7789

7890
The following environment variables configure the exporter:
@@ -85,6 +97,9 @@ The following environment variables configure the exporter:
8597
an alternative to `DATA_SOURCE_NAME` which exclusively accepts the raw URI
8698
without a username and password component.
8799

100+
* `DATA_SOURCE_URI_FILE`
101+
The same as above but reads the URI from a file.
102+
88103
* `DATA_SOURCE_USER`
89104
When using `DATA_SOURCE_URI`, this environment variable is used to specify
90105
the username.
@@ -111,13 +126,19 @@ The following environment variables configure the exporter:
111126
* `PG_EXPORTER_DISABLE_SETTINGS_METRICS`
112127
Use the flag if you don't want to scrape `pg_settings`. Value can be `true` or `false`. Defauls is `false`.
113128

129+
* `PG_EXPORTER_AUTO_DISCOVER_DATABASES`
130+
Whether to discover the databases on a server dynamically. Value can be `true` or `false`. Defauls is `false`.
131+
114132
* `PG_EXPORTER_EXTEND_QUERY_PATH`
115133
Path to a YAML file containing custom queries to run. Check out [`queries.yaml`](queries.yaml)
116134
for examples of the format.
117135

118136
* `PG_EXPORTER_CONSTANT_LABELS`
119137
Labels to set in all metrics. A list of `label=value` pairs, separated by commas.
120138

139+
* `PG_EXPORTER_EXCLUDE_DATABASES`
140+
A comma-separated list of databases to remove when autoDiscoverDatabases is enabled. Default is empty string.
141+
121142
Settings set by environment variables starting with `PG_` will be overwritten by the corresponding CLI flag if given.
122143

123144
### Setting the Postgres server's data source name
@@ -163,7 +184,7 @@ flag. This removes all built-in metrics, and uses only metrics defined by querie
163184

164185
### Automatically discover databases
165186
To scrape metrics from all databases on a database server, the database DSN's can be dynamically discovered via the
166-
`--auto-discover-databases` flag. When true, `SELECT datname FROM pg_database WHERE datallowconn = true AND datistemplate = false` is run for all configured DSN's. From the
187+
`--auto-discover-databases` flag. When true, `SELECT datname FROM pg_database WHERE datallowconn = true AND datistemplate = false and datname != current_database()` is run for all configured DSN's. From the
167188
result a new set of DSN's is created for which the metrics are scraped.
168189

169190
In addition, the option `--exclude-databases` adds the possibily to filter the result from the auto discovery to discard databases you do not need.

cmd/postgres_exporter/postgres_exporter.go

Lines changed: 106 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,26 @@ import (
2323
"github.com/prometheus/client_golang/prometheus"
2424
"github.com/prometheus/client_golang/prometheus/promhttp"
2525
"github.com/prometheus/common/log"
26+
"github.com/prometheus/common/version"
2627
"gopkg.in/alecthomas/kingpin.v2"
2728
"gopkg.in/yaml.v2"
2829
)
2930

31+
// Branch is set during build to the git branch.
32+
var Branch string
33+
34+
// BuildDate is set during build to the ISO-8601 date and time.
35+
var BuildDate string
36+
37+
// Revision is set during build to the git commit revision.
38+
var Revision string
39+
3040
// Version is set during build to the git describe version
3141
// (semantic version)-(commitish) form.
32-
var Version = "0.0.1"
42+
var Version = "0.0.1-rev"
43+
44+
// VersionShort is set during build to the semantic version.
45+
var VersionShort = "0.0.1"
3346

3447
var (
3548
listenAddress = kingpin.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9187").Envar("PG_EXPORTER_WEB_LISTEN_ADDRESS").String()
@@ -101,6 +114,7 @@ type Mapping map[string]MappingOptions
101114
type UserQuery struct {
102115
Query string `yaml:"query"`
103116
Metrics []Mapping `yaml:"metrics"`
117+
Master bool `yaml:"master"` // Querying only for master database
104118
CacheSeconds uint64 `yaml:"cache_seconds"` // Number of seconds to cache the namespace result metrics for.
105119
}
106120

@@ -140,13 +154,15 @@ func (cm *ColumnMapping) UnmarshalYAML(unmarshal func(interface{}) error) error
140154
// This is mainly so we can parse cacheSeconds around.
141155
type intermediateMetricMap struct {
142156
columnMappings map[string]ColumnMapping
157+
master bool
143158
cacheSeconds uint64
144159
}
145160

146161
// MetricMapNamespace groups metric maps under a shared set of labels.
147162
type MetricMapNamespace struct {
148163
labels []string // Label names for this namespace
149164
columnMappings map[string]MetricMap // Column mappings in this namespace
165+
master bool // Call query only for master database
150166
cacheSeconds uint64 // Number of seconds this metric namespace can be cached. 0 disables.
151167
}
152168

@@ -190,6 +206,23 @@ func dumpMaps() {
190206
}
191207

192208
var builtinMetricMaps = map[string]intermediateMetricMap{
209+
"pg_stat_bgwriter": {
210+
map[string]ColumnMapping{
211+
"checkpoints_timed": {COUNTER, "Number of scheduled checkpoints that have been performed", nil, nil},
212+
"checkpoints_req": {COUNTER, "Number of requested checkpoints that have been performed", nil, nil},
213+
"checkpoint_write_time": {COUNTER, "Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in milliseconds", nil, nil},
214+
"checkpoint_sync_time": {COUNTER, "Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in milliseconds", nil, nil},
215+
"buffers_checkpoint": {COUNTER, "Number of buffers written during checkpoints", nil, nil},
216+
"buffers_clean": {COUNTER, "Number of buffers written by the background writer", nil, nil},
217+
"maxwritten_clean": {COUNTER, "Number of times the background writer stopped a cleaning scan because it had written too many buffers", nil, nil},
218+
"buffers_backend": {COUNTER, "Number of buffers written directly by a backend", nil, nil},
219+
"buffers_backend_fsync": {COUNTER, "Number of times a backend had to execute its own fsync call (normally the background writer handles those even when the backend does its own write)", nil, nil},
220+
"buffers_alloc": {COUNTER, "Number of buffers allocated", nil, nil},
221+
"stats_reset": {COUNTER, "Time at which these statistics were last reset", nil, nil},
222+
},
223+
true,
224+
0,
225+
},
193226
"pg_stat_database": {
194227
map[string]ColumnMapping{
195228
"datid": {LABEL, "OID of a database", nil, nil},
@@ -212,6 +245,7 @@ var builtinMetricMaps = map[string]intermediateMetricMap{
212245
"blk_write_time": {COUNTER, "Time spent writing data file blocks by backends in this database, in milliseconds", nil, nil},
213246
"stats_reset": {COUNTER, "Time at which these statistics were last reset", nil, nil},
214247
},
248+
true,
215249
0,
216250
},
217251
"pg_stat_database_conflicts": {
@@ -224,6 +258,7 @@ var builtinMetricMaps = map[string]intermediateMetricMap{
224258
"confl_bufferpin": {COUNTER, "Number of queries in this database that have been canceled due to pinned buffers", nil, nil},
225259
"confl_deadlock": {COUNTER, "Number of queries in this database that have been canceled due to deadlocks", nil, nil},
226260
},
261+
true,
227262
0,
228263
},
229264
"pg_locks": {
@@ -232,6 +267,7 @@ var builtinMetricMaps = map[string]intermediateMetricMap{
232267
"mode": {LABEL, "Type of Lock", nil, nil},
233268
"count": {GAUGE, "Number of locks", nil, nil},
234269
},
270+
true,
235271
0,
236272
},
237273
"pg_stat_replication": {
@@ -277,6 +313,21 @@ var builtinMetricMaps = map[string]intermediateMetricMap{
277313
"flush_lag": {DISCARD, "Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it (but not yet applied it). This can be used to gauge the delay that synchronous_commit level remote_flush incurred while committing if this server was configured as a synchronous standby.", nil, semver.MustParseRange(">=10.0.0")},
278314
"replay_lag": {DISCARD, "Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it. This can be used to gauge the delay that synchronous_commit level remote_apply incurred while committing if this server was configured as a synchronous standby.", nil, semver.MustParseRange(">=10.0.0")},
279315
},
316+
true,
317+
0,
318+
},
319+
"pg_stat_archiver": {
320+
map[string]ColumnMapping{
321+
"archived_count": {COUNTER, "Number of WAL files that have been successfully archived", nil, nil},
322+
"last_archived_wal": {DISCARD, "Name of the last WAL file successfully archived", nil, nil},
323+
"last_archived_time": {DISCARD, "Time of the last successful archive operation", nil, nil},
324+
"failed_count": {COUNTER, "Number of failed attempts for archiving WAL files", nil, nil},
325+
"last_failed_wal": {DISCARD, "Name of the WAL file of the last failed archival operation", nil, nil},
326+
"last_failed_time": {DISCARD, "Time of the last failed archival operation", nil, nil},
327+
"stats_reset": {DISCARD, "Time at which these statistics were last reset", nil, nil},
328+
"last_archive_age": {GAUGE, "Time in seconds since last WAL segment was successfully archived", nil, nil},
329+
},
330+
true,
280331
0,
281332
},
282333
"pg_stat_activity": {
@@ -286,6 +337,7 @@ var builtinMetricMaps = map[string]intermediateMetricMap{
286337
"count": {GAUGE, "number of connections in this state", nil, nil},
287338
"max_tx_duration": {GAUGE, "max duration in seconds any active transaction has been running", nil, nil},
288339
},
340+
true,
289341
0,
290342
},
291343
}
@@ -356,6 +408,17 @@ var queryOverrides = map[string][]OverrideQuery{
356408
},
357409
},
358410

411+
"pg_stat_archiver": {
412+
{
413+
semver.MustParseRange(">=0.0.0"),
414+
`
415+
SELECT *,
416+
extract(epoch from now() - last_archived_time) AS last_archive_age
417+
FROM pg_stat_archiver
418+
`,
419+
},
420+
},
421+
359422
"pg_stat_activity": {
360423
// This query only works
361424
{
@@ -445,6 +508,7 @@ func parseUserQueries(content []byte) (map[string]intermediateMetricMap, map[str
445508
newMetricMap := make(map[string]ColumnMapping)
446509
metricMap = intermediateMetricMap{
447510
columnMappings: newMetricMap,
511+
master: specs.Master,
448512
cacheSeconds: specs.CacheSeconds,
449513
}
450514
metricMaps[metric] = metricMap
@@ -615,7 +679,7 @@ func makeDescMap(pgVersion semver.Version, serverLabels prometheus.Labels, metri
615679
}
616680
}
617681

618-
metricMap[namespace] = MetricMapNamespace{variableLabels, thisMap, intermediateMappings.cacheSeconds}
682+
metricMap[namespace] = MetricMapNamespace{variableLabels, thisMap, intermediateMappings.master, intermediateMappings.cacheSeconds}
619683
}
620684

621685
return metricMap
@@ -858,7 +922,7 @@ func (s *Server) Scrape(ch chan<- prometheus.Metric, disableSettingsMetrics bool
858922

859923
var err error
860924

861-
if (!disableSettingsMetrics && !*autoDiscoverDatabases) || (!disableSettingsMetrics && *autoDiscoverDatabases && s.master) {
925+
if !disableSettingsMetrics && s.master {
862926
if err = querySettings(ch, s); err != nil {
863927
err = fmt.Errorf("error retrieving settings: %s", err)
864928
}
@@ -1258,6 +1322,12 @@ func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[str
12581322

12591323
for namespace, mapping := range server.metricMap {
12601324
log.Debugln("Querying namespace: ", namespace)
1325+
1326+
if mapping.master && !server.master {
1327+
log.Debugln("Query skipped...")
1328+
continue
1329+
}
1330+
12611331
scrapeMetric := false
12621332
// Check if the metric is cached
12631333
server.cacheMtx.Lock()
@@ -1336,12 +1406,13 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, server *Server)
13361406
log.Infof("Semantic Version Changed on %q: %s -> %s", server, server.lastMapVersion, semanticVersion)
13371407
server.mappingMtx.Lock()
13381408

1339-
if e.disableDefaultMetrics || (!e.disableDefaultMetrics && e.autoDiscoverDatabases && !server.master) {
1340-
server.metricMap = make(map[string]MetricMapNamespace)
1341-
server.queryOverrides = make(map[string]string)
1342-
} else {
1409+
// Get Default Metrics only for master database
1410+
if !e.disableDefaultMetrics && server.master {
13431411
server.metricMap = makeDescMap(semanticVersion, server.labels, e.builtinMetricMaps)
13441412
server.queryOverrides = makeQueryOverrideMap(semanticVersion, queryOverrides)
1413+
} else {
1414+
server.metricMap = make(map[string]MetricMapNamespace)
1415+
server.queryOverrides = make(map[string]string)
13451416
}
13461417

13471418
server.lastMapVersion = semanticVersion
@@ -1371,11 +1442,11 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, server *Server)
13711442
server.mappingMtx.Unlock()
13721443
}
13731444

1374-
// Output the version as a special metric
1445+
// Output the version as a special metric only for master database
13751446
versionDesc := prometheus.NewDesc(fmt.Sprintf("%s_%s", namespace, staticLabelName),
13761447
"Version string as reported by postgres", []string{"version", "short_version"}, server.labels)
13771448

1378-
if !e.disableDefaultMetrics && (server.master && e.autoDiscoverDatabases) {
1449+
if !e.disableDefaultMetrics && server.master {
13791450
ch <- prometheus.MustNewConstMetric(versionDesc,
13801451
prometheus.UntypedValue, 1, versionString, semanticVersion.String())
13811452
}
@@ -1440,6 +1511,7 @@ func (e *Exporter) discoverDatabaseDSNs() []string {
14401511
continue
14411512
}
14421513

1514+
// If autoDiscoverDatabases is true, set first dsn as master database (Default: false)
14431515
server.master = true
14441516

14451517
databaseNames, err := queryDatabases(server)
@@ -1468,10 +1540,16 @@ func (e *Exporter) discoverDatabaseDSNs() []string {
14681540

14691541
func (e *Exporter) scrapeDSN(ch chan<- prometheus.Metric, dsn string) error {
14701542
server, err := e.servers.GetServer(dsn)
1543+
14711544
if err != nil {
14721545
return &ErrorConnectToServer{fmt.Sprintf("Error opening connection to database (%s): %s", loggableDSN(dsn), err.Error())}
14731546
}
14741547

1548+
// Check if autoDiscoverDatabases is false, set dsn as master database (Default: false)
1549+
if !e.autoDiscoverDatabases {
1550+
server.master = true
1551+
}
1552+
14751553
// Check if map versions need to be updated
14761554
if err := e.checkMapVersions(ch, server); err != nil {
14771555
log.Warnln("Proceeding with outdated query maps, as the Postgres version could not be determined:", err)
@@ -1522,6 +1600,7 @@ func getDataSources() []string {
15221600
if len(dsn) == 0 {
15231601
var user string
15241602
var pass string
1603+
var uri string
15251604

15261605
if len(os.Getenv("DATA_SOURCE_USER_FILE")) != 0 {
15271606
fileContents, err := ioutil.ReadFile(os.Getenv("DATA_SOURCE_USER_FILE"))
@@ -1559,7 +1638,17 @@ func getDataSources() []string {
15591638
}
15601639

15611640
ui := url.UserPassword(user, pass).String()
1562-
uri := os.Getenv("DATA_SOURCE_URI")
1641+
1642+
if len(os.Getenv("DATA_SOURCE_URI_FILE")) != 0 {
1643+
fileContents, err := ioutil.ReadFile(os.Getenv("DATA_SOURCE_URI_FILE"))
1644+
if err != nil {
1645+
panic(err)
1646+
}
1647+
uri = strings.TrimSpace(string(fileContents))
1648+
} else {
1649+
uri = os.Getenv("DATA_SOURCE_URI")
1650+
}
1651+
15631652
dsn = "postgresql://" + ui + "@" + uri
15641653

15651654
return []string{dsn}
@@ -1614,6 +1703,13 @@ func main() {
16141703
exporter.servers.Close()
16151704
}()
16161705

1706+
// Setup build info metric.
1707+
version.Branch = Branch
1708+
version.BuildDate = BuildDate
1709+
version.Revision = Revision
1710+
version.Version = VersionShort
1711+
prometheus.MustRegister(version.NewCollector("postgres_exporter"))
1712+
16171713
prometheus.MustRegister(exporter)
16181714

16191715
http.Handle(*metricPath, promhttp.Handler())

cmd/postgres_exporter/postgres_exporter_integration_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ func (s *IntegrationSuite) TestUnknownMetricParsingDoesntCrash(c *C) {
117117
for k := range exporter.builtinMetricMaps {
118118
emptyMaps[k] = intermediateMetricMap{
119119
map[string]ColumnMapping{},
120+
true,
120121
0,
121122
}
122123
}

cmd/postgres_exporter/postgres_exporter_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func (s *FunctionalSuite) TestSemanticVersionColumnDiscard(c *C) {
3232
"metric_which_stays": {COUNTER, "This metric should not be eliminated", nil, nil},
3333
"metric_which_discards": {COUNTER, "This metric should be forced to DISCARD", nil, nil},
3434
},
35+
true,
3536
0,
3637
},
3738
}

0 commit comments

Comments
 (0)