8
8
"io/ioutil"
9
9
"math"
10
10
"net/http"
11
+ "net/url"
11
12
"os"
12
13
"regexp"
13
14
"strconv"
@@ -24,6 +25,8 @@ import (
24
25
25
26
var Version string = "0.0.1"
26
27
28
+ var db * sql.DB = nil
29
+
27
30
var (
28
31
listenAddress = flag .String (
29
32
"web.listen-address" , ":9187" ,
@@ -146,7 +149,7 @@ type MetricMap struct {
146
149
147
150
// Metric descriptors for dynamically created metrics.
148
151
var variableMaps = map [string ]map [string ]ColumnMapping {
149
- "pg_runtime_variable" : map [ string ] ColumnMapping {
152
+ "pg_runtime_variable" : {
150
153
"max_connections" : {GAUGE , "Sets the maximum number of concurrent connections." , nil , nil },
151
154
"max_files_per_process" : {GAUGE , "Sets the maximum number of simultaneously open files for each server process." , nil , nil },
152
155
"max_function_args" : {GAUGE , "Shows the maximum number of function arguments." , nil , nil },
@@ -182,7 +185,7 @@ func dumpMaps() {
182
185
}
183
186
184
187
var metricMaps = map [string ]map [string ]ColumnMapping {
185
- "pg_stat_bgwriter" : map [ string ] ColumnMapping {
188
+ "pg_stat_bgwriter" : {
186
189
"checkpoints_timed" : {COUNTER , "Number of scheduled checkpoints that have been performed" , nil , nil },
187
190
"checkpoints_req" : {COUNTER , "Number of requested checkpoints that have been performed" , nil , nil },
188
191
"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{
195
198
"buffers_alloc" : {COUNTER , "Number of buffers allocated" , nil , nil },
196
199
"stats_reset" : {COUNTER , "Time at which these statistics were last reset" , nil , nil },
197
200
},
198
- "pg_stat_database" : map [ string ] ColumnMapping {
201
+ "pg_stat_database" : {
199
202
"datid" : {LABEL , "OID of a database" , nil , nil },
200
203
"datname" : {LABEL , "Name of this database" , nil , nil },
201
204
"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{
216
219
"blk_write_time" : {COUNTER , "Time spent writing data file blocks by backends in this database, in milliseconds" , nil , nil },
217
220
"stats_reset" : {COUNTER , "Time at which these statistics were last reset" , nil , nil },
218
221
},
219
- "pg_stat_database_conflicts" : map [ string ] ColumnMapping {
222
+ "pg_stat_database_conflicts" : {
220
223
"datid" : {LABEL , "OID of a database" , nil , nil },
221
224
"datname" : {LABEL , "Name of this database" , nil , nil },
222
225
"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{
225
228
"confl_bufferpin" : {COUNTER , "Number of queries in this database that have been canceled due to pinned buffers" , nil , nil },
226
229
"confl_deadlock" : {COUNTER , "Number of queries in this database that have been canceled due to deadlocks" , nil , nil },
227
230
},
228
- "pg_locks" : map [ string ] ColumnMapping {
231
+ "pg_locks" : {
229
232
"datname" : {LABEL , "Name of this database" , nil , nil },
230
233
"mode" : {LABEL , "Type of Lock" , nil , nil },
231
234
"count" : {GAUGE , "Number of locks" , nil , nil },
232
235
},
233
- "pg_stat_replication" : map [ string ] ColumnMapping {
236
+ "pg_stat_replication" : {
234
237
"procpid" : {DISCARD , "Process ID of a WAL sender process" , nil , semver .MustParseRange ("<9.2.0" )},
235
238
"pid" : {DISCARD , "Process ID of a WAL sender process" , nil , semver .MustParseRange (">=9.2.0" )},
236
239
"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{
262
265
"pg_xlog_location_diff" : {GAUGE , "Lag in bytes between master and slave" , nil , semver .MustParseRange (">=9.2.0" )},
263
266
"confirmed_flush_lsn" : {DISCARD , "LSN position a consumer of a slot has confirmed flushing the data received" , nil , nil },
264
267
},
265
- "pg_stat_activity" : map [ string ] ColumnMapping {
268
+ "pg_stat_activity" : {
266
269
"datname" : {LABEL , "Name of this database" , nil , nil },
267
270
"state" : {LABEL , "connection state" , nil , semver .MustParseRange (">=9.2.0" )},
268
271
"count" : {GAUGE , "number of connections in this state" , nil , nil },
@@ -282,7 +285,7 @@ type OverrideQuery struct {
282
285
// Overriding queries for namespaces above.
283
286
// TODO: validate this is a closed set in tests, and there are no overlaps
284
287
var queryOverrides = map [string ][]OverrideQuery {
285
- "pg_locks" : [] OverrideQuery {
288
+ "pg_locks" : {
286
289
{
287
290
semver .MustParseRange (">0.0.0" ),
288
291
`SELECT pg_database.datname,tmp.mode,COALESCE(count,0) as count
@@ -306,7 +309,7 @@ var queryOverrides = map[string][]OverrideQuery{
306
309
},
307
310
},
308
311
309
- "pg_stat_replication" : [] OverrideQuery {
312
+ "pg_stat_replication" : {
310
313
{
311
314
semver .MustParseRange (">=9.2.0" ),
312
315
`
@@ -326,7 +329,7 @@ var queryOverrides = map[string][]OverrideQuery{
326
329
},
327
330
},
328
331
329
- "pg_stat_activity" : [] OverrideQuery {
332
+ "pg_stat_activity" : {
330
333
// This query only works
331
334
{
332
335
semver .MustParseRange (">=9.2.0" ),
@@ -967,6 +970,24 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, db *sql.DB) err
967
970
return nil
968
971
}
969
972
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
+
970
991
func (e * Exporter ) scrape (ch chan <- prometheus.Metric ) {
971
992
defer func (begun time.Time ) {
972
993
e .duration .Set (time .Since (begun ).Seconds ())
@@ -975,13 +996,17 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) {
975
996
e .error .Set (0 )
976
997
e .totalScrapes .Inc ()
977
998
978
- db , err := sql . Open ( "postgres" , e .dsn )
999
+ db , err := getDB ( e .dsn )
979
1000
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 )
981
1007
e .error .Set (1 )
982
1008
return
983
1009
}
984
- defer db .Close ()
985
1010
986
1011
// Check if map versions need to be updated
987
1012
if err := e .checkMapVersions (ch , db ); err != nil {
@@ -1027,4 +1052,7 @@ func main() {
1027
1052
1028
1053
log .Infof ("Starting Server: %s" , * listenAddress )
1029
1054
log .Fatal (http .ListenAndServe (* listenAddress , nil ))
1055
+ if db != nil {
1056
+ defer db .Close ()
1057
+ }
1030
1058
}
0 commit comments