Skip to content

Commit 1d03e6b

Browse files
committed
2 parents 8ee408e + 81194c9 commit 1d03e6b

File tree

953 files changed

+405676
-316
lines changed

Some content is hidden

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

953 files changed

+405676
-316
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
.build
22
postgres_exporter
3+
postgres_exporter_integration_test
34
*.tar.gz
45
*.test
56
*-stamp
67
.idea
78
*.iml
89
*.rpm
10+
cover.out
11+
cover.*.out
12+
.coverage
13+
*.prom
14+
.metrics.*.*.prom

.travis.yml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,38 @@ services:
33
- docker
44
language: go
55
go:
6-
- '1.6'
6+
- '1.8'
7+
# Make sure we have p2 and the postgres client.
8+
before_install:
9+
- go get -v github.com/mattn/goveralls
10+
- sudo wget -O /usr/local/bin/p2 https://github.com/wrouesnel/p2cli/releases/download/r4/p2 &&
11+
sudo chmod +x /usr/local/bin/p2
12+
- sudo wget -O /usr/local/bin/docker-compose https://github.com/docker/compose/releases/download/1.9.0-rc4/docker-compose-Linux-x86_64 &&
13+
sudo chmod +x /usr/local/bin/docker-compose
14+
- sudo apt-get update && sudo apt-get install postgresql-client-common
15+
716
script:
817
- make all
918
- make docker
1019
- make test-integration
20+
- make cover.out
21+
- $HOME/gopath/bin/goveralls -coverprofile=cover.out -service=travis-ci
1122
after_success:
12-
- if [ "$TRAVIS_BRANCH" == "master" ]; then docker login -e $DOCKER_EMAIL -u $DOCKER_USER
13-
-p $DOCKER_PASS ; docker push wrouesnel/postgres_exporter ; fi
23+
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
24+
# Push a tagged build if a tag is found.
25+
- if [ ! -z "$TRAVIS_TAG" ]; then
26+
docker tag wrouesnel/postgres_exporter:latest wrouesnel/postgres_exporter:$TRAVIS_TAG ;
27+
docker push wrouesnel/postgres_exporter:$TRAVIS_TAG ;
28+
fi
29+
# Push a latest version
30+
- if [ "$TRAVIS_BRANCH" == "master" ]; then docker push wrouesnel/postgres_exporter ; fi
1431
env:
1532
global:
1633
- secure: RfoWQj5tEB/t3XL2tqJW7u7Qscpz1QBOfF9lMFpB4kAUMTtZU0zBbXfMo1JheGoJQQxD/7NLRHhbUWPT2489o3KKpRTQ7RHn3k8n5U7opH01bWX0+l/EPVmhlsKjSDSLGgmxz80j3I6C8ZV3qDUijSx7r90QUNHGbZtV7g+KtoUTpRV0zir/heK6qq9LHWNHbNsJyHK8qHmd6g1UzWIBaZPJ6a/n/rO2jq4uS1JR0VlIJPRF11HOLH8IjFQvVYpN7YbEslxyNsfQJUSP/7CghSLLVWPSATEjMm8a5GJVLc564+nYghm484psEtiMXkZ3n6ie7AT8aJrKfexWrwh2aCc+cK4PiyXrf4euZehZNYogmFCqWzd1LJKcN2uIkpBSuZQDm3e6c4qkkWGpx+RdFWtAMG8IgZLDbcuryxFNzMwHc2CJ009s9Zsa+g7D57csyR5LCZ8YtNGI3g8FmhwpCKvYkfKa9aijUEWyJMyT4Vhd/w7btMTuwYHgUQ85k4ov4Xjz5SNpAGgemig5G5w7PJj4NhGvIBz9weL154x/BFVjHOZZ6Y/bWgJIPoW1KM15x5K8QylWYEBUHtwiyVyXOxHqt6MOX1vYo1L37jMK88IErrfh/VmlxEhtN9wOghk8IudMfFwQtjIwiWlJf218wxMIzUjoyb5/25tU9f2OJrg=
1734
- 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=
1835
- secure: RRQH4Tr94OblZoqls50BIoyK1OvK9fALs4pAq1Uk5dksY1NWnomheQzOaHzbVfMfXc4zXAzppZIqxUDGn8GiSLbtJL6pnxsxYNGoCGdS8lMjjKWXbCAs8TBJobi3krOOjqgbhOWTpyluTEShnBcg7CjrRQUa/ChS3uE5kl21/4eIl9Be6Q08Eqm3p1yvMAyAgIL6Y6oPAAtBa6zIsi2MSNlryz3RKHJO7AheilppYx3E8B03A+a/oqvTTcw6w/RwBYxB8MYfSLC0jSssZz5pUSX/byUaklGFhQLnKAzJyhrMOvRyMVcO4PHaLgVi1eAKQz6eLQh7uEiIqKh19cuvTbZHDgu8zMpLDTxOW9U95e4kbjOZ5pWZ7E5QTrb24RZIt42JGbmme7PWOvy3zNbWHwfwiOF1qwYwISUcj2KFCpes8mDGt6iv46LfdlU0uoZdZu3MAiTiW0u2SD5hIeFq4XYesPtkS/TKFoAbB5Tu1qbxdmYu5NqmfvmxsmeNEm4inFJ5ap3fRRCVo668Z6qRMuQ1URcEfOz8iEftP9CnwSOXRuiuMo+W9GgckRuDZcPyQMCftq8+PhB+SjK57zrAd4Kxqf6kVHV16tcWqmFjfJJUFqmL+gpjT/VMEVDY2FOnbOARjkeLTjVC4dADBjxfJ6wmlLrfHdUm4GinbaHq0iA=
1936
deploy:
37+
skip_cleanup: true
2038
provider: releases
2139
api_key:
2240
secure: rwlge/Rs3wnWyfKRhD9fd5GviVe0foYUp20DY3AjKdDjhtwScA1EeR9QHOkB3raze52en0+KkpqlLCWbt3q4CRT7+ku1DNKhd6VWALdTZ1RPJYvNlU6CKJdRnWUJsECmSBsShXlbiYR8axqNVedzFPFGKzS9gYlFN6rr7pez/JZhxqucopZ6I+TkRHMELrFXyQK7/Y2bNRCLC4a+rGsjKeLLtYXbRXCmS0G4BSJEBRk7d69fIRzBApCMfrcLftgHzPuPth616yyUusQSCQYvaZ5tlwrPP8/E0wG3SVJVeDCMuDOSBZ9M6vNzR8W8VR/hxQamegn1OQgC5kNOaLZCTcJ5xguRouqb+FNFBqrd/Zi6vESo7RiVLULawzwxkh9sIPa3WZYDb3VK/Z/cpggUeR7wAu0S5ZYEvJHRefIZpqofZEHzDE3Blqp5yErz05e/zmjpd6HHK3f/UHmRRYfbulkvGT3aL/dlq5GcFvuxVC/vTL2VPvg9cGbqtf7PakC5IhoHpDs35tOyLxifOBLHvkwtGSxEfsCohIG8Hz2XFD83EsxgOiKSXVPLNd6yxjdqZj7OeAKFFU3bzGndnRbDIXaf987IN1imgUtP6wegfImoRStqxN4gEwwIMFsZCF86Ug4eLhlajLbWhudriDxDPBM/F9950aVxLwmWh9l5cRI=

Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM scratch
2+
3+
COPY postgres_exporter /postgres_exporter
4+
5+
EXPOSE 9187
6+
7+
ENTRYPOINT [ "/postgres_exporter" ]

Makefile

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,83 @@
11

2-
GO_SRC := $(shell find -type f -name "*.go")
2+
COVERDIR = .coverage
3+
TOOLDIR = tools
4+
5+
GO_SRC := $(shell find . -name '*.go' ! -path '*/vendor/*' ! -path 'tools/*' )
6+
GO_DIRS := $(shell find . -type d -name '*.go' ! -path '*/vendor/*' ! -path 'tools/*' )
7+
GO_PKGS := $(shell go list ./... | grep -v '/vendor/')
38

49
CONTAINER_NAME ?= wrouesnel/postgres_exporter:latest
10+
VERSION ?= $(shell git describe --dirty)
11+
12+
CONCURRENT_LINTERS ?= $(shell cat /proc/cpuinfo | grep processor | wc -l)
13+
LINTER_DEADLINE ?= 30s
14+
15+
export PATH := $(TOOLDIR)/bin:$(PATH)
16+
SHELL := env PATH=$(PATH) /bin/bash
517

6-
all: vet test postgres_exporter
18+
all: style lint test postgres_exporter
19+
20+
# Cross compilation (e.g. if you are on a Mac)
21+
cross: docker-build docker
722

823
# Simple go build
924
postgres_exporter: $(GO_SRC)
10-
CGO_ENABLED=0 GOOS=linux go build -a -ldflags "-extldflags '-static' -X main.Version=git:$(shell git rev-parse HEAD)" -o postgres_exporter .
25+
CGO_ENABLED=0 go build -a -ldflags "-extldflags '-static' -X main.Version=$(VERSION)" -o postgres_exporter .
26+
27+
postgres_exporter_integration_test: $(GO_SRC)
28+
CGO_ENABLED=0 go test -c -tags integration \
29+
-a -ldflags "-extldflags '-static' -X main.Version=$(VERSION)" -o postgres_exporter_integration_test -cover -covermode count .
1130

1231
# Take a go build and turn it into a minimal container
1332
docker: postgres_exporter
14-
tar -cf - postgres_exporter | docker import --change "EXPOSE 9113" \
15-
--change 'ENTRYPOINT [ "/postgres_exporter" ]' \
16-
- $(CONTAINER_NAME)
33+
docker build -t $(CONTAINER_NAME) .
34+
35+
style: tools
36+
gometalinter --disable-all --enable=gofmt --vendor
1737

18-
vet:
19-
go vet .
38+
lint: tools
39+
@echo Using $(CONCURRENT_LINTERS) processes
40+
gometalinter -j $(CONCURRENT_LINTERS) --deadline=$(LINTER_DEADLINE) --disable=gotype --disable=gocyclo $(GO_DIRS)
2041

21-
test:
22-
go test -v .
42+
fmt: tools
43+
gofmt -s -w $(GO_SRC)
2344

24-
test-integration:
25-
tests/test-smoke
45+
test: tools
46+
@mkdir -p $(COVERDIR)
47+
@rm -f $(COVERDIR)/*
48+
for pkg in $(GO_PKGS) ; do \
49+
go test -v -covermode count -coverprofile=$(COVERDIR)/$$(echo $$pkg | tr '/' '-').out $$pkg ; \
50+
done
51+
gocovmerge $(shell find $(COVERDIR) -name '*.out') > cover.test.out
2652

2753
rpm: postgres_exporter
2854
@echo ">> building rpm"
2955
@rpmbuild -bb --define "_sourcedir $(CURDIR)" --define "_rpmdir $(CURDIR)" --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" postgres_exporter.spec
3056

31-
# Do a self-contained docker build - we pull the official upstream container,
32-
# then template out a dockerfile which builds the real image.
33-
docker-build: postgres_exporter
57+
test-integration: postgres_exporter postgres_exporter_integration_test
58+
tests/test-smoke "$(shell pwd)/postgres_exporter" "$(shell pwd)/postgres_exporter_integration_test_script $(shell pwd)/postgres_exporter_integration_test $(shell pwd)/cover.integration.out"
59+
60+
cover.out: tools
61+
gocovmerge cover.*.out > cover.out
62+
63+
# Do a self-contained docker build - we pull the official upstream container
64+
# and do a self-contained build.
65+
docker-build:
3466
docker run -v $(shell pwd):/go/src/github.com/wrouesnel/postgres_exporter \
67+
-v $(shell pwd):/real_src \
68+
-e SHELL_UID=$(shell id -u) -e SHELL_GID=$(shell id -g) \
3569
-w /go/src/github.com/wrouesnel/postgres_exporter \
36-
golang:1.6-wheezy \
37-
/bin/bash -c "make >&2 && tar -cf - ./postgres_exporter" | \
38-
docker import --change "EXPOSE 9113" \
39-
--change 'ENTRYPOINT [ "/postgres_exporter" ]' \
40-
- $(CONTAINER_NAME)
70+
golang:1.8-wheezy \
71+
/bin/bash -c "make >&2 && chown $$SHELL_UID:$$SHELL_GID ./postgres_exporter"
72+
docker build -t $(CONTAINER_NAME) .
73+
74+
push:
75+
docker push $(CONTAINER_NAME)
76+
77+
tools:
78+
$(MAKE) -C $(TOOLDIR)
79+
80+
clean:
81+
rm -f postgres_exporter postgres_exporter_integration_test
4182

42-
.PHONY: docker-build docker test vet
83+
.PHONY: tools docker-build docker lint fmt test vet push cross clean

README.md

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
[![Build Status](https://travis-ci.org/wrouesnel/postgres_exporter.svg?branch=master)](https://travis-ci.org/wrouesnel/postgres_exporter)
2+
[![Coverage Status](https://coveralls.io/repos/github/wrouesnel/postgres_exporter/badge.svg?branch=master)](https://coveralls.io/github/wrouesnel/postgres_exporter?branch=master)
3+
[![Go Report Card](https://goreportcard.com/badge/github.com/wrouesnel/postgres_exporter)](https://goreportcard.com/report/github.com/wrouesnel/postgres_exporter)
24

3-
# PostgresSQL Server Exporter
5+
# PostgreSQL Server Exporter
46

5-
Prometheus exporter for PostgresSQL server metrics.
7+
Prometheus exporter for PostgreSQL server metrics.
68
Supported Postgres versions: 9.1 and up.
79

810
## Quick Start
@@ -11,7 +13,7 @@ This package is available for Docker:
1113
# Start an example database
1214
docker run --net=host -it --rm -e POSTGRES_PASSWORD=password postgres
1315
# Connect to it
14-
docker run -e DATA_SOURCE_NAME="postgresql://postgres:password@localhost:5432/?sslmode=disable" -p 9113:9113 wrouesnel/postgres_exporter
16+
docker run -e DATA_SOURCE_NAME="postgresql://postgres:password@localhost:5432/?sslmode=disable" -p 9187:9187 wrouesnel/postgres_exporter
1517
```
1618

1719
## Building and running
@@ -34,14 +36,15 @@ Package vendoring is handled with [`govendor`](https://github.com/kardianos/gove
3436

3537
### Flags
3638

37-
Name | Description
38-
-------------------|------------
39-
web.listen-address | Address to listen on for web interface and telemetry.
40-
web.telemetry-path | Path under which to expose metrics.
39+
* `web.listen-address`
40+
Address to listen on for web interface and telemetry.
41+
42+
* `web.telemetry-path`
43+
Path under which to expose metrics.
4144

4245
### Setting the Postgres server's data source name
4346

44-
The PostgresSQL server's [data source name](http://en.wikipedia.org/wiki/Data_source_name)
47+
The PostgreSQL server's [data source name](http://en.wikipedia.org/wiki/Data_source_name)
4548
must be set via the `DATA_SOURCE_NAME` environment variable.
4649

4750
For running it locally on a default Debian/Ubuntu install, this will work (transpose to init script as appropriate):
@@ -65,6 +68,10 @@ for l in StringIO(x):
6568
Adjust the value of the resultant prometheus value type appropriately. This helps build
6669
rich self-documenting metrics for the exporter.
6770

71+
### Adding new metrics via a config file
72+
73+
The -extend.query-path command-line argument specifies a YAML file containing additional queries to run.
74+
Some examples are provided in [queries.yaml](queries.yaml).
6875

6976
### Running as non-superuser
7077

@@ -74,6 +81,8 @@ To be able to collect metrics from pg_stat_activity and pg_stat_replication as n
7481
CREATE USER postgres_exporter PASSWORD 'password';
7582
ALTER USER postgres_exporter SET SEARCH_PATH TO postgres_exporter,pg_catalog;
7683

84+
-- If deploying as non-superuser (for example in AWS RDS)
85+
-- GRANT postgres_exporter TO :MASTER_USER;
7786
CREATE SCHEMA postgres_exporter AUTHORIZATION postgres_exporter;
7887

7988
CREATE FUNCTION postgres_exporter.f_select_pg_stat_activity()
@@ -103,3 +112,9 @@ AS
103112
GRANT SELECT ON postgres_exporter.pg_stat_replication TO postgres_exporter;
104113
GRANT SELECT ON postgres_exporter.pg_stat_activity TO postgres_exporter;
105114
```
115+
116+
> **NOTE**
117+
> <br />Remember to use `postgres` database name in the connection string:
118+
> ```
119+
> DATA_SOURCE_NAME=postgresql://postgres_exporter:password@localhost:5432/postgres?sslmode=disable
120+
> ```

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() // nolint: errcheck
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 // nolint: ineffassign
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, fmt.Errorf("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 = fmt.Errorf("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+
}

0 commit comments

Comments
 (0)