diff --git a/collector/exporter.go b/collector/exporter.go index 0af0bc7..db0ff09 100644 --- a/collector/exporter.go +++ b/collector/exporter.go @@ -42,7 +42,7 @@ var ( // Verify if Exporter implements prometheus.Collector var _ prometheus.Collector = (*Exporter)(nil) -// Exporter collects MySQL metrics. It implements prometheus.Collector. +// Exporter collects PostgreSQL metrics. It implements prometheus.Collector. type Exporter struct { ctx context.Context dsn string @@ -89,6 +89,7 @@ func (e *Exporter) scrape(ctx context.Context, ch chan<- prometheus.Metric) { sqldb := sql.OpenDB(pgconn) // Only use one connection sqldb.SetMaxOpenConns(1) + defer sqldb.Close() db := bun.NewDB(sqldb, pgdialect.New()) // get the database version @@ -164,6 +165,7 @@ func (e *Exporter) scrape(ctx context.Context, ch chan<- prometheus.Metric) { localsqldb := sql.OpenDB(localconn) // Only use one connection localsqldb.SetMaxOpenConns(1) + defer localsqldb.Close() localdb := bun.NewDB(localsqldb, pgdialect.New()) for _, scraper := range e.scrapers { diff --git a/go.mod b/go.mod index de19491..8a9b210 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect - github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect + github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect @@ -31,6 +31,7 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/spf13/pflag v1.0.3 // indirect + github.com/stretchr/testify v1.8.2 // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index 8201649..a972748 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -48,10 +48,15 @@ github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0ua github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= github.com/uptrace/bun v1.1.12 h1:sOjDVHxNTuM6dNGaba0wUuz7KvDE1BmNu9Gqs2gJSXQ= @@ -104,6 +109,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/gengo v0.0.0-20190907103519-ebc107f98eab h1:j4L8spMe0tFfBvvW6lrc0c+Ql8+nnkcV3RYfi3eSwGY= k8s.io/gengo v0.0.0-20190907103519-ebc107f98eab/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.4.0 h1:lCJCxf/LIowc2IGS9TPjWDyXY4nOmdGdfcwwDQCOURQ= diff --git a/pg_exporter.go b/pg_exporter.go index b3a605b..7895c22 100644 --- a/pg_exporter.go +++ b/pg_exporter.go @@ -12,10 +12,12 @@ import ( "strings" "time" + "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/promlog" + "github.com/prometheus/common/promlog/flag" "github.com/prometheus/common/version" "github.com/uptrace/bun/driver/pgdriver" "gopkg.in/alecthomas/kingpin.v2" @@ -23,8 +25,6 @@ import ( "github.com/1and1/pg-exporter/collector" ) -var log = promlog.NewDynamic(&promlog.Config{}) - var ( listenAddress = kingpin.Flag( "web.listen-address", @@ -64,7 +64,7 @@ func init() { prometheus.MustRegister(version.NewCollector("pg_exporter")) } -func newHandler(metrics collector.Metrics, scrapers []collector.Scraper) http.HandlerFunc { +func newHandler(metrics collector.Metrics, scrapers []collector.Scraper, logger log.Logger) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { filteredScrapers := scrapers params := r.URL.Query()["collect[]"] @@ -74,15 +74,11 @@ func newHandler(metrics collector.Metrics, scrapers []collector.Scraper) http.Ha if v := r.Header.Get("X-Prometheus-Scrape-Timeout-Seconds"); v != "" { timeoutSeconds, err := strconv.ParseFloat(v, 64) if err != nil { - level.Error(log).Log("Failed to parse timeout from Prometheus header: %s", err) + level.Error(logger).Log("msg", "Failed to parse timeout from Prometheus header", "err", err) } else { if *timeoutOffset >= timeoutSeconds { // Ignore timeout offset if it doesn't leave time to scrape. - level.Error(log).Log( - "Timeout offset (--timeout-offset=%.2f) should be lower than prometheus scrape time (X-Prometheus-Scrape-Timeout-Seconds=%.2f).", - *timeoutOffset, - timeoutSeconds, - ) + level.Error(logger).Log("msg", "Timeout offset should be lower than prometheus scrape timeout", "offset", *timeoutOffset, "prometheus_scrape_timeout", timeoutSeconds) } else { // Subtract timeout offset from timeout. timeoutSeconds -= *timeoutOffset @@ -95,7 +91,6 @@ func newHandler(metrics collector.Metrics, scrapers []collector.Scraper) http.Ha r = r.WithContext(ctx) } } - level.Debug(log).Log("collect query:", params) // Check if we have some "collect[]" query parameters. if len(params) > 0 { @@ -144,10 +139,12 @@ func main() { } // Parse flags. - // log.AddFlags(kingpin.CommandLine) + promlogConfig := &promlog.Config{} + flag.AddFlags(kingpin.CommandLine, promlogConfig) kingpin.Version(version.Print("pg_exporter")) kingpin.HelpFlag.Short('h') kingpin.Parse() + logger := promlog.New(promlogConfig) // landingPage contains the HTML served at '/'. // TODO: Make this nicer and more informative. @@ -160,8 +157,8 @@ func main() { `) - level.Info(log).Log("Starting pg_exporter", version.Info()) - level.Info(log).Log("Build context", version.BuildContext()) + level.Info(logger).Log("Starting pg_exporter", version.Info()) + level.Info(logger).Log("Build context", version.BuildContext()) // if we have a dsn, we use this for the connection if dsn := os.Getenv("DATA_SOURCE_NAME"); dsn != "" { @@ -186,20 +183,19 @@ func main() { } } // Register only scrapers enabled by flag. - level.Info(log).Log("Enabled scrapers:") enabledScrapers := []collector.Scraper{} for scraper, enabled := range scraperFlags { if *enabled { - level.Info(log).Log(" --collect.%s", scraper.Name()) + level.Info(logger).Log("msg", "Scraper enabled", "scraper", scraper.Name()) enabledScrapers = append(enabledScrapers, scraper) } } - handlerFunc := newHandler(collector.NewMetrics(), enabledScrapers) + handlerFunc := newHandler(collector.NewMetrics(), enabledScrapers, logger) http.Handle(*metricPath, promhttp.InstrumentMetricHandler(prometheus.DefaultRegisterer, handlerFunc)) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write(landingPage) }) - level.Info(log).Log("Listening on ", *listenAddress) - level.Info(log).Log(http.ListenAndServe(*listenAddress, nil)) + level.Info(logger).Log("msg", "Listening on", "address", *listenAddress) + level.Info(logger).Log(http.ListenAndServe(*listenAddress, nil)) } diff --git a/vendor/github.com/alecthomas/units/README.md b/vendor/github.com/alecthomas/units/README.md index bee884e..57b458a 100644 --- a/vendor/github.com/alecthomas/units/README.md +++ b/vendor/github.com/alecthomas/units/README.md @@ -1,3 +1,5 @@ +[![Go Reference](https://pkg.go.dev/badge/github.com/alecthomas/units.svg)](https://pkg.go.dev/github.com/alecthomas/units) + # Units - Helpful unit multipliers and functions for Go The goal of this package is to have functionality similar to the [time](http://golang.org/pkg/time/) package. diff --git a/vendor/github.com/alecthomas/units/bytes.go b/vendor/github.com/alecthomas/units/bytes.go index 61d0ca4..f13a842 100644 --- a/vendor/github.com/alecthomas/units/bytes.go +++ b/vendor/github.com/alecthomas/units/bytes.go @@ -40,9 +40,76 @@ func (b Base2Bytes) String() string { return ToString(int64(b), 1024, "iB", "B") } -var ( - metricBytesUnitMap = MakeUnitMap("B", "B", 1000) -) +// MarshalText implement encoding.TextMarshaler to process json/yaml. +func (b Base2Bytes) MarshalText() ([]byte, error) { + return []byte(b.String()), nil +} + +// UnmarshalText implement encoding.TextUnmarshaler to process json/yaml. +func (b *Base2Bytes) UnmarshalText(text []byte) error { + n, err := ParseBase2Bytes(string(text)) + *b = n + return err +} + +// Floor returns Base2Bytes with all but the largest unit zeroed out. So that e.g. 1GiB1MiB1KiB → 1GiB. +func (b Base2Bytes) Floor() Base2Bytes { + switch { + case b > Exbibyte: + return (b / Exbibyte) * Exbibyte + case b > Pebibyte: + return (b / Pebibyte) * Pebibyte + case b > Tebibyte: + return (b / Tebibyte) * Tebibyte + case b > Gibibyte: + return (b / Gibibyte) * Gibibyte + case b > Mebibyte: + return (b / Mebibyte) * Mebibyte + case b > Kibibyte: + return (b / Kibibyte) * Kibibyte + default: + return b + } +} + +// Round returns Base2Bytes with all but the first n units zeroed out. So that e.g. 1GiB1MiB1KiB → 1GiB1MiB, if n is 2. +func (b Base2Bytes) Round(n int) Base2Bytes { + idx := 0 + + switch { + case b > Exbibyte: + idx = n + case b > Pebibyte: + idx = n + 1 + case b > Tebibyte: + idx = n + 2 + case b > Gibibyte: + idx = n + 3 + case b > Mebibyte: + idx = n + 4 + case b > Kibibyte: + idx = n + 5 + } + + switch idx { + case 1: + return b - b%Exbibyte + case 2: + return b - b%Pebibyte + case 3: + return b - b%Tebibyte + case 4: + return b - b%Gibibyte + case 5: + return b - b%Mebibyte + case 6: + return b - b%Kibibyte + default: + return b + } +} + +var metricBytesUnitMap = MakeUnitMap("B", "B", 1000) // MetricBytes are SI byte units (1000 bytes in a kilobyte). type MetricBytes SI @@ -74,6 +141,63 @@ func (m MetricBytes) String() string { return ToString(int64(m), 1000, "B", "B") } +// Floor returns MetricBytes with all but the largest unit zeroed out. So that e.g. 1GB1MB1KB → 1GB. +func (b MetricBytes) Floor() MetricBytes { + switch { + case b > Exabyte: + return (b / Exabyte) * Exabyte + case b > Petabyte: + return (b / Petabyte) * Petabyte + case b > Terabyte: + return (b / Terabyte) * Terabyte + case b > Gigabyte: + return (b / Gigabyte) * Gigabyte + case b > Megabyte: + return (b / Megabyte) * Megabyte + case b > Kilobyte: + return (b / Kilobyte) * Kilobyte + default: + return b + } +} + +// Round returns MetricBytes with all but the first n units zeroed out. So that e.g. 1GB1MB1KB → 1GB1MB, if n is 2. +func (b MetricBytes) Round(n int) MetricBytes { + idx := 0 + + switch { + case b > Exabyte: + idx = n + case b > Petabyte: + idx = n + 1 + case b > Terabyte: + idx = n + 2 + case b > Gigabyte: + idx = n + 3 + case b > Megabyte: + idx = n + 4 + case b > Kilobyte: + idx = n + 5 + } + + switch idx { + case 1: + return b - b%Exabyte + case 2: + return b - b%Petabyte + case 3: + return b - b%Terabyte + case 4: + return b - b%Gigabyte + case 5: + return b - b%Megabyte + case 6: + return b - b%Kilobyte + default: + return b + } +} + // ParseStrictBytes supports both iB and B suffixes for base 2 and metric, // respectively. That is, KiB represents 1024 and kB, KB represent 1000. func ParseStrictBytes(s string) (int64, error) { diff --git a/vendor/github.com/prometheus/common/promlog/flag/flag.go b/vendor/github.com/prometheus/common/promlog/flag/flag.go new file mode 100644 index 0000000..ec55008 --- /dev/null +++ b/vendor/github.com/prometheus/common/promlog/flag/flag.go @@ -0,0 +1,45 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package flag + +import ( + "github.com/prometheus/common/promlog" + kingpin "gopkg.in/alecthomas/kingpin.v2" +) + +// LevelFlagName is the canonical flag name to configure the allowed log level +// within Prometheus projects. +const LevelFlagName = "log.level" + +// LevelFlagHelp is the help description for the log.level flag. +const LevelFlagHelp = "Only log messages with the given severity or above. One of: [debug, info, warn, error]" + +// FormatFlagName is the canonical flag name to configure the log format +// within Prometheus projects. +const FormatFlagName = "log.format" + +// FormatFlagHelp is the help description for the log.format flag. +const FormatFlagHelp = "Output format of log messages. One of: [logfmt, json]" + +// AddFlags adds the flags used by this package to the Kingpin application. +// To use the default Kingpin application, call AddFlags(kingpin.CommandLine) +func AddFlags(a *kingpin.Application, config *promlog.Config) { + config.Level = &promlog.AllowedLevel{} + a.Flag(LevelFlagName, LevelFlagHelp). + Default("info").SetValue(config.Level) + + config.Format = &promlog.AllowedFormat{} + a.Flag(FormatFlagName, FormatFlagHelp). + Default("logfmt").SetValue(config.Format) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 85b43f8..8694920 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -2,8 +2,8 @@ ## explicit github.com/alecthomas/template github.com/alecthomas/template/parse -# github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d -## explicit +# github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 +## explicit; go 1.15 github.com/alecthomas/units # github.com/beorn7/perks v1.0.1 ## explicit; go 1.11 @@ -54,6 +54,7 @@ github.com/prometheus/common/expfmt github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg github.com/prometheus/common/model github.com/prometheus/common/promlog +github.com/prometheus/common/promlog/flag github.com/prometheus/common/version # github.com/prometheus/procfs v0.8.0 ## explicit; go 1.17 @@ -63,6 +64,8 @@ github.com/prometheus/procfs/internal/util # github.com/spf13/pflag v1.0.3 ## explicit github.com/spf13/pflag +# github.com/stretchr/testify v1.8.2 +## explicit; go 1.13 # github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc ## explicit github.com/tmthrgd/go-hex