@@ -31,11 +31,16 @@ import (
3131"time" 
3232
3333"github.com/blang/semver" 
34+ "github.com/go-kit/kit/log" 
35+ "github.com/go-kit/kit/log/level" 
3436"github.com/lib/pq" 
3537"github.com/prometheus/client_golang/prometheus" 
3638"github.com/prometheus/client_golang/prometheus/promhttp" 
37- "github.com/prometheus/common/log" 
39+ "github.com/prometheus/common/promlog" 
40+ "github.com/prometheus/common/promlog/flag" 
3841"github.com/prometheus/common/version" 
42+ "github.com/prometheus/exporter-toolkit/web" 
43+ webflag "github.com/prometheus/exporter-toolkit/web/kingpinflag" 
3944"gopkg.in/alecthomas/kingpin.v2" 
4045"gopkg.in/yaml.v2" 
4146)
@@ -58,6 +63,7 @@ var VersionShort = "0.0.1"
5863
5964var  (
6065listenAddress  =  kingpin .Flag ("web.listen-address" , "Address to listen on for web interface and telemetry." ).Default (":9187" ).Envar ("PG_EXPORTER_WEB_LISTEN_ADDRESS" ).String ()
66+ webConfig  =  webflag .AddFlags (kingpin .CommandLine )
6167metricPath  =  kingpin .Flag ("web.telemetry-path" , "Path under which to expose metrics." ).Default ("/metrics" ).Envar ("PG_EXPORTER_WEB_TELEMETRY_PATH" ).String ()
6268disableDefaultMetrics  =  kingpin .Flag ("disable-default-metrics" , "Do not include default metrics." ).Default ("false" ).Envar ("PG_EXPORTER_DISABLE_DEFAULT_METRICS" ).Bool ()
6369disableSettingsMetrics  =  kingpin .Flag ("disable-settings-metrics" , "Do not include pg_settings metrics." ).Default ("false" ).Envar ("PG_EXPORTER_DISABLE_SETTINGS_METRICS" ).Bool ()
6773constantLabelsList  =  kingpin .Flag ("constantLabels" , "A list of label=value separated by comma(,)." ).Default ("" ).Envar ("PG_EXPORTER_CONSTANT_LABELS" ).String ()
6874excludeDatabases  =  kingpin .Flag ("exclude-databases" , "A list of databases to remove when autoDiscoverDatabases is enabled" ).Default ("" ).Envar ("PG_EXPORTER_EXCLUDE_DATABASES" ).String ()
6975metricPrefix  =  kingpin .Flag ("metric-prefix" , "A metric prefix can be used to have non-default (not \" pg\" ) prefixes for each of the metrics" ).Default ("pg" ).Envar ("PG_EXPORTER_METRIC_PREFIX" ).String ()
76+ logger  =  log .NewNopLogger ()
7077)
7178
7279// Metric name parts. 
@@ -516,7 +523,7 @@ func makeQueryOverrideMap(pgVersion semver.Version, queryOverrides map[string][]
516523}
517524}
518525if  ! matched  {
519- log . Warnln ( " No query matched override for" ,  name ,  "-  disabling metric space." 
526+ level . Warn ( logger ). Log ( "msg" ,  " No query matched override,  disabling metric space" ,  "name" ,  name )
520527resultMap [name ] =  "" 
521528}
522529}
@@ -537,7 +544,7 @@ func parseUserQueries(content []byte) (map[string]intermediateMetricMap, map[str
537544newQueryOverrides  :=  make (map [string ]string )
538545
539546for  metric , specs  :=  range  userQueries  {
540- log . Debugln ( " New user metric namespace from YAML: "metric ,  "Will cache results for: "specs .CacheSeconds )
547+ level . Debug ( logger ). Log ( "msg" ,  " New user metric namespace from YAML metric "" metric" ,  metric ,  "cache_seconds "specs .CacheSeconds )
541548newQueryOverrides [metric ] =  specs .Query 
542549metricMap , ok  :=  metricMaps [metric ]
543550if  ! ok  {
@@ -589,9 +596,9 @@ func addQueries(content []byte, pgVersion semver.Version, server *Server) error
589596for  k , v  :=  range  partialExporterMap  {
590597_ , found  :=  server .metricMap [k ]
591598if  found  {
592- log . Debugln ( "Overriding metric "k ,  " from user YAML file." 
599+ level . Debug ( logger ). Log ( "msg ""Overriding metric  from user YAML file" ,  "metric" ,  k )
593600} else  {
594- log . Debugln ( " Adding new metric" ,  k ,  " from user YAML file." 
601+ level . Debug ( logger ). Log ( "msg" ,  " Adding new metric  from user YAML file" ,  "metric" ,  k )
595602}
596603server .metricMap [k ] =  v 
597604}
@@ -600,9 +607,9 @@ func addQueries(content []byte, pgVersion semver.Version, server *Server) error
600607for  k , v  :=  range  newQueryOverrides  {
601608_ , found  :=  server .queryOverrides [k ]
602609if  found  {
603- log . Debugln ( " Overriding query override" ,  k ,  " from user YAML file." 
610+ level . Debug ( logger ). Log ( "msg" ,  " Overriding query override  from user YAML file" ,  "query_override" ,  k )
604611} else  {
605- log . Debugln ( " Adding new query override" ,  k ,  " from user YAML file." 
612+ level . Debug ( logger ). Log ( "msg" ,  " Adding new query override  from user YAML file" ,  "query_override" ,  k )
606613}
607614server .queryOverrides [k ] =  v 
608615}
@@ -633,7 +640,7 @@ func makeDescMap(pgVersion semver.Version, serverLabels prometheus.Labels, metri
633640if  ! columnMapping .supportedVersions (pgVersion ) {
634641// It's very useful to be able to see what columns are being 
635642// rejected. 
636- log . Debugln ( columnName , "is being forced to discard due to version incompatibility."  )
643+ level . Debug ( logger ). Log ( "msg" , "Column  is being forced to discard due to version incompatibility"  ,  "column" ,  columnName )
637644thisMap [columnName ] =  MetricMap {
638645discard : true ,
639646conversion : func (_  interface {}) (float64 , bool ) {
@@ -720,7 +727,7 @@ func makeDescMap(pgVersion semver.Version, serverLabels prometheus.Labels, metri
720727case  string :
721728durationString  =  t 
722729default :
723- log . Errorln ( "DURATION  conversion metric was not a string"
730+ level . Error ( logger ). Log ( "msg" ,  "Duration  conversion metric was not a string"
724731return  math .NaN (), false 
725732}
726733
@@ -730,7 +737,7 @@ func makeDescMap(pgVersion semver.Version, serverLabels prometheus.Labels, metri
730737
731738d , err  :=  time .ParseDuration (durationString )
732739if  err  !=  nil  {
733- log . Errorln ( " Failed converting result to metric: "columnName , in , err )
740+ level . Error ( logger ). Log ( "msg" ,  " Failed converting result to metric""column" ,  columnName , "in" ,  in ,  "err" , err )
734741return  math .NaN (), false 
735742}
736743return  float64 (d  /  time .Millisecond ), true 
@@ -793,14 +800,14 @@ func dbToFloat64(t interface{}) (float64, bool) {
793800strV  :=  string (v )
794801result , err  :=  strconv .ParseFloat (strV , 64 )
795802if  err  !=  nil  {
796- log . Infoln ( " Could not parse []byte: "err )
803+ level . Info ( logger ). Log ( "msg" ,  " Could not parse []byte" ,  "err "err )
797804return  math .NaN (), false 
798805}
799806return  result , true 
800807case  string :
801808result , err  :=  strconv .ParseFloat (v , 64 )
802809if  err  !=  nil  {
803- log . Infoln ( " Could not parse string: "err )
810+ level . Info ( logger ). Log ( "msg" ,  " Could not parse string" ,  "err "err )
804811return  math .NaN (), false 
805812}
806813return  result , true 
@@ -833,14 +840,14 @@ func dbToUint64(t interface{}) (uint64, bool) {
833840strV  :=  string (v )
834841result , err  :=  strconv .ParseUint (strV , 10 , 64 )
835842if  err  !=  nil  {
836- log . Infoln ( " Could not parse []byte: "err )
843+ level . Info ( logger ). Log ( "msg" ,  " Could not parse []byte" ,  "err "err )
837844return  0 , false 
838845}
839846return  result , true 
840847case  string :
841848result , err  :=  strconv .ParseUint (v , 10 , 64 )
842849if  err  !=  nil  {
843- log . Infoln ( " Could not parse string: "err )
850+ level . Info ( logger ). Log ( "msg" ,  " Could not parse string" ,  "err "err )
844851return  0 , false 
845852}
846853return  result , true 
@@ -980,7 +987,7 @@ func NewServer(dsn string, opts ...ServerOpt) (*Server, error) {
980987db .SetMaxOpenConns (1 )
981988db .SetMaxIdleConns (1 )
982989
983- log . Infof ( " Established new database connection to %q. "fingerprint )
990+ level . Info ( logger ). Log ( "msg" ,  " Established new database connection" ,  "fingerprint "fingerprint )
984991
985992s  :=  & Server {
986993db : db ,
@@ -1007,7 +1014,7 @@ func (s *Server) Close() error {
10071014func  (s  * Server ) Ping () error  {
10081015if  err  :=  s .db .Ping (); err  !=  nil  {
10091016if  cerr  :=  s .Close (); cerr  !=  nil  {
1010- log . Errorf ( " Error while closing non-pinging DB connection to %q: %v" s , cerr )
1017+ level . Error ( logger ). Log ( "msg" ,  " Error while closing non-pinging DB connection" ,  "server" , s ,  "err" , cerr )
10111018}
10121019return  err 
10131020}
@@ -1093,7 +1100,7 @@ func (s *Servers) Close() {
10931100defer  s .m .Unlock ()
10941101for  _ , server  :=  range  s .servers  {
10951102if  err  :=  server .Close (); err  !=  nil  {
1096- log . Errorf ( "failed  to close connection to %q: %v" server , err )
1103+ level . Error ( logger ). Log ( "msg" ,  "Failed  to close connection" ,  "server" , server ,  "err" , err )
10971104}
10981105}
10991106}
@@ -1178,7 +1185,7 @@ func parseConstLabels(s string) prometheus.Labels {
11781185for  _ , p  :=  range  parts  {
11791186keyValue  :=  strings .Split (strings .TrimSpace (p ), "=" )
11801187if  len (keyValue ) !=  2  {
1181- log . Errorf ( `Wrong constant labels format %q , should be "key=value"` , p )
1188+ level . Error ( logger ). Log ( `Wrong constant labels format, should be "key=value"` ,  "input" , p )
11821189continue 
11831190}
11841191key  :=  strings .TrimSpace (keyValue [0 ])
@@ -1457,10 +1464,10 @@ func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[str
14571464scrapeStart  :=  time .Now ()
14581465
14591466for  namespace , mapping  :=  range  server .metricMap  {
1460- log . Debugln ( " Querying namespace:  "namespace )
1467+ level . Debug ( logger ). Log ( "msg" ,  " Querying namespace" ,  "namespace "namespace )
14611468
14621469if  mapping .master  &&  ! server .master  {
1463- log . Debugln ( "Query skipped..." )
1470+ level . Debug ( logger ). Log ( "msg" ,  "Query skipped..." )
14641471continue 
14651472}
14661473
@@ -1469,7 +1476,7 @@ func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[str
14691476serVersion , _  :=  semver .Parse (server .lastMapVersion .String ())
14701477runServerRange , _  :=  semver .ParseRange (server .runonserver )
14711478if  ! runServerRange (serVersion ) {
1472- log . Debugln ( " Query skipped for database version: " server .lastMapVersion .String (), " as it should be run on database server version:  " , server .runonserver )
1479+ level . Debug ( logger ). Log ( "msg" ,  " Query skipped for this  database version" ,  "version" , server .lastMapVersion .String (), "target_version " , server .runonserver )
14731480continue 
14741481}
14751482}
@@ -1500,12 +1507,12 @@ func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[str
15001507// Serious error - a namespace disappeared 
15011508if  err  !=  nil  {
15021509namespaceErrors [namespace ] =  err 
1503- log . Infoln ( err )
1510+ level . Info ( logger ). Log ( "err" ,  err )
15041511}
15051512// Non-serious errors - likely version or parsing problems. 
15061513if  len (nonFatalErrors ) >  0  {
15071514for  _ , err  :=  range  nonFatalErrors  {
1508- log . Infoln ( err . Error () )
1515+ level . Info ( logger ). Log ( "err" ,  err )
15091516}
15101517}
15111518
@@ -1532,7 +1539,7 @@ func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[str
15321539
15331540// Check and update the exporters query maps if the version has changed. 
15341541func  (e  * Exporter ) checkMapVersions (ch  chan <-  prometheus.Metric , server  * Server ) error  {
1535- log . Debugf ( " Querying Postgres Version on %q "server )
1542+ level . Debug ( logger ). Log ( "msg" ,  " Querying PostgreSQL version" ,  "server "server )
15361543versionRow  :=  server .db .QueryRow ("SELECT version();" )
15371544var  versionString  string 
15381545err  :=  versionRow .Scan (& versionString )
@@ -1544,12 +1551,12 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, server *Server)
15441551return  fmt .Errorf ("Error parsing version string on %q: %v" , server , err )
15451552}
15461553if  ! e .disableDefaultMetrics  &&  semanticVersion .LT (lowestSupportedVersion ) {
1547- log . Warnf ( " PostgreSQL version is lower on %q then  our lowest supported version! Got %s minimum supported is %s." server , semanticVersion , lowestSupportedVersion )
1554+ level . Warn ( logger ). Log ( "msg" ,  " PostgreSQL version is lower than  our lowest supported version" ,  "server" , server , "version" ,  semanticVersion ,  "lowest_supported_version" , lowestSupportedVersion )
15481555}
15491556
15501557// Check if semantic version changed and recalculate maps if needed. 
15511558if  semanticVersion .NE (server .lastMapVersion ) ||  server .metricMap  ==  nil  {
1552- log . Infof ( " Semantic Version Changed on %q: %s -> %s" server , server .lastMapVersion , semanticVersion )
1559+ level . Info ( logger ). Log ( "msg" ,  " Semantic version changed" ,  "server" , server , "from" ,  server .lastMapVersion ,  "to" , semanticVersion )
15531560server .mappingMtx .Lock ()
15541561
15551562// Get Default Metrics only for master database 
@@ -1570,13 +1577,13 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, server *Server)
15701577// Calculate the hashsum of the useQueries 
15711578userQueriesData , err  :=  ioutil .ReadFile (e .userQueriesPath )
15721579if  err  !=  nil  {
1573- log . Errorln ( " Failed to reload user queries: "e .userQueriesPath , err )
1580+ level . Error ( logger ). Log ( "msg" ,  " Failed to reload user queries""path" ,  e .userQueriesPath ,  "err" , err )
15741581e .userQueriesError .WithLabelValues (e .userQueriesPath , "" ).Set (1 )
15751582} else  {
15761583hashsumStr  :=  fmt .Sprintf ("%x" , sha256 .Sum256 (userQueriesData ))
15771584
15781585if  err  :=  addQueries (userQueriesData , semanticVersion , server ); err  !=  nil  {
1579- log . Errorln ( " Failed to reload user queries: "e .userQueriesPath , err )
1586+ level . Error ( logger ). Log ( "msg" ,  " Failed to reload user queries""path" ,  e .userQueriesPath ,  "err" , err )
15801587e .userQueriesError .WithLabelValues (e .userQueriesPath , hashsumStr ).Set (1 )
15811588} else  {
15821589// Mark user queries as successfully loaded 
@@ -1618,7 +1625,7 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) {
16181625if  err  :=  e .scrapeDSN (ch , dsn ); err  !=  nil  {
16191626errorsCount ++ 
16201627
1621- log . Errorf ( err . Error () )
1628+ level . Error (logger ). Log ( "err" ,  err )
16221629
16231630if  _ , ok  :=  err .(* ErrorConnectToServer ); ok  {
16241631connectionErrorsCount ++ 
@@ -1656,19 +1663,19 @@ func (e *Exporter) discoverDatabaseDSNs() []string {
16561663var  err  error 
16571664dsnURI , err  =  url .Parse (dsn )
16581665if  err  !=  nil  {
1659- log . Errorf ( " Unable to parse DSN as URI (%s): %v" loggableDSN (dsn ), err )
1666+ level . Error ( logger ). Log ( "msg" ,  " Unable to parse DSN as URI" ,  "dsn" , loggableDSN (dsn ),  "err" , err )
16601667continue 
16611668}
16621669} else  if  connstringRe .MatchString (dsn ) {
16631670dsnConnstring  =  dsn 
16641671} else  {
1665- log . Errorf ( " Unable to parse DSN as either URI or connstring (%s) "loggableDSN (dsn ))
1672+ level . Error ( logger ). Log ( "msg" ,  " Unable to parse DSN as either URI or connstring" ,  "dsn "loggableDSN (dsn ))
16661673continue 
16671674}
16681675
16691676server , err  :=  e .servers .GetServer (dsn )
16701677if  err  !=  nil  {
1671- log . Errorf ( " Error opening connection to database (%s): %v" loggableDSN (dsn ), err )
1678+ level . Error ( logger ). Log ( "msg" ,  " Error opening connection to database" ,  "dsn" , loggableDSN (dsn ),  "err" , err )
16721679continue 
16731680}
16741681dsns [dsn ] =  struct {}{}
@@ -1678,7 +1685,7 @@ func (e *Exporter) discoverDatabaseDSNs() []string {
16781685
16791686databaseNames , err  :=  queryDatabases (server )
16801687if  err  !=  nil  {
1681- log . Errorf ( " Error querying databases (%s): %v" loggableDSN (dsn ), err )
1688+ level . Error ( logger ). Log ( "msg" ,  " Error querying databases" ,  "dsn" , loggableDSN (dsn ),  "err" , err )
16821689continue 
16831690}
16841691for  _ , databaseName  :=  range  databaseNames  {
@@ -1722,7 +1729,7 @@ func (e *Exporter) scrapeDSN(ch chan<- prometheus.Metric, dsn string) error {
17221729
17231730// Check if map versions need to be updated 
17241731if  err  :=  e .checkMapVersions (ch , server ); err  !=  nil  {
1725- log . Warnln ( " Proceeding with outdated query maps, as the Postgres version could not be determined: "err )
1732+ level . Warn ( logger ). Log ( "msg" ,  " Proceeding with outdated query maps, as the Postgres version could not be determined" ,  "err "err )
17261733}
17271734
17281735return  server .Scrape (ch , e .disableSettingsMetrics )
@@ -1790,8 +1797,10 @@ func contains(a []string, x string) bool {
17901797
17911798func  main () {
17921799kingpin .Version (fmt .Sprintf ("postgres_exporter %s (built with %s)\n " , Version , runtime .Version ()))
1793- log .AddFlags (kingpin .CommandLine )
1800+ promlogConfig  :=  & promlog.Config {}
1801+ flag .AddFlags (kingpin .CommandLine , promlogConfig )
17941802kingpin .Parse ()
1803+ logger  =  promlog .New (promlogConfig )
17951804
17961805// landingPage contains the HTML served at '/'. 
17971806// TODO: Make this nicer and more informative. 
@@ -1811,11 +1820,13 @@ func main() {
18111820
18121821dsn , err  :=  getDataSources ()
18131822if  err  !=  nil  {
1814- log .Fatalf ("failed reading data sources: %s" , err .Error ())
1823+ level .Error (logger ).Log ("msg" , "Failed reading data sources" , "err" , err .Error ())
1824+ os .Exit (1 )
18151825}
18161826
18171827if  len (dsn ) ==  0  {
1818- log .Fatal ("couldn't find environment variables describing the datasource to use" )
1828+ level .Error (logger ).Log ("msg" , "Couldn't find environment variables describing the datasource to use" )
1829+ os .Exit (1 )
18191830}
18201831
18211832opts  :=  []ExporterOpt {
@@ -1847,6 +1858,10 @@ func main() {
18471858w .Write (landingPage ) // nolint: errcheck 
18481859})
18491860
1850- log .Infof ("Starting Server: %s" , * listenAddress )
1851- log .Fatal (http .ListenAndServe (* listenAddress , nil ))
1861+ level .Info (logger ).Log ("msg" , "Listening on address" , "address" , * listenAddress )
1862+ srv  :=  & http.Server {Addr : * listenAddress }
1863+ if  err  :=  web .ListenAndServe (srv , * webConfig , logger ); err  !=  nil  {
1864+ level .Error (logger ).Log ("msg" , "Error running HTTP server" , "err" , err )
1865+ os .Exit (1 )
1866+ }
18521867}
0 commit comments