Skip to content

Commit 0a80095

Browse files
authored
Merge branch 'master' into master
2 parents dc015cb + 53b9d9c commit 0a80095

10 files changed

+119
-34
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ postgres_exporter_integration_test
66
*-stamp
77
.idea
88
*.iml
9+
cover.out
10+
cover.*.out
11+

.travis.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ services:
33
- docker
44
language: go
55
go:
6-
- '1.7'
6+
- '1.7.5'
77
# Make sure we have p2 and the postgres client.
88
before_install:
9+
- go get -v github.com/mattn/goveralls
910
- sudo wget -O /usr/local/bin/p2 https://github.com/wrouesnel/p2cli/releases/download/r4/p2 &&
1011
sudo chmod +x /usr/local/bin/p2
1112
- sudo wget -O /usr/local/bin/docker-compose https://github.com/docker/compose/releases/download/1.9.0-rc4/docker-compose-Linux-x86_64 &&
@@ -16,6 +17,8 @@ script:
1617
- make all
1718
- make docker
1819
- make test-integration
20+
- ./concatenate_coverage cover.out cover.test.out cover.integration.out
21+
- $HOME/gopath/bin/goveralls -coverprofile=cover.out -service=travis-ci
1922
after_success:
2023
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
2124
# Push a tagged build if a tag is found.

Makefile

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,46 @@
11

2-
GO_SRC := $(shell find . -type f -name "*.go")
2+
GO_SRC := $(shell find -type f -name '*.go' ! -path '*/vendor/*')
33

44
CONTAINER_NAME ?= wrouesnel/postgres_exporter:latest
5+
VERSION ?= $(shell git describe --dirty)
56

67
all: vet test postgres_exporter
78

9+
# Cross compilation (e.g. if you are on a Mac)
10+
cross: docker-build docker
11+
812
# Simple go build
913
postgres_exporter: $(GO_SRC)
10-
CGO_ENABLED=0 go build -a -ldflags "-extldflags '-static' -X main.Version=$(shell git describe --dirty)" -o postgres_exporter .
14+
CGO_ENABLED=0 go build -a -ldflags "-extldflags '-static' -X main.Version=$(VERSION)" -o postgres_exporter .
1115

1216
postgres_exporter_integration_test: $(GO_SRC)
1317
CGO_ENABLED=0 go test -c -tags integration \
14-
-a -ldflags "-extldflags '-static' -X main.Version=git:$(shell git describe --dirty)" -o postgres_exporter_integration_test .
18+
-a -ldflags "-extldflags '-static' -X main.Version=$(VERSION)" -o postgres_exporter_integration_test -cover -covermode count .
1519

1620
# Take a go build and turn it into a minimal container
1721
docker: postgres_exporter
1822
docker build -t $(CONTAINER_NAME) .
1923

2024
vet:
21-
go vet .
25+
go vet
26+
27+
# Check code conforms to go fmt
28+
style:
29+
! gofmt -s -l $(GO_SRC) 2>&1 | read 2>/dev/null
30+
31+
# Format the code
32+
fmt:
33+
gofmt -s -w $(GO_SRC)
2234

2335
test:
24-
go test -v -cover .
36+
go test -v -covermode count -coverprofile=cover.test.out
2537

2638
test-integration: postgres_exporter postgres_exporter_integration_test
27-
tests/test-smoke ./postgres_exporter ./postgres_exporter_integration_test
39+
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"
2840

2941
# Do a self-contained docker build - we pull the official upstream container
3042
# and do a self-contained build.
31-
docker-build: postgres_exporter
43+
docker-build:
3244
docker run -v $(shell pwd):/go/src/github.com/wrouesnel/postgres_exporter \
3345
-v $(shell pwd):/real_src \
3446
-e SHELL_UID=$(shell id -u) -e SHELL_GID=$(shell id -g) \
@@ -37,4 +49,7 @@ docker-build: postgres_exporter
3749
/bin/bash -c "make >&2 && chown $$SHELL_UID:$$SHELL_GID ./postgres_exporter"
3850
docker build -t $(CONTAINER_NAME) .
3951

40-
.PHONY: docker-build docker test vet
52+
push:
53+
docker push $(CONTAINER_NAME)
54+
55+
.PHONY: docker-build docker test vet push cross

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
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

35
# PostgresSQL Server Exporter
46

@@ -108,3 +110,9 @@ AS
108110
GRANT SELECT ON postgres_exporter.pg_stat_replication TO postgres_exporter;
109111
GRANT SELECT ON postgres_exporter.pg_stat_activity TO postgres_exporter;
110112
```
113+
114+
> **NOTE**
115+
> <br />Remember to use `postgres` database name in the connection string:
116+
> ```
117+
> DATA_SOURCE_NAME=postgresql://postgres_exporter:password@localhost:5432/postgres?sslmode=disable
118+
> ```

concatenate_coverage

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
# Concatenate a list of coverage reports
3+
# Usage: concatenate_coverage <out> [[test] ...]
4+
5+
output_file=$1
6+
shift
7+
cat $1 > $output_file
8+
shift
9+
10+
for f in $@ ; do
11+
tail -n +2 $f >> $output_file
12+
done

postgres_exporter.go

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"io/ioutil"
99
"math"
1010
"net/http"
11+
"net/url"
1112
"os"
1213
"regexp"
1314
"strconv"
@@ -24,6 +25,8 @@ import (
2425

2526
var Version string = "0.0.1"
2627

28+
var db *sql.DB = nil
29+
2730
var (
2831
listenAddress = flag.String(
2932
"web.listen-address", ":9187",
@@ -146,7 +149,7 @@ type MetricMap struct {
146149

147150
// Metric descriptors for dynamically created metrics.
148151
var variableMaps = map[string]map[string]ColumnMapping{
149-
"pg_runtime_variable": map[string]ColumnMapping{
152+
"pg_runtime_variable": {
150153
"max_connections": {GAUGE, "Sets the maximum number of concurrent connections.", nil, nil},
151154
"max_files_per_process": {GAUGE, "Sets the maximum number of simultaneously open files for each server process.", nil, nil},
152155
"max_function_args": {GAUGE, "Shows the maximum number of function arguments.", nil, nil},
@@ -182,7 +185,7 @@ func dumpMaps() {
182185
}
183186

184187
var metricMaps = map[string]map[string]ColumnMapping{
185-
"pg_stat_bgwriter": map[string]ColumnMapping{
188+
"pg_stat_bgwriter": {
186189
"checkpoints_timed": {COUNTER, "Number of scheduled checkpoints that have been performed", nil, nil},
187190
"checkpoints_req": {COUNTER, "Number of requested checkpoints that have been performed", nil, nil},
188191
"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},
@@ -195,7 +198,7 @@ var metricMaps = map[string]map[string]ColumnMapping{
195198
"buffers_alloc": {COUNTER, "Number of buffers allocated", nil, nil},
196199
"stats_reset": {COUNTER, "Time at which these statistics were last reset", nil, nil},
197200
},
198-
"pg_stat_database": map[string]ColumnMapping{
201+
"pg_stat_database": {
199202
"datid": {LABEL, "OID of a database", nil, nil},
200203
"datname": {LABEL, "Name of this database", nil, nil},
201204
"numbackends": {GAUGE, "Number of backends currently connected to this database. This is the only column in this view that returns a value reflecting current state; all other columns return the accumulated values since the last reset.", nil, nil},
@@ -216,7 +219,7 @@ var metricMaps = map[string]map[string]ColumnMapping{
216219
"blk_write_time": {COUNTER, "Time spent writing data file blocks by backends in this database, in milliseconds", nil, nil},
217220
"stats_reset": {COUNTER, "Time at which these statistics were last reset", nil, nil},
218221
},
219-
"pg_stat_database_conflicts": map[string]ColumnMapping{
222+
"pg_stat_database_conflicts": {
220223
"datid": {LABEL, "OID of a database", nil, nil},
221224
"datname": {LABEL, "Name of this database", nil, nil},
222225
"confl_tablespace": {COUNTER, "Number of queries in this database that have been canceled due to dropped tablespaces", nil, nil},
@@ -225,12 +228,12 @@ var metricMaps = map[string]map[string]ColumnMapping{
225228
"confl_bufferpin": {COUNTER, "Number of queries in this database that have been canceled due to pinned buffers", nil, nil},
226229
"confl_deadlock": {COUNTER, "Number of queries in this database that have been canceled due to deadlocks", nil, nil},
227230
},
228-
"pg_locks": map[string]ColumnMapping{
231+
"pg_locks": {
229232
"datname": {LABEL, "Name of this database", nil, nil},
230233
"mode": {LABEL, "Type of Lock", nil, nil},
231234
"count": {GAUGE, "Number of locks", nil, nil},
232235
},
233-
"pg_stat_replication": map[string]ColumnMapping{
236+
"pg_stat_replication": {
234237
"procpid": {DISCARD, "Process ID of a WAL sender process", nil, semver.MustParseRange("<9.2.0")},
235238
"pid": {DISCARD, "Process ID of a WAL sender process", nil, semver.MustParseRange(">=9.2.0")},
236239
"usesysid": {DISCARD, "OID of the user logged into this WAL sender process", nil, nil},
@@ -262,7 +265,7 @@ var metricMaps = map[string]map[string]ColumnMapping{
262265
"pg_xlog_location_diff": {GAUGE, "Lag in bytes between master and slave", nil, semver.MustParseRange(">=9.2.0")},
263266
"confirmed_flush_lsn": {DISCARD, "LSN position a consumer of a slot has confirmed flushing the data received", nil, nil},
264267
},
265-
"pg_stat_activity": map[string]ColumnMapping{
268+
"pg_stat_activity": {
266269
"datname": {LABEL, "Name of this database", nil, nil},
267270
"state": {LABEL, "connection state", nil, semver.MustParseRange(">=9.2.0")},
268271
"count": {GAUGE, "number of connections in this state", nil, nil},
@@ -282,7 +285,7 @@ type OverrideQuery struct {
282285
// Overriding queries for namespaces above.
283286
// TODO: validate this is a closed set in tests, and there are no overlaps
284287
var queryOverrides = map[string][]OverrideQuery{
285-
"pg_locks": []OverrideQuery{
288+
"pg_locks": {
286289
{
287290
semver.MustParseRange(">0.0.0"),
288291
`SELECT pg_database.datname,tmp.mode,COALESCE(count,0) as count
@@ -306,7 +309,7 @@ var queryOverrides = map[string][]OverrideQuery{
306309
},
307310
},
308311

309-
"pg_stat_replication": []OverrideQuery{
312+
"pg_stat_replication": {
310313
{
311314
semver.MustParseRange(">=9.2.0"),
312315
`
@@ -326,7 +329,7 @@ var queryOverrides = map[string][]OverrideQuery{
326329
},
327330
},
328331

329-
"pg_stat_activity": []OverrideQuery{
332+
"pg_stat_activity": {
330333
// This query only works
331334
{
332335
semver.MustParseRange(">=9.2.0"),
@@ -967,6 +970,24 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, db *sql.DB) err
967970
return nil
968971
}
969972

973+
func getDB(conn string) (*sql.DB, error) {
974+
if db == nil {
975+
d, err := sql.Open("postgres", conn)
976+
if err != nil {
977+
return nil, err
978+
}
979+
err = d.Ping()
980+
if err != nil {
981+
return nil, err
982+
}
983+
d.SetMaxOpenConns(1)
984+
d.SetMaxIdleConns(1)
985+
db = d
986+
}
987+
988+
return db, nil
989+
}
990+
970991
func (e *Exporter) scrape(ch chan<- prometheus.Metric) {
971992
defer func(begun time.Time) {
972993
e.duration.Set(time.Since(begun).Seconds())
@@ -975,13 +996,17 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) {
975996
e.error.Set(0)
976997
e.totalScrapes.Inc()
977998

978-
db, err := sql.Open("postgres", e.dsn)
999+
db, err := getDB(e.dsn)
9791000
if err != nil {
980-
log.Infoln("Error opening connection to database:", err)
1001+
loggableDsn := "could not parse DATA_SOURCE_NAME"
1002+
if pDsn, pErr := url.Parse(e.dsn); pErr != nil {
1003+
pDsn.User = url.UserPassword(pDsn.User.Username(), "xxx")
1004+
loggableDsn = pDsn.String()
1005+
}
1006+
log.Infof("Error opening connection to database (%s): %s", loggableDsn, err)
9811007
e.error.Set(1)
9821008
return
9831009
}
984-
defer db.Close()
9851010

9861011
// Check if map versions need to be updated
9871012
if err := e.checkMapVersions(ch, db); err != nil {
@@ -1027,4 +1052,7 @@ func main() {
10271052

10281053
log.Infof("Starting Server: %s", *listenAddress)
10291054
log.Fatal(http.ListenAndServe(*listenAddress, nil))
1055+
if db != nil {
1056+
defer db.Close()
1057+
}
10301058
}

postgres_exporter_integration_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ import (
1111

1212
. "gopkg.in/check.v1"
1313

14-
"github.com/prometheus/client_golang/prometheus"
1514
"database/sql"
16-
_ "github.com/lib/pq"
1715
"fmt"
16+
_ "github.com/lib/pq"
17+
"github.com/prometheus/client_golang/prometheus"
1818
)
1919

2020
// Hook up gocheck into the "go test" runner.
2121
func Test(t *testing.T) { TestingT(t) }
2222

23-
type IntegrationSuite struct{
23+
type IntegrationSuite struct {
2424
e *Exporter
2525
}
2626

@@ -43,7 +43,8 @@ func (s *IntegrationSuite) TestAllNamespacesReturnResults(c *C) {
4343
// Setup a dummy channel to consume metrics
4444
ch := make(chan prometheus.Metric, 100)
4545
go func() {
46-
for _ = range ch {}
46+
for range ch {
47+
}
4748
}()
4849

4950
// Open a database connection
@@ -65,7 +66,6 @@ func (s *IntegrationSuite) TestAllNamespacesReturnResults(c *C) {
6566
}
6667
}
6768

68-
6969
// This should never happen in our test cases.
7070
errMap := queryNamespaceMappings(ch, db, s.e.metricMap, s.e.queryOverrides)
7171
if !c.Check(len(errMap), Equals, 0) {
@@ -74,4 +74,4 @@ func (s *IntegrationSuite) TestAllNamespacesReturnResults(c *C) {
7474
fmt.Println(namespace, ":", err)
7575
}
7676
}
77-
}
77+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
# This script wraps the integration test binary so it produces concatenated
3+
# test output.
4+
5+
test_binary=$1
6+
shift
7+
output_cov=$1
8+
shift
9+
10+
echo "mode: count" > $output_cov
11+
12+
test_cov=$(mktemp)
13+
$test_binary -test.coverprofile=$test_cov $@
14+
tail -n +2 $test_cov >> $output_cov
15+
rm -f $test_cov

postgres_exporter_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
package main
44

55
import (
6-
"testing"
76
. "gopkg.in/check.v1"
7+
"testing"
88

99
"github.com/blang/semver"
1010
)
1111

1212
// Hook up gocheck into the "go test" runner.
1313
func Test(t *testing.T) { TestingT(t) }
1414

15-
type FunctionalSuite struct{
15+
type FunctionalSuite struct {
1616
e *Exporter
1717
}
1818

@@ -24,9 +24,9 @@ func (s *FunctionalSuite) SetUpSuite(c *C) {
2424

2525
func (s *FunctionalSuite) TestSemanticVersionColumnDiscard(c *C) {
2626
testMetricMap := map[string]map[string]ColumnMapping{
27-
"test_namespace" : map[string]ColumnMapping{
28-
"metric_which_stays" : {COUNTER, "This metric should not be eliminated", nil, nil},
29-
"metric_which_discards" : {COUNTER, "This metric should be forced to DISCARD", nil, nil},
27+
"test_namespace": {
28+
"metric_which_stays": {COUNTER, "This metric should not be eliminated", nil, nil},
29+
"metric_which_discards": {COUNTER, "This metric should be forced to DISCARD", nil, nil},
3030
},
3131
}
3232

@@ -84,4 +84,4 @@ func (s *FunctionalSuite) TestSemanticVersionColumnDiscard(c *C) {
8484
false,
8585
)
8686
}
87-
}
87+
}

tests/test-smoke

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ smoketest_postgres() {
8181
wait_for_postgres localhost 55432
8282

8383
DATA_SOURCE_NAME="postgresql://postgres:$POSTGRES_PASSWORD@localhost:55432/?sslmode=disable" $test_binary --log.level=debug || exit $?
84+
8485
# exporter_pid=$!
8586
# trap "docker logs $CONTAINER_NAME ; docker kill $CONTAINER_NAME ; docker rm $CONTAINER_NAME ; kill $exporter_pid; exit 1" EXIT INT TERM
8687
# wait_for_exporter

0 commit comments

Comments
 (0)