From 29f6fa1891897f8a187ab692eea0f8b0dbf1cd46 Mon Sep 17 00:00:00 2001 From: Dmitry F Date: Tue, 25 May 2021 12:12:35 +0700 Subject: [PATCH 001/228] Fix replication_slot query all supported versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Филатов Дмитрий --- cmd/postgres_exporter/postgres_exporter.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index 36c524c8e..b2e9f75b4 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -430,7 +430,14 @@ var queryOverrides = map[string][]OverrideQuery{ "pg_replication_slots": { { - semver.MustParseRange(">=9.4.0"), + semver.MustParseRange(">=9.4.0 <10.0.0"), + ` + SELECT slot_name, database, active, pg_xlog_location_diff(pg_current_xlog_location(), restart_lsn) + FROM pg_replication_slots + `, + }, + { + semver.MustParseRange(">=10.0.0"), ` SELECT slot_name, database, active, pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) FROM pg_replication_slots From bc981e66c3585035c1130526488f36a7f7266680 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Thu, 1 Jul 2021 16:43:32 -0400 Subject: [PATCH 002/228] Refactor code into logical files Moves code into more manageable, logical files to group behavior together. This should help improve a developer's ability to navigate the code. Signed-off-by: Joe Adams --- cmd/postgres_exporter/datasource.go | 168 +++ cmd/postgres_exporter/main.go | 129 +++ cmd/postgres_exporter/namespace.go | 264 +++++ cmd/postgres_exporter/postgres_exporter.go | 1175 +------------------- cmd/postgres_exporter/queries.go | 303 +++++ cmd/postgres_exporter/server.go | 190 ++++ cmd/postgres_exporter/util.go | 218 ++++ 7 files changed, 1300 insertions(+), 1147 deletions(-) create mode 100644 cmd/postgres_exporter/datasource.go create mode 100644 cmd/postgres_exporter/main.go create mode 100644 cmd/postgres_exporter/namespace.go create mode 100644 cmd/postgres_exporter/queries.go create mode 100644 cmd/postgres_exporter/server.go create mode 100644 cmd/postgres_exporter/util.go diff --git a/cmd/postgres_exporter/datasource.go b/cmd/postgres_exporter/datasource.go new file mode 100644 index 000000000..3bbe2f0a7 --- /dev/null +++ b/cmd/postgres_exporter/datasource.go @@ -0,0 +1,168 @@ +// Copyright 2021 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 main + +import ( + "fmt" + "io/ioutil" + "net/url" + "os" + "regexp" + "strings" + + "github.com/go-kit/kit/log/level" + "github.com/prometheus/client_golang/prometheus" +) + +func (e *Exporter) discoverDatabaseDSNs() []string { + // connstring syntax is complex (and not sure if even regular). + // we don't need to parse it, so just superficially validate that it starts + // with a valid-ish keyword pair + connstringRe := regexp.MustCompile(`^ *[a-zA-Z0-9]+ *= *[^= ]+`) + + dsns := make(map[string]struct{}) + for _, dsn := range e.dsn { + var dsnURI *url.URL + var dsnConnstring string + + if strings.HasPrefix(dsn, "postgresql://") { + var err error + dsnURI, err = url.Parse(dsn) + if err != nil { + level.Error(logger).Log("msg", "Unable to parse DSN as URI", "dsn", loggableDSN(dsn), "err", err) + continue + } + } else if connstringRe.MatchString(dsn) { + dsnConnstring = dsn + } else { + level.Error(logger).Log("msg", "Unable to parse DSN as either URI or connstring", "dsn", loggableDSN(dsn)) + continue + } + + server, err := e.servers.GetServer(dsn) + if err != nil { + level.Error(logger).Log("msg", "Error opening connection to database", "dsn", loggableDSN(dsn), "err", err) + continue + } + dsns[dsn] = struct{}{} + + // If autoDiscoverDatabases is true, set first dsn as master database (Default: false) + server.master = true + + databaseNames, err := queryDatabases(server) + if err != nil { + level.Error(logger).Log("msg", "Error querying databases", "dsn", loggableDSN(dsn), "err", err) + continue + } + for _, databaseName := range databaseNames { + if contains(e.excludeDatabases, databaseName) { + continue + } + + if len(e.includeDatabases) != 0 && !contains(e.includeDatabases, databaseName) { + continue + } + + if dsnURI != nil { + dsnURI.Path = databaseName + dsn = dsnURI.String() + } else { + // replacing one dbname with another is complicated. + // just append new dbname to override. + dsn = fmt.Sprintf("%s dbname=%s", dsnConnstring, databaseName) + } + dsns[dsn] = struct{}{} + } + } + + result := make([]string, len(dsns)) + index := 0 + for dsn := range dsns { + result[index] = dsn + index++ + } + + return result +} + +func (e *Exporter) scrapeDSN(ch chan<- prometheus.Metric, dsn string) error { + server, err := e.servers.GetServer(dsn) + + if err != nil { + return &ErrorConnectToServer{fmt.Sprintf("Error opening connection to database (%s): %s", loggableDSN(dsn), err.Error())} + } + + // Check if autoDiscoverDatabases is false, set dsn as master database (Default: false) + if !e.autoDiscoverDatabases { + server.master = true + } + + // Check if map versions need to be updated + if err := e.checkMapVersions(ch, server); err != nil { + level.Warn(logger).Log("msg", "Proceeding with outdated query maps, as the Postgres version could not be determined", "err", err) + } + + return server.Scrape(ch, e.disableSettingsMetrics) +} + +// try to get the DataSource +// DATA_SOURCE_NAME always wins so we do not break older versions +// reading secrets from files wins over secrets in environment variables +// DATA_SOURCE_NAME > DATA_SOURCE_{USER|PASS}_FILE > DATA_SOURCE_{USER|PASS} +func getDataSources() ([]string, error) { + var dsn = os.Getenv("DATA_SOURCE_NAME") + if len(dsn) != 0 { + return strings.Split(dsn, ","), nil + } + + var user, pass, uri string + + dataSourceUserFile := os.Getenv("DATA_SOURCE_USER_FILE") + if len(dataSourceUserFile) != 0 { + fileContents, err := ioutil.ReadFile(dataSourceUserFile) + if err != nil { + return nil, fmt.Errorf("failed loading data source user file %s: %s", dataSourceUserFile, err.Error()) + } + user = strings.TrimSpace(string(fileContents)) + } else { + user = os.Getenv("DATA_SOURCE_USER") + } + + dataSourcePassFile := os.Getenv("DATA_SOURCE_PASS_FILE") + if len(dataSourcePassFile) != 0 { + fileContents, err := ioutil.ReadFile(dataSourcePassFile) + if err != nil { + return nil, fmt.Errorf("failed loading data source pass file %s: %s", dataSourcePassFile, err.Error()) + } + pass = strings.TrimSpace(string(fileContents)) + } else { + pass = os.Getenv("DATA_SOURCE_PASS") + } + + ui := url.UserPassword(user, pass).String() + dataSrouceURIFile := os.Getenv("DATA_SOURCE_URI_FILE") + if len(dataSrouceURIFile) != 0 { + fileContents, err := ioutil.ReadFile(dataSrouceURIFile) + if err != nil { + return nil, fmt.Errorf("failed loading data source URI file %s: %s", dataSrouceURIFile, err.Error()) + } + uri = strings.TrimSpace(string(fileContents)) + } else { + uri = os.Getenv("DATA_SOURCE_URI") + } + + dsn = "postgresql://" + ui + "@" + uri + + return []string{dsn}, nil +} diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go new file mode 100644 index 000000000..25f94a745 --- /dev/null +++ b/cmd/postgres_exporter/main.go @@ -0,0 +1,129 @@ +// Copyright 2021 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 main + +import ( + "net/http" + "os" + + "github.com/go-kit/kit/log" + "github.com/go-kit/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/prometheus/exporter-toolkit/web" + webflag "github.com/prometheus/exporter-toolkit/web/kingpinflag" + "gopkg.in/alecthomas/kingpin.v2" +) + +var ( + listenAddress = kingpin.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9187").Envar("PG_EXPORTER_WEB_LISTEN_ADDRESS").String() + webConfig = webflag.AddFlags(kingpin.CommandLine) + metricPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").Envar("PG_EXPORTER_WEB_TELEMETRY_PATH").String() + disableDefaultMetrics = kingpin.Flag("disable-default-metrics", "Do not include default metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_DEFAULT_METRICS").Bool() + disableSettingsMetrics = kingpin.Flag("disable-settings-metrics", "Do not include pg_settings metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_SETTINGS_METRICS").Bool() + autoDiscoverDatabases = kingpin.Flag("auto-discover-databases", "Whether to discover the databases on a server dynamically.").Default("false").Envar("PG_EXPORTER_AUTO_DISCOVER_DATABASES").Bool() + queriesPath = kingpin.Flag("extend.query-path", "Path to custom queries to run.").Default("").Envar("PG_EXPORTER_EXTEND_QUERY_PATH").String() + onlyDumpMaps = kingpin.Flag("dumpmaps", "Do not run, simply dump the maps.").Bool() + constantLabelsList = kingpin.Flag("constantLabels", "A list of label=value separated by comma(,).").Default("").Envar("PG_EXPORTER_CONSTANT_LABELS").String() + excludeDatabases = kingpin.Flag("exclude-databases", "A list of databases to remove when autoDiscoverDatabases is enabled").Default("").Envar("PG_EXPORTER_EXCLUDE_DATABASES").String() + includeDatabases = kingpin.Flag("include-databases", "A list of databases to include when autoDiscoverDatabases is enabled").Default("").Envar("PG_EXPORTER_INCLUDE_DATABASES").String() + metricPrefix = 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() + logger = log.NewNopLogger() +) + +// Metric name parts. +const ( + // Namespace for all metrics. + namespace = "pg" + // Subsystems. + exporter = "exporter" + // The name of the exporter. + exporterName = "postgres_exporter" + // Metric label used for static string data thats handy to send to Prometheus + // e.g. version + staticLabelName = "static" + // Metric label used for server identification. + serverLabelName = "server" +) + +func main() { + kingpin.Version(version.Print(exporterName)) + promlogConfig := &promlog.Config{} + flag.AddFlags(kingpin.CommandLine, promlogConfig) + kingpin.HelpFlag.Short('h') + kingpin.Parse() + logger = promlog.New(promlogConfig) + + // landingPage contains the HTML served at '/'. + // TODO: Make this nicer and more informative. + var landingPage = []byte(` + Postgres exporter + +

Postgres exporter

+

Metrics

+ + + `) + + if *onlyDumpMaps { + dumpMaps() + return + } + + dsn, err := getDataSources() + if err != nil { + level.Error(logger).Log("msg", "Failed reading data sources", "err", err.Error()) + os.Exit(1) + } + + if len(dsn) == 0 { + level.Error(logger).Log("msg", "Couldn't find environment variables describing the datasource to use") + os.Exit(1) + } + + opts := []ExporterOpt{ + DisableDefaultMetrics(*disableDefaultMetrics), + DisableSettingsMetrics(*disableSettingsMetrics), + AutoDiscoverDatabases(*autoDiscoverDatabases), + WithUserQueriesPath(*queriesPath), + WithConstantLabels(*constantLabelsList), + ExcludeDatabases(*excludeDatabases), + IncludeDatabases(*includeDatabases), + } + + exporter := NewExporter(dsn, opts...) + defer func() { + exporter.servers.Close() + }() + + prometheus.MustRegister(version.NewCollector(exporterName)) + + prometheus.MustRegister(exporter) + + http.Handle(*metricPath, promhttp.Handler()) + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=UTF-8") // nolint: errcheck + w.Write(landingPage) // nolint: errcheck + }) + + level.Info(logger).Log("msg", "Listening on address", "address", *listenAddress) + srv := &http.Server{Addr: *listenAddress} + if err := web.ListenAndServe(srv, *webConfig, logger); err != nil { + level.Error(logger).Log("msg", "Error running HTTP server", "err", err) + os.Exit(1) + } +} diff --git a/cmd/postgres_exporter/namespace.go b/cmd/postgres_exporter/namespace.go new file mode 100644 index 000000000..1b9e970ef --- /dev/null +++ b/cmd/postgres_exporter/namespace.go @@ -0,0 +1,264 @@ +// Copyright 2021 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 main + +import ( + "database/sql" + "errors" + "fmt" + "time" + + "github.com/blang/semver" + "github.com/go-kit/kit/log/level" + "github.com/lib/pq" + "github.com/prometheus/client_golang/prometheus" +) + +// Query within a namespace mapping and emit metrics. Returns fatal errors if +// the scrape fails, and a slice of errors if they were non-fatal. +func queryNamespaceMapping(server *Server, namespace string, mapping MetricMapNamespace) ([]prometheus.Metric, []error, error) { + // Check for a query override for this namespace + query, found := server.queryOverrides[namespace] + + // Was this query disabled (i.e. nothing sensible can be queried on cu + // version of PostgreSQL? + if query == "" && found { + // Return success (no pertinent data) + return []prometheus.Metric{}, []error{}, nil + } + + // Don't fail on a bad scrape of one metric + var rows *sql.Rows + var err error + + if !found { + // I've no idea how to avoid this properly at the moment, but this is + // an admin tool so you're not injecting SQL right? + rows, err = server.db.Query(fmt.Sprintf("SELECT * FROM %s;", namespace)) // nolint: gas + } else { + rows, err = server.db.Query(query) + } + if err != nil { + return []prometheus.Metric{}, []error{}, fmt.Errorf("Error running query on database %q: %s %v", server, namespace, err) + } + defer rows.Close() // nolint: errcheck + + var columnNames []string + columnNames, err = rows.Columns() + if err != nil { + return []prometheus.Metric{}, []error{}, errors.New(fmt.Sprintln("Error retrieving column list for: ", namespace, err)) + } + + // Make a lookup map for the column indices + var columnIdx = make(map[string]int, len(columnNames)) + for i, n := range columnNames { + columnIdx[n] = i + } + + var columnData = make([]interface{}, len(columnNames)) + var scanArgs = make([]interface{}, len(columnNames)) + for i := range columnData { + scanArgs[i] = &columnData[i] + } + + nonfatalErrors := []error{} + + metrics := make([]prometheus.Metric, 0) + + for rows.Next() { + err = rows.Scan(scanArgs...) + if err != nil { + return []prometheus.Metric{}, []error{}, errors.New(fmt.Sprintln("Error retrieving rows:", namespace, err)) + } + + // Get the label values for this row. + labels := make([]string, len(mapping.labels)) + for idx, label := range mapping.labels { + labels[idx], _ = dbToString(columnData[columnIdx[label]]) + } + + // Loop over column names, and match to scan data. Unknown columns + // will be filled with an untyped metric number *if* they can be + // converted to float64s. NULLs are allowed and treated as NaN. + for idx, columnName := range columnNames { + var metric prometheus.Metric + if metricMapping, ok := mapping.columnMappings[columnName]; ok { + // Is this a metricy metric? + if metricMapping.discard { + continue + } + + if metricMapping.histogram { + var keys []float64 + err = pq.Array(&keys).Scan(columnData[idx]) + if err != nil { + return []prometheus.Metric{}, []error{}, errors.New(fmt.Sprintln("Error retrieving", columnName, "buckets:", namespace, err)) + } + + var values []int64 + valuesIdx, ok := columnIdx[columnName+"_bucket"] + if !ok { + nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Missing column: ", namespace, columnName+"_bucket"))) + continue + } + err = pq.Array(&values).Scan(columnData[valuesIdx]) + if err != nil { + return []prometheus.Metric{}, []error{}, errors.New(fmt.Sprintln("Error retrieving", columnName, "bucket values:", namespace, err)) + } + + buckets := make(map[float64]uint64, len(keys)) + for i, key := range keys { + if i >= len(values) { + break + } + buckets[key] = uint64(values[i]) + } + + idx, ok = columnIdx[columnName+"_sum"] + if !ok { + nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Missing column: ", namespace, columnName+"_sum"))) + continue + } + sum, ok := dbToFloat64(columnData[idx]) + if !ok { + nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Unexpected error parsing column: ", namespace, columnName+"_sum", columnData[idx]))) + continue + } + + idx, ok = columnIdx[columnName+"_count"] + if !ok { + nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Missing column: ", namespace, columnName+"_count"))) + continue + } + count, ok := dbToUint64(columnData[idx]) + if !ok { + nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Unexpected error parsing column: ", namespace, columnName+"_count", columnData[idx]))) + continue + } + + metric = prometheus.MustNewConstHistogram( + metricMapping.desc, + count, sum, buckets, + labels..., + ) + } else { + value, ok := dbToFloat64(columnData[idx]) + if !ok { + nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Unexpected error parsing column: ", namespace, columnName, columnData[idx]))) + continue + } + // Generate the metric + metric = prometheus.MustNewConstMetric(metricMapping.desc, metricMapping.vtype, value, labels...) + } + } else { + // Unknown metric. Report as untyped if scan to float64 works, else note an error too. + metricLabel := fmt.Sprintf("%s_%s", namespace, columnName) + desc := prometheus.NewDesc(metricLabel, fmt.Sprintf("Unknown metric from %s", namespace), mapping.labels, server.labels) + + // Its not an error to fail here, since the values are + // unexpected anyway. + value, ok := dbToFloat64(columnData[idx]) + if !ok { + nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Unparseable column type - discarding: ", namespace, columnName, err))) + continue + } + metric = prometheus.MustNewConstMetric(desc, prometheus.UntypedValue, value, labels...) + } + metrics = append(metrics, metric) + } + } + return metrics, nonfatalErrors, nil +} + +// Iterate through all the namespace mappings in the exporter and run their +// queries. +func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[string]error { + // Return a map of namespace -> errors + namespaceErrors := make(map[string]error) + + scrapeStart := time.Now() + + for namespace, mapping := range server.metricMap { + level.Debug(logger).Log("msg", "Querying namespace", "namespace", namespace) + + if mapping.master && !server.master { + level.Debug(logger).Log("msg", "Query skipped...") + continue + } + + // check if the query is to be run on specific database server version range or not + if len(server.runonserver) > 0 { + serVersion, _ := semver.Parse(server.lastMapVersion.String()) + runServerRange, _ := semver.ParseRange(server.runonserver) + if !runServerRange(serVersion) { + level.Debug(logger).Log("msg", "Query skipped for this database version", "version", server.lastMapVersion.String(), "target_version", server.runonserver) + continue + } + } + + scrapeMetric := false + // Check if the metric is cached + server.cacheMtx.Lock() + cachedMetric, found := server.metricCache[namespace] + server.cacheMtx.Unlock() + // If found, check if needs refresh from cache + if found { + if scrapeStart.Sub(cachedMetric.lastScrape).Seconds() > float64(mapping.cacheSeconds) { + scrapeMetric = true + } + } else { + scrapeMetric = true + } + + var metrics []prometheus.Metric + var nonFatalErrors []error + var err error + if scrapeMetric { + metrics, nonFatalErrors, err = queryNamespaceMapping(server, namespace, mapping) + } else { + metrics = cachedMetric.metrics + } + + // Serious error - a namespace disappeared + if err != nil { + namespaceErrors[namespace] = err + level.Info(logger).Log("err", err) + } + // Non-serious errors - likely version or parsing problems. + if len(nonFatalErrors) > 0 { + for _, err := range nonFatalErrors { + level.Info(logger).Log("err", err) + } + } + + // Emit the metrics into the channel + for _, metric := range metrics { + ch <- metric + } + + if scrapeMetric { + // Only cache if metric is meaningfully cacheable + if mapping.cacheSeconds > 0 { + server.cacheMtx.Lock() + server.metricCache[namespace] = cachedMetrics{ + metrics: metrics, + lastScrape: scrapeStart, + } + server.cacheMtx.Unlock() + } + } + } + + return namespaceErrors +} diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index b2e9f75b4..158048112 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -20,74 +20,34 @@ import ( "fmt" "io/ioutil" "math" - "net/http" - "net/url" - "os" "regexp" - "strconv" "strings" - "sync" "time" "github.com/blang/semver" - "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/lib/pq" "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/prometheus/exporter-toolkit/web" - webflag "github.com/prometheus/exporter-toolkit/web/kingpinflag" - "gopkg.in/alecthomas/kingpin.v2" - "gopkg.in/yaml.v2" -) - -var ( - listenAddress = kingpin.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9187").Envar("PG_EXPORTER_WEB_LISTEN_ADDRESS").String() - webConfig = webflag.AddFlags(kingpin.CommandLine) - metricPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").Envar("PG_EXPORTER_WEB_TELEMETRY_PATH").String() - disableDefaultMetrics = kingpin.Flag("disable-default-metrics", "Do not include default metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_DEFAULT_METRICS").Bool() - disableSettingsMetrics = kingpin.Flag("disable-settings-metrics", "Do not include pg_settings metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_SETTINGS_METRICS").Bool() - autoDiscoverDatabases = kingpin.Flag("auto-discover-databases", "Whether to discover the databases on a server dynamically.").Default("false").Envar("PG_EXPORTER_AUTO_DISCOVER_DATABASES").Bool() - queriesPath = kingpin.Flag("extend.query-path", "Path to custom queries to run.").Default("").Envar("PG_EXPORTER_EXTEND_QUERY_PATH").String() - onlyDumpMaps = kingpin.Flag("dumpmaps", "Do not run, simply dump the maps.").Bool() - constantLabelsList = kingpin.Flag("constantLabels", "A list of label=value separated by comma(,).").Default("").Envar("PG_EXPORTER_CONSTANT_LABELS").String() - excludeDatabases = kingpin.Flag("exclude-databases", "A list of databases to remove when autoDiscoverDatabases is enabled").Default("").Envar("PG_EXPORTER_EXCLUDE_DATABASES").String() - includeDatabases = kingpin.Flag("include-databases", "A list of databases to include when autoDiscoverDatabases is enabled").Default("").Envar("PG_EXPORTER_INCLUDE_DATABASES").String() - metricPrefix = 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() - logger = log.NewNopLogger() -) - -// Metric name parts. -const ( - // Namespace for all metrics. - namespace = "pg" - // Subsystems. - exporter = "exporter" - // The name of the exporter. - exporterName = "postgres_exporter" - // Metric label used for static string data thats handy to send to Prometheus - // e.g. version - staticLabelName = "static" - // Metric label used for server identification. - serverLabelName = "server" ) // ColumnUsage should be one of several enum values which describe how a // queried row is to be converted to a Prometheus metric. type ColumnUsage int -// nolint: golint const ( - DISCARD ColumnUsage = iota // Ignore this column - LABEL ColumnUsage = iota // Use this column as a label - COUNTER ColumnUsage = iota // Use this column as a counter - GAUGE ColumnUsage = iota // Use this column as a gauge - MAPPEDMETRIC ColumnUsage = iota // Use this column with the supplied mapping of text values - DURATION ColumnUsage = iota // This column should be interpreted as a text duration (and converted to milliseconds) - HISTOGRAM ColumnUsage = iota // Use this column as a histogram + // DISCARD ignores a column + DISCARD ColumnUsage = iota + // LABEL identifies a column as a label + LABEL ColumnUsage = iota + // COUNTER identifies a column as a counter + COUNTER ColumnUsage = iota + // GAUGE identifies a column as a gauge + GAUGE ColumnUsage = iota + // MAPPEDMETRIC identifies a column as a mapping of text values + MAPPEDMETRIC ColumnUsage = iota + // DURATION identifies a column as a text duration (and converted to milliseconds) + DURATION ColumnUsage = iota + // HISTOGRAM identifies a column as a histogram + HISTOGRAM ColumnUsage = iota ) // UnmarshalYAML implements the yaml.Unmarshaller interface. @@ -114,21 +74,9 @@ type MappingOptions struct { SupportedVersions semver.Range `yaml:"pg_version"` // Semantic version ranges which are supported. Unsupported columns are not queried (internally converted to DISCARD). } -// nolint: golint +// Mapping represents a set of MappingOptions type Mapping map[string]MappingOptions -// nolint: golint -type UserQuery struct { - Query string `yaml:"query"` - Metrics []Mapping `yaml:"metrics"` - Master bool `yaml:"master"` // Querying only for master database - CacheSeconds uint64 `yaml:"cache_seconds"` // Number of seconds to cache the namespace result metrics for. - RunOnServer string `yaml:"runonserver"` // Querying to run on which server version -} - -// nolint: golint -type UserQueries map[string]UserQuery - // Regex used to get the "short-version" from the postgres version field. var versionRegex = regexp.MustCompile(`^\w+ ((\d+)(\.\d+)?(\.\d+)?)`) var lowestSupportedVersion = semver.MustParse("9.1.0") @@ -361,254 +309,6 @@ var builtinMetricMaps = map[string]intermediateMetricMap{ }, } -// OverrideQuery 's are run in-place of simple namespace look ups, and provide -// advanced functionality. But they have a tendency to postgres version specific. -// There aren't too many versions, so we simply store customized versions using -// the semver matching we do for columns. -type OverrideQuery struct { - versionRange semver.Range - query string -} - -// Overriding queries for namespaces above. -// TODO: validate this is a closed set in tests, and there are no overlaps -var queryOverrides = map[string][]OverrideQuery{ - "pg_locks": { - { - semver.MustParseRange(">0.0.0"), - `SELECT pg_database.datname,tmp.mode,COALESCE(count,0) as count - FROM - ( - VALUES ('accesssharelock'), - ('rowsharelock'), - ('rowexclusivelock'), - ('shareupdateexclusivelock'), - ('sharelock'), - ('sharerowexclusivelock'), - ('exclusivelock'), - ('accessexclusivelock'), - ('sireadlock') - ) AS tmp(mode) CROSS JOIN pg_database - LEFT JOIN - (SELECT database, lower(mode) AS mode,count(*) AS count - FROM pg_locks WHERE database IS NOT NULL - GROUP BY database, lower(mode) - ) AS tmp2 - ON tmp.mode=tmp2.mode and pg_database.oid = tmp2.database ORDER BY 1`, - }, - }, - - "pg_stat_replication": { - { - semver.MustParseRange(">=10.0.0"), - ` - SELECT *, - (case pg_is_in_recovery() when 't' then null else pg_current_wal_lsn() end) AS pg_current_wal_lsn, - (case pg_is_in_recovery() when 't' then null else pg_wal_lsn_diff(pg_current_wal_lsn(), pg_lsn('0/0'))::float end) AS pg_current_wal_lsn_bytes, - (case pg_is_in_recovery() when 't' then null else pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)::float end) AS pg_wal_lsn_diff - FROM pg_stat_replication - `, - }, - { - semver.MustParseRange(">=9.2.0 <10.0.0"), - ` - SELECT *, - (case pg_is_in_recovery() when 't' then null else pg_current_xlog_location() end) AS pg_current_xlog_location, - (case pg_is_in_recovery() when 't' then null else pg_xlog_location_diff(pg_current_xlog_location(), replay_location)::float end) AS pg_xlog_location_diff - FROM pg_stat_replication - `, - }, - { - semver.MustParseRange("<9.2.0"), - ` - SELECT *, - (case pg_is_in_recovery() when 't' then null else pg_current_xlog_location() end) AS pg_current_xlog_location - FROM pg_stat_replication - `, - }, - }, - - "pg_replication_slots": { - { - semver.MustParseRange(">=9.4.0 <10.0.0"), - ` - SELECT slot_name, database, active, pg_xlog_location_diff(pg_current_xlog_location(), restart_lsn) - FROM pg_replication_slots - `, - }, - { - semver.MustParseRange(">=10.0.0"), - ` - SELECT slot_name, database, active, pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) - FROM pg_replication_slots - `, - }, - }, - - "pg_stat_archiver": { - { - semver.MustParseRange(">=0.0.0"), - ` - SELECT *, - extract(epoch from now() - last_archived_time) AS last_archive_age - FROM pg_stat_archiver - `, - }, - }, - - "pg_stat_activity": { - // This query only works - { - semver.MustParseRange(">=9.2.0"), - ` - SELECT - pg_database.datname, - tmp.state, - COALESCE(count,0) as count, - COALESCE(max_tx_duration,0) as max_tx_duration - FROM - ( - VALUES ('active'), - ('idle'), - ('idle in transaction'), - ('idle in transaction (aborted)'), - ('fastpath function call'), - ('disabled') - ) AS tmp(state) CROSS JOIN pg_database - LEFT JOIN - ( - SELECT - datname, - state, - count(*) AS count, - MAX(EXTRACT(EPOCH FROM now() - xact_start))::float AS max_tx_duration - FROM pg_stat_activity GROUP BY datname,state) AS tmp2 - ON tmp.state = tmp2.state AND pg_database.datname = tmp2.datname - `, - }, - { - semver.MustParseRange("<9.2.0"), - ` - SELECT - datname, - 'unknown' AS state, - COALESCE(count(*),0) AS count, - COALESCE(MAX(EXTRACT(EPOCH FROM now() - xact_start))::float,0) AS max_tx_duration - FROM pg_stat_activity GROUP BY datname - `, - }, - }, -} - -// Convert the query override file to the version-specific query override file -// for the exporter. -func makeQueryOverrideMap(pgVersion semver.Version, queryOverrides map[string][]OverrideQuery) map[string]string { - resultMap := make(map[string]string) - for name, overrideDef := range queryOverrides { - // Find a matching semver. We make it an error to have overlapping - // ranges at test-time, so only 1 should ever match. - matched := false - for _, queryDef := range overrideDef { - if queryDef.versionRange(pgVersion) { - resultMap[name] = queryDef.query - matched = true - break - } - } - if !matched { - level.Warn(logger).Log("msg", "No query matched override, disabling metric space", "name", name) - resultMap[name] = "" - } - } - - return resultMap -} - -func parseUserQueries(content []byte) (map[string]intermediateMetricMap, map[string]string, error) { - var userQueries UserQueries - - err := yaml.Unmarshal(content, &userQueries) - if err != nil { - return nil, nil, err - } - - // Stores the loaded map representation - metricMaps := make(map[string]intermediateMetricMap) - newQueryOverrides := make(map[string]string) - - for metric, specs := range userQueries { - level.Debug(logger).Log("msg", "New user metric namespace from YAML metric", "metric", metric, "cache_seconds", specs.CacheSeconds) - newQueryOverrides[metric] = specs.Query - metricMap, ok := metricMaps[metric] - if !ok { - // Namespace for metric not found - add it. - newMetricMap := make(map[string]ColumnMapping) - metricMap = intermediateMetricMap{ - columnMappings: newMetricMap, - master: specs.Master, - cacheSeconds: specs.CacheSeconds, - } - metricMaps[metric] = metricMap - } - for _, metric := range specs.Metrics { - for name, mappingOption := range metric { - var columnMapping ColumnMapping - tmpUsage, _ := stringToColumnUsage(mappingOption.Usage) - columnMapping.usage = tmpUsage - columnMapping.description = mappingOption.Description - - // TODO: we should support cu - columnMapping.mapping = nil - // Should we support this for users? - columnMapping.supportedVersions = nil - - metricMap.columnMappings[name] = columnMapping - } - } - } - return metricMaps, newQueryOverrides, nil -} - -// Add queries to the builtinMetricMaps and queryOverrides maps. Added queries do not -// respect version requirements, because it is assumed that the user knows -// what they are doing with their version of postgres. -// -// This function modifies metricMap and queryOverrideMap to contain the new -// queries. -// TODO: test code for all cu. -// TODO: the YAML this supports is "non-standard" - we should move away from it. -func addQueries(content []byte, pgVersion semver.Version, server *Server) error { - metricMaps, newQueryOverrides, err := parseUserQueries(content) - if err != nil { - return err - } - // Convert the loaded metric map into exporter representation - partialExporterMap := makeDescMap(pgVersion, server.labels, metricMaps) - - // Merge the two maps (which are now quite flatteend) - for k, v := range partialExporterMap { - _, found := server.metricMap[k] - if found { - level.Debug(logger).Log("msg", "Overriding metric from user YAML file", "metric", k) - } else { - level.Debug(logger).Log("msg", "Adding new metric from user YAML file", "metric", k) - } - server.metricMap[k] = v - } - - // Merge the query override map - for k, v := range newQueryOverrides { - _, found := server.queryOverrides[k] - if found { - level.Debug(logger).Log("msg", "Overriding query override from user YAML file", "query_override", k) - } else { - level.Debug(logger).Log("msg", "Adding new query override from user YAML file", "query_override", k) - } - server.queryOverrides[k] = v - } - return nil -} - // Turn the MetricMap column mapping into a prometheus descriptor mapping. func makeDescMap(pgVersion semver.Version, serverLabels prometheus.Labels, metricMaps map[string]intermediateMetricMap) map[string]MetricMapNamespace { var metricMap = make(map[string]MetricMapNamespace) @@ -745,359 +445,11 @@ func makeDescMap(pgVersion semver.Version, serverLabels prometheus.Labels, metri return metricMap } -// convert a string to the corresponding ColumnUsage -func stringToColumnUsage(s string) (ColumnUsage, error) { - var u ColumnUsage - var err error - switch s { - case "DISCARD": - u = DISCARD - - case "LABEL": - u = LABEL - - case "COUNTER": - u = COUNTER - - case "GAUGE": - u = GAUGE - - case "HISTOGRAM": - u = HISTOGRAM - - case "MAPPEDMETRIC": - u = MAPPEDMETRIC - - case "DURATION": - u = DURATION - - default: - err = fmt.Errorf("wrong ColumnUsage given : %s", s) - } - - return u, err -} - -// Convert database.sql types to float64s for Prometheus consumption. Null types are mapped to NaN. string and []byte -// types are mapped as NaN and !ok -func dbToFloat64(t interface{}) (float64, bool) { - switch v := t.(type) { - case int64: - return float64(v), true - case float64: - return v, true - case time.Time: - return float64(v.Unix()), true - case []byte: - // Try and convert to string and then parse to a float64 - strV := string(v) - result, err := strconv.ParseFloat(strV, 64) - if err != nil { - level.Info(logger).Log("msg", "Could not parse []byte", "err", err) - return math.NaN(), false - } - return result, true - case string: - result, err := strconv.ParseFloat(v, 64) - if err != nil { - level.Info(logger).Log("msg", "Could not parse string", "err", err) - return math.NaN(), false - } - return result, true - case bool: - if v { - return 1.0, true - } - return 0.0, true - case nil: - return math.NaN(), true - default: - return math.NaN(), false - } -} - -// Convert database.sql types to uint64 for Prometheus consumption. Null types are mapped to 0. string and []byte -// types are mapped as 0 and !ok -func dbToUint64(t interface{}) (uint64, bool) { - switch v := t.(type) { - case uint64: - return v, true - case int64: - return uint64(v), true - case float64: - return uint64(v), true - case time.Time: - return uint64(v.Unix()), true - case []byte: - // Try and convert to string and then parse to a uint64 - strV := string(v) - result, err := strconv.ParseUint(strV, 10, 64) - if err != nil { - level.Info(logger).Log("msg", "Could not parse []byte", "err", err) - return 0, false - } - return result, true - case string: - result, err := strconv.ParseUint(v, 10, 64) - if err != nil { - level.Info(logger).Log("msg", "Could not parse string", "err", err) - return 0, false - } - return result, true - case bool: - if v { - return 1, true - } - return 0, true - case nil: - return 0, true - default: - return 0, false - } -} - -// Convert database.sql to string for Prometheus labels. Null types are mapped to empty strings. -func dbToString(t interface{}) (string, bool) { - switch v := t.(type) { - case int64: - return fmt.Sprintf("%v", v), true - case float64: - return fmt.Sprintf("%v", v), true - case time.Time: - return fmt.Sprintf("%v", v.Unix()), true - case nil: - return "", true - case []byte: - // Try and convert to string - return string(v), true - case string: - return v, true - case bool: - if v { - return "true", true - } - return "false", true - default: - return "", false - } -} - -func parseFingerprint(url string) (string, error) { - dsn, err := pq.ParseURL(url) - if err != nil { - dsn = url - } - - pairs := strings.Split(dsn, " ") - kv := make(map[string]string, len(pairs)) - for _, pair := range pairs { - splitted := strings.SplitN(pair, "=", 2) - if len(splitted) != 2 { - return "", fmt.Errorf("malformed dsn %q", dsn) - } - kv[splitted[0]] = splitted[1] - } - - var fingerprint string - - if host, ok := kv["host"]; ok { - fingerprint += host - } else { - fingerprint += "localhost" - } - - if port, ok := kv["port"]; ok { - fingerprint += ":" + port - } else { - fingerprint += ":5432" - } - - return fingerprint, nil -} - -func loggableDSN(dsn string) string { - pDSN, err := url.Parse(dsn) - if err != nil { - return "could not parse DATA_SOURCE_NAME" - } - // Blank user info if not nil - if pDSN.User != nil { - pDSN.User = url.UserPassword(pDSN.User.Username(), "PASSWORD_REMOVED") - } - - return pDSN.String() -} - type cachedMetrics struct { metrics []prometheus.Metric lastScrape time.Time } -// Server describes a connection to Postgres. -// Also it contains metrics map and query overrides. -type Server struct { - db *sql.DB - labels prometheus.Labels - master bool - runonserver string - - // Last version used to calculate metric map. If mismatch on scrape, - // then maps are recalculated. - lastMapVersion semver.Version - // Currently active metric map - metricMap map[string]MetricMapNamespace - // Currently active query overrides - queryOverrides map[string]string - mappingMtx sync.RWMutex - // Currently cached metrics - metricCache map[string]cachedMetrics - cacheMtx sync.Mutex -} - -// ServerOpt configures a server. -type ServerOpt func(*Server) - -// ServerWithLabels configures a set of labels. -func ServerWithLabels(labels prometheus.Labels) ServerOpt { - return func(s *Server) { - for k, v := range labels { - s.labels[k] = v - } - } -} - -// NewServer establishes a new connection using DSN. -func NewServer(dsn string, opts ...ServerOpt) (*Server, error) { - fingerprint, err := parseFingerprint(dsn) - if err != nil { - return nil, err - } - - db, err := sql.Open("postgres", dsn) - if err != nil { - return nil, err - } - db.SetMaxOpenConns(1) - db.SetMaxIdleConns(1) - - level.Info(logger).Log("msg", "Established new database connection", "fingerprint", fingerprint) - - s := &Server{ - db: db, - master: false, - labels: prometheus.Labels{ - serverLabelName: fingerprint, - }, - metricCache: make(map[string]cachedMetrics), - } - - for _, opt := range opts { - opt(s) - } - - return s, nil -} - -// Close disconnects from Postgres. -func (s *Server) Close() error { - return s.db.Close() -} - -// Ping checks connection availability and possibly invalidates the connection if it fails. -func (s *Server) Ping() error { - if err := s.db.Ping(); err != nil { - if cerr := s.Close(); cerr != nil { - level.Error(logger).Log("msg", "Error while closing non-pinging DB connection", "server", s, "err", cerr) - } - return err - } - return nil -} - -// String returns server's fingerprint. -func (s *Server) String() string { - return s.labels[serverLabelName] -} - -// Scrape loads metrics. -func (s *Server) Scrape(ch chan<- prometheus.Metric, disableSettingsMetrics bool) error { - s.mappingMtx.RLock() - defer s.mappingMtx.RUnlock() - - var err error - - if !disableSettingsMetrics && s.master { - if err = querySettings(ch, s); err != nil { - err = fmt.Errorf("error retrieving settings: %s", err) - } - } - - errMap := queryNamespaceMappings(ch, s) - if len(errMap) > 0 { - err = fmt.Errorf("queryNamespaceMappings returned %d errors", len(errMap)) - } - - return err -} - -// Servers contains a collection of servers to Postgres. -type Servers struct { - m sync.Mutex - servers map[string]*Server - opts []ServerOpt -} - -// NewServers creates a collection of servers to Postgres. -func NewServers(opts ...ServerOpt) *Servers { - return &Servers{ - servers: make(map[string]*Server), - opts: opts, - } -} - -// GetServer returns established connection from a collection. -func (s *Servers) GetServer(dsn string) (*Server, error) { - s.m.Lock() - defer s.m.Unlock() - var err error - var ok bool - errCount := 0 // start at zero because we increment before doing work - retries := 1 - var server *Server - for { - if errCount++; errCount > retries { - return nil, err - } - server, ok = s.servers[dsn] - if !ok { - server, err = NewServer(dsn, s.opts...) - if err != nil { - time.Sleep(time.Duration(errCount) * time.Second) - continue - } - s.servers[dsn] = server - } - if err = server.Ping(); err != nil { - delete(s.servers, dsn) - time.Sleep(time.Duration(errCount) * time.Second) - continue - } - break - } - return server, nil -} - -// Close disconnects from all known servers. -func (s *Servers) Close() { - s.m.Lock() - defer s.m.Unlock() - for _, server := range s.servers { - if err := server.Close(); err != nil { - level.Error(logger).Log("msg", "Failed to close connection", "server", server, "err", err) - } - } -} - // Exporter collects Postgres metrics. It implements prometheus.Collector. type Exporter struct { // Holds a reference to the build in column mappings. Currently this is for testing purposes @@ -1214,15 +566,11 @@ func NewExporter(dsn []string, opts ...ExporterOpt) *Exporter { } e.setupInternalMetrics() - e.setupServers() + e.servers = NewServers(ServerWithLabels(e.constantLabels)) return e } -func (e *Exporter) setupServers() { - e.servers = NewServers(ServerWithLabels(e.constantLabels)) -} - func (e *Exporter) setupInternalMetrics() { e.duration = prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: namespace, @@ -1282,277 +630,29 @@ func newDesc(subsystem, name, help string, labels prometheus.Labels) *prometheus ) } -func queryDatabases(server *Server) ([]string, error) { - rows, err := server.db.Query("SELECT datname FROM pg_database WHERE datallowconn = true AND datistemplate = false AND datname != current_database()") - if err != nil { - return nil, fmt.Errorf("Error retrieving databases: %v", err) - } - defer rows.Close() // nolint: errcheck - - var databaseName string - result := make([]string, 0) - for rows.Next() { - err = rows.Scan(&databaseName) - if err != nil { - return nil, errors.New(fmt.Sprintln("Error retrieving rows:", err)) - } - result = append(result, databaseName) - } - - return result, nil -} - -// Query within a namespace mapping and emit metrics. Returns fatal errors if -// the scrape fails, and a slice of errors if they were non-fatal. -func queryNamespaceMapping(server *Server, namespace string, mapping MetricMapNamespace) ([]prometheus.Metric, []error, error) { - // Check for a query override for this namespace - query, found := server.queryOverrides[namespace] - - // Was this query disabled (i.e. nothing sensible can be queried on cu - // version of PostgreSQL? - if query == "" && found { - // Return success (no pertinent data) - return []prometheus.Metric{}, []error{}, nil - } - - // Don't fail on a bad scrape of one metric - var rows *sql.Rows - var err error - - if !found { - // I've no idea how to avoid this properly at the moment, but this is - // an admin tool so you're not injecting SQL right? - rows, err = server.db.Query(fmt.Sprintf("SELECT * FROM %s;", namespace)) // nolint: gas - } else { - rows, err = server.db.Query(query) - } +func checkPostgresVersion(db *sql.DB, server string) (semver.Version, string, error) { + level.Debug(logger).Log("msg", "Querying PostgreSQL version", "server", server) + versionRow := db.QueryRow("SELECT version();") + var versionString string + err := versionRow.Scan(&versionString) if err != nil { - return []prometheus.Metric{}, []error{}, fmt.Errorf("Error running query on database %q: %s %v", server, namespace, err) + return semver.Version{}, "", fmt.Errorf("Error scanning version string on %q: %v", server, err) } - defer rows.Close() // nolint: errcheck - - var columnNames []string - columnNames, err = rows.Columns() + semanticVersion, err := parseVersion(versionString) if err != nil { - return []prometheus.Metric{}, []error{}, errors.New(fmt.Sprintln("Error retrieving column list for: ", namespace, err)) - } - - // Make a lookup map for the column indices - var columnIdx = make(map[string]int, len(columnNames)) - for i, n := range columnNames { - columnIdx[n] = i - } - - var columnData = make([]interface{}, len(columnNames)) - var scanArgs = make([]interface{}, len(columnNames)) - for i := range columnData { - scanArgs[i] = &columnData[i] - } - - nonfatalErrors := []error{} - - metrics := make([]prometheus.Metric, 0) - - for rows.Next() { - err = rows.Scan(scanArgs...) - if err != nil { - return []prometheus.Metric{}, []error{}, errors.New(fmt.Sprintln("Error retrieving rows:", namespace, err)) - } - - // Get the label values for this row. - labels := make([]string, len(mapping.labels)) - for idx, label := range mapping.labels { - labels[idx], _ = dbToString(columnData[columnIdx[label]]) - } - - // Loop over column names, and match to scan data. Unknown columns - // will be filled with an untyped metric number *if* they can be - // converted to float64s. NULLs are allowed and treated as NaN. - for idx, columnName := range columnNames { - var metric prometheus.Metric - if metricMapping, ok := mapping.columnMappings[columnName]; ok { - // Is this a metricy metric? - if metricMapping.discard { - continue - } - - if metricMapping.histogram { - var keys []float64 - err = pq.Array(&keys).Scan(columnData[idx]) - if err != nil { - return []prometheus.Metric{}, []error{}, errors.New(fmt.Sprintln("Error retrieving", columnName, "buckets:", namespace, err)) - } - - var values []int64 - valuesIdx, ok := columnIdx[columnName+"_bucket"] - if !ok { - nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Missing column: ", namespace, columnName+"_bucket"))) - continue - } - err = pq.Array(&values).Scan(columnData[valuesIdx]) - if err != nil { - return []prometheus.Metric{}, []error{}, errors.New(fmt.Sprintln("Error retrieving", columnName, "bucket values:", namespace, err)) - } - - buckets := make(map[float64]uint64, len(keys)) - for i, key := range keys { - if i >= len(values) { - break - } - buckets[key] = uint64(values[i]) - } - - idx, ok = columnIdx[columnName+"_sum"] - if !ok { - nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Missing column: ", namespace, columnName+"_sum"))) - continue - } - sum, ok := dbToFloat64(columnData[idx]) - if !ok { - nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Unexpected error parsing column: ", namespace, columnName+"_sum", columnData[idx]))) - continue - } - - idx, ok = columnIdx[columnName+"_count"] - if !ok { - nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Missing column: ", namespace, columnName+"_count"))) - continue - } - count, ok := dbToUint64(columnData[idx]) - if !ok { - nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Unexpected error parsing column: ", namespace, columnName+"_count", columnData[idx]))) - continue - } - - metric = prometheus.MustNewConstHistogram( - metricMapping.desc, - count, sum, buckets, - labels..., - ) - } else { - value, ok := dbToFloat64(columnData[idx]) - if !ok { - nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Unexpected error parsing column: ", namespace, columnName, columnData[idx]))) - continue - } - // Generate the metric - metric = prometheus.MustNewConstMetric(metricMapping.desc, metricMapping.vtype, value, labels...) - } - } else { - // Unknown metric. Report as untyped if scan to float64 works, else note an error too. - metricLabel := fmt.Sprintf("%s_%s", namespace, columnName) - desc := prometheus.NewDesc(metricLabel, fmt.Sprintf("Unknown metric from %s", namespace), mapping.labels, server.labels) - - // Its not an error to fail here, since the values are - // unexpected anyway. - value, ok := dbToFloat64(columnData[idx]) - if !ok { - nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Unparseable column type - discarding: ", namespace, columnName, err))) - continue - } - metric = prometheus.MustNewConstMetric(desc, prometheus.UntypedValue, value, labels...) - } - metrics = append(metrics, metric) - } - } - return metrics, nonfatalErrors, nil -} - -// Iterate through all the namespace mappings in the exporter and run their -// queries. -func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[string]error { - // Return a map of namespace -> errors - namespaceErrors := make(map[string]error) - - scrapeStart := time.Now() - - for namespace, mapping := range server.metricMap { - level.Debug(logger).Log("msg", "Querying namespace", "namespace", namespace) - - if mapping.master && !server.master { - level.Debug(logger).Log("msg", "Query skipped...") - continue - } - - // check if the query is to be run on specific database server version range or not - if len(server.runonserver) > 0 { - serVersion, _ := semver.Parse(server.lastMapVersion.String()) - runServerRange, _ := semver.ParseRange(server.runonserver) - if !runServerRange(serVersion) { - level.Debug(logger).Log("msg", "Query skipped for this database version", "version", server.lastMapVersion.String(), "target_version", server.runonserver) - continue - } - } - - scrapeMetric := false - // Check if the metric is cached - server.cacheMtx.Lock() - cachedMetric, found := server.metricCache[namespace] - server.cacheMtx.Unlock() - // If found, check if needs refresh from cache - if found { - if scrapeStart.Sub(cachedMetric.lastScrape).Seconds() > float64(mapping.cacheSeconds) { - scrapeMetric = true - } - } else { - scrapeMetric = true - } - - var metrics []prometheus.Metric - var nonFatalErrors []error - var err error - if scrapeMetric { - metrics, nonFatalErrors, err = queryNamespaceMapping(server, namespace, mapping) - } else { - metrics = cachedMetric.metrics - } - - // Serious error - a namespace disappeared - if err != nil { - namespaceErrors[namespace] = err - level.Info(logger).Log("err", err) - } - // Non-serious errors - likely version or parsing problems. - if len(nonFatalErrors) > 0 { - for _, err := range nonFatalErrors { - level.Info(logger).Log("err", err) - } - } - - // Emit the metrics into the channel - for _, metric := range metrics { - ch <- metric - } - - if scrapeMetric { - // Only cache if metric is meaningfully cacheable - if mapping.cacheSeconds > 0 { - server.cacheMtx.Lock() - server.metricCache[namespace] = cachedMetrics{ - metrics: metrics, - lastScrape: scrapeStart, - } - server.cacheMtx.Unlock() - } - } + return semver.Version{}, "", fmt.Errorf("Error parsing version string on %q: %v", server, err) } - return namespaceErrors + return semanticVersion, versionString, nil } // Check and update the exporters query maps if the version has changed. func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, server *Server) error { - level.Debug(logger).Log("msg", "Querying PostgreSQL version", "server", server) - versionRow := server.db.QueryRow("SELECT version();") - var versionString string - err := versionRow.Scan(&versionString) - if err != nil { - return fmt.Errorf("Error scanning version string on %q: %v", server, err) - } - semanticVersion, err := parseVersion(versionString) + semanticVersion, versionString, err := checkPostgresVersion(server.db, server.String()) if err != nil { - return fmt.Errorf("Error parsing version string on %q: %v", server, err) + return fmt.Errorf("Error fetching version string on %q: %v", server, err) } + if !e.disableDefaultMetrics && semanticVersion.LT(lowestSupportedVersion) { level.Warn(logger).Log("msg", "PostgreSQL version is lower than our lowest supported version", "server", server, "version", semanticVersion, "lowest_supported_version", lowestSupportedVersion) } @@ -1650,222 +750,3 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) { e.error.Set(1) } } - -func (e *Exporter) discoverDatabaseDSNs() []string { - // connstring syntax is complex (and not sure if even regular). - // we don't need to parse it, so just superficially validate that it starts - // with a valid-ish keyword pair - connstringRe := regexp.MustCompile(`^ *[a-zA-Z0-9]+ *= *[^= ]+`) - - dsns := make(map[string]struct{}) - for _, dsn := range e.dsn { - var dsnURI *url.URL - var dsnConnstring string - - if strings.HasPrefix(dsn, "postgresql://") { - var err error - dsnURI, err = url.Parse(dsn) - if err != nil { - level.Error(logger).Log("msg", "Unable to parse DSN as URI", "dsn", loggableDSN(dsn), "err", err) - continue - } - } else if connstringRe.MatchString(dsn) { - dsnConnstring = dsn - } else { - level.Error(logger).Log("msg", "Unable to parse DSN as either URI or connstring", "dsn", loggableDSN(dsn)) - continue - } - - server, err := e.servers.GetServer(dsn) - if err != nil { - level.Error(logger).Log("msg", "Error opening connection to database", "dsn", loggableDSN(dsn), "err", err) - continue - } - dsns[dsn] = struct{}{} - - // If autoDiscoverDatabases is true, set first dsn as master database (Default: false) - server.master = true - - databaseNames, err := queryDatabases(server) - if err != nil { - level.Error(logger).Log("msg", "Error querying databases", "dsn", loggableDSN(dsn), "err", err) - continue - } - for _, databaseName := range databaseNames { - if contains(e.excludeDatabases, databaseName) { - continue - } - - if len(e.includeDatabases) != 0 && !contains(e.includeDatabases, databaseName) { - continue - } - - if dsnURI != nil { - dsnURI.Path = databaseName - dsn = dsnURI.String() - } else { - // replacing one dbname with another is complicated. - // just append new dbname to override. - dsn = fmt.Sprintf("%s dbname=%s", dsnConnstring, databaseName) - } - dsns[dsn] = struct{}{} - } - } - - result := make([]string, len(dsns)) - index := 0 - for dsn := range dsns { - result[index] = dsn - index++ - } - - return result -} - -func (e *Exporter) scrapeDSN(ch chan<- prometheus.Metric, dsn string) error { - server, err := e.servers.GetServer(dsn) - - if err != nil { - return &ErrorConnectToServer{fmt.Sprintf("Error opening connection to database (%s): %s", loggableDSN(dsn), err.Error())} - } - - // Check if autoDiscoverDatabases is false, set dsn as master database (Default: false) - if !e.autoDiscoverDatabases { - server.master = true - } - - // Check if map versions need to be updated - if err := e.checkMapVersions(ch, server); err != nil { - level.Warn(logger).Log("msg", "Proceeding with outdated query maps, as the Postgres version could not be determined", "err", err) - } - - return server.Scrape(ch, e.disableSettingsMetrics) -} - -// try to get the DataSource -// DATA_SOURCE_NAME always wins so we do not break older versions -// reading secrets from files wins over secrets in environment variables -// DATA_SOURCE_NAME > DATA_SOURCE_{USER|PASS}_FILE > DATA_SOURCE_{USER|PASS} -func getDataSources() ([]string, error) { - var dsn = os.Getenv("DATA_SOURCE_NAME") - if len(dsn) != 0 { - return strings.Split(dsn, ","), nil - } - - var user, pass, uri string - - dataSourceUserFile := os.Getenv("DATA_SOURCE_USER_FILE") - if len(dataSourceUserFile) != 0 { - fileContents, err := ioutil.ReadFile(dataSourceUserFile) - if err != nil { - return nil, fmt.Errorf("failed loading data source user file %s: %s", dataSourceUserFile, err.Error()) - } - user = strings.TrimSpace(string(fileContents)) - } else { - user = os.Getenv("DATA_SOURCE_USER") - } - - dataSourcePassFile := os.Getenv("DATA_SOURCE_PASS_FILE") - if len(dataSourcePassFile) != 0 { - fileContents, err := ioutil.ReadFile(dataSourcePassFile) - if err != nil { - return nil, fmt.Errorf("failed loading data source pass file %s: %s", dataSourcePassFile, err.Error()) - } - pass = strings.TrimSpace(string(fileContents)) - } else { - pass = os.Getenv("DATA_SOURCE_PASS") - } - - ui := url.UserPassword(user, pass).String() - dataSrouceURIFile := os.Getenv("DATA_SOURCE_URI_FILE") - if len(dataSrouceURIFile) != 0 { - fileContents, err := ioutil.ReadFile(dataSrouceURIFile) - if err != nil { - return nil, fmt.Errorf("failed loading data source URI file %s: %s", dataSrouceURIFile, err.Error()) - } - uri = strings.TrimSpace(string(fileContents)) - } else { - uri = os.Getenv("DATA_SOURCE_URI") - } - - dsn = "postgresql://" + ui + "@" + uri - - return []string{dsn}, nil -} - -func contains(a []string, x string) bool { - for _, n := range a { - if x == n { - return true - } - } - return false -} - -func main() { - kingpin.Version(version.Print(exporterName)) - promlogConfig := &promlog.Config{} - flag.AddFlags(kingpin.CommandLine, promlogConfig) - kingpin.HelpFlag.Short('h') - kingpin.Parse() - logger = promlog.New(promlogConfig) - - // landingPage contains the HTML served at '/'. - // TODO: Make this nicer and more informative. - var landingPage = []byte(` - Postgres exporter - -

Postgres exporter

-

Metrics

- - - `) - - if *onlyDumpMaps { - dumpMaps() - return - } - - dsn, err := getDataSources() - if err != nil { - level.Error(logger).Log("msg", "Failed reading data sources", "err", err.Error()) - os.Exit(1) - } - - if len(dsn) == 0 { - level.Error(logger).Log("msg", "Couldn't find environment variables describing the datasource to use") - os.Exit(1) - } - - opts := []ExporterOpt{ - DisableDefaultMetrics(*disableDefaultMetrics), - DisableSettingsMetrics(*disableSettingsMetrics), - AutoDiscoverDatabases(*autoDiscoverDatabases), - WithUserQueriesPath(*queriesPath), - WithConstantLabels(*constantLabelsList), - ExcludeDatabases(*excludeDatabases), - IncludeDatabases(*includeDatabases), - } - - exporter := NewExporter(dsn, opts...) - defer func() { - exporter.servers.Close() - }() - - prometheus.MustRegister(version.NewCollector(exporterName)) - - prometheus.MustRegister(exporter) - - http.Handle(*metricPath, promhttp.Handler()) - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/html; charset=UTF-8") // nolint: errcheck - w.Write(landingPage) // nolint: errcheck - }) - - level.Info(logger).Log("msg", "Listening on address", "address", *listenAddress) - srv := &http.Server{Addr: *listenAddress} - if err := web.ListenAndServe(srv, *webConfig, logger); err != nil { - level.Error(logger).Log("msg", "Error running HTTP server", "err", err) - os.Exit(1) - } -} diff --git a/cmd/postgres_exporter/queries.go b/cmd/postgres_exporter/queries.go new file mode 100644 index 000000000..903e1a277 --- /dev/null +++ b/cmd/postgres_exporter/queries.go @@ -0,0 +1,303 @@ +// Copyright 2021 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 main + +import ( + "errors" + "fmt" + + "github.com/blang/semver" + "github.com/go-kit/kit/log/level" + "gopkg.in/yaml.v2" +) + +// UserQuery represents a user defined query +type UserQuery struct { + Query string `yaml:"query"` + Metrics []Mapping `yaml:"metrics"` + Master bool `yaml:"master"` // Querying only for master database + CacheSeconds uint64 `yaml:"cache_seconds"` // Number of seconds to cache the namespace result metrics for. + RunOnServer string `yaml:"runonserver"` // Querying to run on which server version +} + +// UserQueries represents a set of UserQuery objects +type UserQueries map[string]UserQuery + +// OverrideQuery 's are run in-place of simple namespace look ups, and provide +// advanced functionality. But they have a tendency to postgres version specific. +// There aren't too many versions, so we simply store customized versions using +// the semver matching we do for columns. +type OverrideQuery struct { + versionRange semver.Range + query string +} + +// Overriding queries for namespaces above. +// TODO: validate this is a closed set in tests, and there are no overlaps +var queryOverrides = map[string][]OverrideQuery{ + "pg_locks": { + { + semver.MustParseRange(">0.0.0"), + `SELECT pg_database.datname,tmp.mode,COALESCE(count,0) as count + FROM + ( + VALUES ('accesssharelock'), + ('rowsharelock'), + ('rowexclusivelock'), + ('shareupdateexclusivelock'), + ('sharelock'), + ('sharerowexclusivelock'), + ('exclusivelock'), + ('accessexclusivelock'), + ('sireadlock') + ) AS tmp(mode) CROSS JOIN pg_database + LEFT JOIN + (SELECT database, lower(mode) AS mode,count(*) AS count + FROM pg_locks WHERE database IS NOT NULL + GROUP BY database, lower(mode) + ) AS tmp2 + ON tmp.mode=tmp2.mode and pg_database.oid = tmp2.database ORDER BY 1`, + }, + }, + + "pg_stat_replication": { + { + semver.MustParseRange(">=10.0.0"), + ` + SELECT *, + (case pg_is_in_recovery() when 't' then null else pg_current_wal_lsn() end) AS pg_current_wal_lsn, + (case pg_is_in_recovery() when 't' then null else pg_wal_lsn_diff(pg_current_wal_lsn(), pg_lsn('0/0'))::float end) AS pg_current_wal_lsn_bytes, + (case pg_is_in_recovery() when 't' then null else pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)::float end) AS pg_wal_lsn_diff + FROM pg_stat_replication + `, + }, + { + semver.MustParseRange(">=9.2.0 <10.0.0"), + ` + SELECT *, + (case pg_is_in_recovery() when 't' then null else pg_current_xlog_location() end) AS pg_current_xlog_location, + (case pg_is_in_recovery() when 't' then null else pg_xlog_location_diff(pg_current_xlog_location(), replay_location)::float end) AS pg_xlog_location_diff + FROM pg_stat_replication + `, + }, + { + semver.MustParseRange("<9.2.0"), + ` + SELECT *, + (case pg_is_in_recovery() when 't' then null else pg_current_xlog_location() end) AS pg_current_xlog_location + FROM pg_stat_replication + `, + }, + }, + + "pg_replication_slots": { + { + semver.MustParseRange(">=9.4.0 <10.0.0"), + ` + SELECT slot_name, database, active, pg_xlog_location_diff(pg_current_xlog_location(), restart_lsn) + FROM pg_replication_slots + `, + }, + { + semver.MustParseRange(">=10.0.0"), + ` + SELECT slot_name, database, active, pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) + FROM pg_replication_slots + `, + }, + }, + + "pg_stat_archiver": { + { + semver.MustParseRange(">=0.0.0"), + ` + SELECT *, + extract(epoch from now() - last_archived_time) AS last_archive_age + FROM pg_stat_archiver + `, + }, + }, + + "pg_stat_activity": { + // This query only works + { + semver.MustParseRange(">=9.2.0"), + ` + SELECT + pg_database.datname, + tmp.state, + COALESCE(count,0) as count, + COALESCE(max_tx_duration,0) as max_tx_duration + FROM + ( + VALUES ('active'), + ('idle'), + ('idle in transaction'), + ('idle in transaction (aborted)'), + ('fastpath function call'), + ('disabled') + ) AS tmp(state) CROSS JOIN pg_database + LEFT JOIN + ( + SELECT + datname, + state, + count(*) AS count, + MAX(EXTRACT(EPOCH FROM now() - xact_start))::float AS max_tx_duration + FROM pg_stat_activity GROUP BY datname,state) AS tmp2 + ON tmp.state = tmp2.state AND pg_database.datname = tmp2.datname + `, + }, + { + semver.MustParseRange("<9.2.0"), + ` + SELECT + datname, + 'unknown' AS state, + COALESCE(count(*),0) AS count, + COALESCE(MAX(EXTRACT(EPOCH FROM now() - xact_start))::float,0) AS max_tx_duration + FROM pg_stat_activity GROUP BY datname + `, + }, + }, +} + +// Convert the query override file to the version-specific query override file +// for the exporter. +func makeQueryOverrideMap(pgVersion semver.Version, queryOverrides map[string][]OverrideQuery) map[string]string { + resultMap := make(map[string]string) + for name, overrideDef := range queryOverrides { + // Find a matching semver. We make it an error to have overlapping + // ranges at test-time, so only 1 should ever match. + matched := false + for _, queryDef := range overrideDef { + if queryDef.versionRange(pgVersion) { + resultMap[name] = queryDef.query + matched = true + break + } + } + if !matched { + level.Warn(logger).Log("msg", "No query matched override, disabling metric space", "name", name) + resultMap[name] = "" + } + } + + return resultMap +} + +func parseUserQueries(content []byte) (map[string]intermediateMetricMap, map[string]string, error) { + var userQueries UserQueries + + err := yaml.Unmarshal(content, &userQueries) + if err != nil { + return nil, nil, err + } + + // Stores the loaded map representation + metricMaps := make(map[string]intermediateMetricMap) + newQueryOverrides := make(map[string]string) + + for metric, specs := range userQueries { + level.Debug(logger).Log("msg", "New user metric namespace from YAML metric", "metric", metric, "cache_seconds", specs.CacheSeconds) + newQueryOverrides[metric] = specs.Query + metricMap, ok := metricMaps[metric] + if !ok { + // Namespace for metric not found - add it. + newMetricMap := make(map[string]ColumnMapping) + metricMap = intermediateMetricMap{ + columnMappings: newMetricMap, + master: specs.Master, + cacheSeconds: specs.CacheSeconds, + } + metricMaps[metric] = metricMap + } + for _, metric := range specs.Metrics { + for name, mappingOption := range metric { + var columnMapping ColumnMapping + tmpUsage, _ := stringToColumnUsage(mappingOption.Usage) + columnMapping.usage = tmpUsage + columnMapping.description = mappingOption.Description + + // TODO: we should support cu + columnMapping.mapping = nil + // Should we support this for users? + columnMapping.supportedVersions = nil + + metricMap.columnMappings[name] = columnMapping + } + } + } + return metricMaps, newQueryOverrides, nil +} + +// Add queries to the builtinMetricMaps and queryOverrides maps. Added queries do not +// respect version requirements, because it is assumed that the user knows +// what they are doing with their version of postgres. +// +// This function modifies metricMap and queryOverrideMap to contain the new +// queries. +// TODO: test code for all cu. +// TODO: the YAML this supports is "non-standard" - we should move away from it. +func addQueries(content []byte, pgVersion semver.Version, server *Server) error { + metricMaps, newQueryOverrides, err := parseUserQueries(content) + if err != nil { + return err + } + // Convert the loaded metric map into exporter representation + partialExporterMap := makeDescMap(pgVersion, server.labels, metricMaps) + + // Merge the two maps (which are now quite flatteend) + for k, v := range partialExporterMap { + _, found := server.metricMap[k] + if found { + level.Debug(logger).Log("msg", "Overriding metric from user YAML file", "metric", k) + } else { + level.Debug(logger).Log("msg", "Adding new metric from user YAML file", "metric", k) + } + server.metricMap[k] = v + } + + // Merge the query override map + for k, v := range newQueryOverrides { + _, found := server.queryOverrides[k] + if found { + level.Debug(logger).Log("msg", "Overriding query override from user YAML file", "query_override", k) + } else { + level.Debug(logger).Log("msg", "Adding new query override from user YAML file", "query_override", k) + } + server.queryOverrides[k] = v + } + return nil +} + +func queryDatabases(server *Server) ([]string, error) { + rows, err := server.db.Query("SELECT datname FROM pg_database WHERE datallowconn = true AND datistemplate = false AND datname != current_database()") + if err != nil { + return nil, fmt.Errorf("Error retrieving databases: %v", err) + } + defer rows.Close() // nolint: errcheck + + var databaseName string + result := make([]string, 0) + for rows.Next() { + err = rows.Scan(&databaseName) + if err != nil { + return nil, errors.New(fmt.Sprintln("Error retrieving rows:", err)) + } + result = append(result, databaseName) + } + + return result, nil +} diff --git a/cmd/postgres_exporter/server.go b/cmd/postgres_exporter/server.go new file mode 100644 index 000000000..cf2469cc9 --- /dev/null +++ b/cmd/postgres_exporter/server.go @@ -0,0 +1,190 @@ +// Copyright 2021 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 main + +import ( + "database/sql" + "fmt" + "sync" + "time" + + "github.com/blang/semver" + "github.com/go-kit/kit/log/level" + "github.com/prometheus/client_golang/prometheus" +) + +// Server describes a connection to Postgres. +// Also it contains metrics map and query overrides. +type Server struct { + db *sql.DB + labels prometheus.Labels + master bool + runonserver string + + // Last version used to calculate metric map. If mismatch on scrape, + // then maps are recalculated. + lastMapVersion semver.Version + // Currently active metric map + metricMap map[string]MetricMapNamespace + // Currently active query overrides + queryOverrides map[string]string + mappingMtx sync.RWMutex + // Currently cached metrics + metricCache map[string]cachedMetrics + cacheMtx sync.Mutex +} + +// ServerOpt configures a server. +type ServerOpt func(*Server) + +// ServerWithLabels configures a set of labels. +func ServerWithLabels(labels prometheus.Labels) ServerOpt { + return func(s *Server) { + for k, v := range labels { + s.labels[k] = v + } + } +} + +// NewServer establishes a new connection using DSN. +func NewServer(dsn string, opts ...ServerOpt) (*Server, error) { + fingerprint, err := parseFingerprint(dsn) + if err != nil { + return nil, err + } + + db, err := sql.Open("postgres", dsn) + if err != nil { + return nil, err + } + db.SetMaxOpenConns(1) + db.SetMaxIdleConns(1) + + level.Info(logger).Log("msg", "Established new database connection", "fingerprint", fingerprint) + + s := &Server{ + db: db, + master: false, + labels: prometheus.Labels{ + serverLabelName: fingerprint, + }, + metricCache: make(map[string]cachedMetrics), + } + + for _, opt := range opts { + opt(s) + } + + return s, nil +} + +// Close disconnects from Postgres. +func (s *Server) Close() error { + return s.db.Close() +} + +// Ping checks connection availability and possibly invalidates the connection if it fails. +func (s *Server) Ping() error { + if err := s.db.Ping(); err != nil { + if cerr := s.Close(); cerr != nil { + level.Error(logger).Log("msg", "Error while closing non-pinging DB connection", "server", s, "err", cerr) + } + return err + } + return nil +} + +// String returns server's fingerprint. +func (s *Server) String() string { + return s.labels[serverLabelName] +} + +// Scrape loads metrics. +func (s *Server) Scrape(ch chan<- prometheus.Metric, disableSettingsMetrics bool) error { + s.mappingMtx.RLock() + defer s.mappingMtx.RUnlock() + + var err error + + if !disableSettingsMetrics && s.master { + if err = querySettings(ch, s); err != nil { + err = fmt.Errorf("error retrieving settings: %s", err) + } + } + + errMap := queryNamespaceMappings(ch, s) + if len(errMap) > 0 { + err = fmt.Errorf("queryNamespaceMappings returned %d errors", len(errMap)) + } + + return err +} + +// Servers contains a collection of servers to Postgres. +type Servers struct { + m sync.Mutex + servers map[string]*Server + opts []ServerOpt +} + +// NewServers creates a collection of servers to Postgres. +func NewServers(opts ...ServerOpt) *Servers { + return &Servers{ + servers: make(map[string]*Server), + opts: opts, + } +} + +// GetServer returns established connection from a collection. +func (s *Servers) GetServer(dsn string) (*Server, error) { + s.m.Lock() + defer s.m.Unlock() + var err error + var ok bool + errCount := 0 // start at zero because we increment before doing work + retries := 1 + var server *Server + for { + if errCount++; errCount > retries { + return nil, err + } + server, ok = s.servers[dsn] + if !ok { + server, err = NewServer(dsn, s.opts...) + if err != nil { + time.Sleep(time.Duration(errCount) * time.Second) + continue + } + s.servers[dsn] = server + } + if err = server.Ping(); err != nil { + delete(s.servers, dsn) + time.Sleep(time.Duration(errCount) * time.Second) + continue + } + break + } + return server, nil +} + +// Close disconnects from all known servers. +func (s *Servers) Close() { + s.m.Lock() + defer s.m.Unlock() + for _, server := range s.servers { + if err := server.Close(); err != nil { + level.Error(logger).Log("msg", "Failed to close connection", "server", server, "err", err) + } + } +} diff --git a/cmd/postgres_exporter/util.go b/cmd/postgres_exporter/util.go new file mode 100644 index 000000000..5ecb5ec71 --- /dev/null +++ b/cmd/postgres_exporter/util.go @@ -0,0 +1,218 @@ +// Copyright 2021 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 main + +import ( + "fmt" + "math" + "net/url" + "strconv" + "strings" + "time" + + "github.com/go-kit/kit/log/level" + "github.com/lib/pq" +) + +func contains(a []string, x string) bool { + for _, n := range a { + if x == n { + return true + } + } + return false +} + +// convert a string to the corresponding ColumnUsage +func stringToColumnUsage(s string) (ColumnUsage, error) { + var u ColumnUsage + var err error + switch s { + case "DISCARD": + u = DISCARD + + case "LABEL": + u = LABEL + + case "COUNTER": + u = COUNTER + + case "GAUGE": + u = GAUGE + + case "HISTOGRAM": + u = HISTOGRAM + + case "MAPPEDMETRIC": + u = MAPPEDMETRIC + + case "DURATION": + u = DURATION + + default: + err = fmt.Errorf("wrong ColumnUsage given : %s", s) + } + + return u, err +} + +// Convert database.sql types to float64s for Prometheus consumption. Null types are mapped to NaN. string and []byte +// types are mapped as NaN and !ok +func dbToFloat64(t interface{}) (float64, bool) { + switch v := t.(type) { + case int64: + return float64(v), true + case float64: + return v, true + case time.Time: + return float64(v.Unix()), true + case []byte: + // Try and convert to string and then parse to a float64 + strV := string(v) + result, err := strconv.ParseFloat(strV, 64) + if err != nil { + level.Info(logger).Log("msg", "Could not parse []byte", "err", err) + return math.NaN(), false + } + return result, true + case string: + result, err := strconv.ParseFloat(v, 64) + if err != nil { + level.Info(logger).Log("msg", "Could not parse string", "err", err) + return math.NaN(), false + } + return result, true + case bool: + if v { + return 1.0, true + } + return 0.0, true + case nil: + return math.NaN(), true + default: + return math.NaN(), false + } +} + +// Convert database.sql types to uint64 for Prometheus consumption. Null types are mapped to 0. string and []byte +// types are mapped as 0 and !ok +func dbToUint64(t interface{}) (uint64, bool) { + switch v := t.(type) { + case uint64: + return v, true + case int64: + return uint64(v), true + case float64: + return uint64(v), true + case time.Time: + return uint64(v.Unix()), true + case []byte: + // Try and convert to string and then parse to a uint64 + strV := string(v) + result, err := strconv.ParseUint(strV, 10, 64) + if err != nil { + level.Info(logger).Log("msg", "Could not parse []byte", "err", err) + return 0, false + } + return result, true + case string: + result, err := strconv.ParseUint(v, 10, 64) + if err != nil { + level.Info(logger).Log("msg", "Could not parse string", "err", err) + return 0, false + } + return result, true + case bool: + if v { + return 1, true + } + return 0, true + case nil: + return 0, true + default: + return 0, false + } +} + +// Convert database.sql to string for Prometheus labels. Null types are mapped to empty strings. +func dbToString(t interface{}) (string, bool) { + switch v := t.(type) { + case int64: + return fmt.Sprintf("%v", v), true + case float64: + return fmt.Sprintf("%v", v), true + case time.Time: + return fmt.Sprintf("%v", v.Unix()), true + case nil: + return "", true + case []byte: + // Try and convert to string + return string(v), true + case string: + return v, true + case bool: + if v { + return "true", true + } + return "false", true + default: + return "", false + } +} + +func parseFingerprint(url string) (string, error) { + dsn, err := pq.ParseURL(url) + if err != nil { + dsn = url + } + + pairs := strings.Split(dsn, " ") + kv := make(map[string]string, len(pairs)) + for _, pair := range pairs { + splitted := strings.SplitN(pair, "=", 2) + if len(splitted) != 2 { + return "", fmt.Errorf("malformed dsn %q", dsn) + } + kv[splitted[0]] = splitted[1] + } + + var fingerprint string + + if host, ok := kv["host"]; ok { + fingerprint += host + } else { + fingerprint += "localhost" + } + + if port, ok := kv["port"]; ok { + fingerprint += ":" + port + } else { + fingerprint += ":5432" + } + + return fingerprint, nil +} + +func loggableDSN(dsn string) string { + pDSN, err := url.Parse(dsn) + if err != nil { + return "could not parse DATA_SOURCE_NAME" + } + // Blank user info if not nil + if pDSN.User != nil { + pDSN.User = url.UserPassword(pDSN.User.Username(), "PASSWORD_REMOVED") + } + + return pDSN.String() +} From 59623d570936752f9e72529d732de03ad62e6edc Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Tue, 6 Jul 2021 21:36:32 -0400 Subject: [PATCH 003/228] Release v0.10.0 Signed-off-by: Joe Adams --- CHANGELOG.md | 4 ++++ VERSION | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cedc9cfc3..bdf41673e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.0 / 2021-07-07 +* [ENHANCEMENT] Add ability to set included databases when autoDiscoverDatabases is enabled #499 +* [BUGFIX] fix pg_replication_slots on postgresql versions 9.4 <> 10.0 #537 + ## 0.9.0 / 2021-03-01 First release under the Prometheus Community organisation. diff --git a/VERSION b/VERSION index ac39a106c..78bc1abd1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.9.0 +0.10.0 From 08fd458df01778d49c45714fdb2980fce56d23fb Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 7 Jul 2021 09:52:56 -0400 Subject: [PATCH 004/228] Update dependencies and fix tests Signed-off-by: Joe Adams --- CHANGELOG.md | 1 + cmd/postgres_exporter/util.go | 5 +- go.mod | 10 +- go.sum | 553 ++++++++++++++++++++++++---------- 4 files changed, 408 insertions(+), 161 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdf41673e..20046a961 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ## 0.10.0 / 2021-07-07 + * [ENHANCEMENT] Add ability to set included databases when autoDiscoverDatabases is enabled #499 * [BUGFIX] fix pg_replication_slots on postgresql versions 9.4 <> 10.0 #537 diff --git a/cmd/postgres_exporter/util.go b/cmd/postgres_exporter/util.go index 5ecb5ec71..b8ddfe080 100644 --- a/cmd/postgres_exporter/util.go +++ b/cmd/postgres_exporter/util.go @@ -184,7 +184,10 @@ func parseFingerprint(url string) (string, error) { if len(splitted) != 2 { return "", fmt.Errorf("malformed dsn %q", dsn) } - kv[splitted[0]] = splitted[1] + // Newer versions of pq.ParseURL quote values so trim them off if they exist + key := strings.Trim(splitted[0], "'\"") + value := strings.Trim(splitted[1], "'\"") + kv[key] = value } var fingerprint string diff --git a/go.mod b/go.mod index 1b8a95634..8a6912792 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,12 @@ go 1.14 require ( github.com/blang/semver v3.5.1+incompatible - github.com/go-kit/kit v0.10.0 - github.com/lib/pq v1.9.0 - github.com/prometheus/client_golang v1.9.0 + github.com/go-kit/kit v0.11.0 + github.com/lib/pq v1.10.2 + github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.17.0 - github.com/prometheus/exporter-toolkit v0.5.1 + github.com/prometheus/common v0.29.0 + github.com/prometheus/exporter-toolkit v0.6.0 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index 478fe5718..df0f869b4 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,38 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= @@ -13,15 +45,15 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 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/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aws/aws-sdk-go v1.38.68/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go-v2 v1.7.0/go.mod h1:tb9wi5s61kTDA5qCkcDbt3KRVV74GGslQkl/DRdX/P4= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0/go.mod h1:acH3+MQoiMzozT/ivU+DbRg7Ooo2298RdRaWcOv+4vM= +github.com/aws/smithy-go v1.5.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -29,149 +61,188 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/casbin/casbin/v2 v2.31.6/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= -github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/kit v0.11.0 h1:IGmIEl7aHTYh6E2HlT+ptILBotjo4xl8PMDl852etiI= +github.com/go-kit/kit v0.11.0/go.mod h1:73/6Ixaufkvb5Osvkls8C79vuQ49Ba1rUEUYNSf+FUw= +github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.8.1/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= +github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.12/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= -github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -181,34 +252,22 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= +github.com/nats-io/jwt/v2 v2.0.2/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= +github.com/nats-io/nats-server/v2 v2.2.6/go.mod h1:sEnFaxqe09cDmfMgACxZbziXnhQFhwk+aKkZjBBRYrI= +github.com/nats-io/nats.go v1.11.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -217,191 +276,368 @@ github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6J github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.9.0 h1:Rrch9mh17XcxvEu9D9DEpb4isxjGBtcevQjKvxPRQIU= -github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= +github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.17.0 h1:kDIZLI74SS+3tedSvEkykgBkD7txMxaJAPj8DtJUKYA= -github.com/prometheus/common v0.17.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/exporter-toolkit v0.5.1 h1:9eqgis5er9xN613ZSADjypCJaDGj9ZlcWBvsIHa8/3c= -github.com/prometheus/exporter-toolkit v0.5.1/go.mod h1:OCkM4805mmisBhLmVFw858QYi3v0wKdY6/UxrT0pZVg= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.29.0 h1:3jqPBvKT4OHAbje2Ql7KeaaSicDBCxMYwEJU1zRJceE= +github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/exporter-toolkit v0.6.0 h1:rGoS9gIqj3sXaw+frvo0ozCs1CxBRqpOCGsbixC52UI= +github.com/prometheus/exporter-toolkit v0.6.0/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9 h1:sYNJzB4J8toYPQTM6pAkcmBRgw9SnQKP9oXCHfgy604= -golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e h1:AyodaIpKjppX+cBfTASF2E1US3H2JFBj920Ot3rtDjs= -golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -409,24 +645,31 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= From c6632ab1e44d7d39352c9f0f855595e50502073f Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 7 Jul 2021 16:54:36 -0400 Subject: [PATCH 005/228] Rollback lib/pq to v1.10.1 for illumos compatability Signed-off-by: Joe Adams --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 8a6912792..6011a2af5 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,11 @@ module github.com/prometheus-community/postgres_exporter -go 1.14 +go 1.16 require ( github.com/blang/semver v3.5.1+incompatible github.com/go-kit/kit v0.11.0 - github.com/lib/pq v1.10.2 + github.com/lib/pq v1.10.1 github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.29.0 diff --git a/go.sum b/go.sum index df0f869b4..3e9df6e05 100644 --- a/go.sum +++ b/go.sum @@ -225,8 +225,8 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.1 h1:6VXZrLU0jHBYyAqrSPa+MgPfnSvTPuMgK+k0o5kVFWo= +github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= From 7fdb0198113d79627f4529e19fa903c14fbe7561 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Thu, 8 Jul 2021 09:16:57 -0400 Subject: [PATCH 006/228] Bump date for release Signed-off-by: Joe Adams --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20046a961..9d17767ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.10.0 / 2021-07-07 +## 0.10.0 / 2021-07-08 * [ENHANCEMENT] Add ability to set included databases when autoDiscoverDatabases is enabled #499 * [BUGFIX] fix pg_replication_slots on postgresql versions 9.4 <> 10.0 #537 From 820c05b7476138f6e0198a4002bbadc3617c93ed Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Thu, 8 Jul 2021 09:31:06 -0400 Subject: [PATCH 007/228] Revert go version change Signed-off-by: Joe Adams --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 6011a2af5..4012c360a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/prometheus-community/postgres_exporter -go 1.16 +go 1.14 require ( github.com/blang/semver v3.5.1+incompatible From c1ab341279907350a3b1e2e7f94dbdca8ca8164f Mon Sep 17 00:00:00 2001 From: Harkishen Singh Date: Wed, 14 Jul 2021 13:38:25 +0530 Subject: [PATCH 008/228] Fix broken log-level for values other than debug. Signed-off-by: Harkishen Singh --- cmd/postgres_exporter/datasource.go | 2 +- cmd/postgres_exporter/main.go | 4 +- cmd/postgres_exporter/namespace.go | 2 +- cmd/postgres_exporter/pg_setting.go | 2 +- cmd/postgres_exporter/postgres_exporter.go | 2 +- cmd/postgres_exporter/queries.go | 2 +- cmd/postgres_exporter/server.go | 2 +- cmd/postgres_exporter/util.go | 2 +- go.mod | 2 +- go.sum | 195 +-------------------- scripts/errcheck_excludes.txt | 2 +- 11 files changed, 14 insertions(+), 203 deletions(-) diff --git a/cmd/postgres_exporter/datasource.go b/cmd/postgres_exporter/datasource.go index 3bbe2f0a7..90d797b63 100644 --- a/cmd/postgres_exporter/datasource.go +++ b/cmd/postgres_exporter/datasource.go @@ -21,7 +21,7 @@ import ( "regexp" "strings" - "github.com/go-kit/kit/log/level" + "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 25f94a745..87ce17c83 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -17,8 +17,8 @@ import ( "net/http" "os" - "github.com/go-kit/kit/log" - "github.com/go-kit/kit/log/level" + "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" diff --git a/cmd/postgres_exporter/namespace.go b/cmd/postgres_exporter/namespace.go index 1b9e970ef..ab1e74ea0 100644 --- a/cmd/postgres_exporter/namespace.go +++ b/cmd/postgres_exporter/namespace.go @@ -20,7 +20,7 @@ import ( "time" "github.com/blang/semver" - "github.com/go-kit/kit/log/level" + "github.com/go-kit/log/level" "github.com/lib/pq" "github.com/prometheus/client_golang/prometheus" ) diff --git a/cmd/postgres_exporter/pg_setting.go b/cmd/postgres_exporter/pg_setting.go index 4b0e2124f..4a7dae048 100644 --- a/cmd/postgres_exporter/pg_setting.go +++ b/cmd/postgres_exporter/pg_setting.go @@ -19,7 +19,7 @@ import ( "strconv" "strings" - "github.com/go-kit/kit/log/level" + "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index 158048112..ff6993dab 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -25,7 +25,7 @@ import ( "time" "github.com/blang/semver" - "github.com/go-kit/kit/log/level" + "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) diff --git a/cmd/postgres_exporter/queries.go b/cmd/postgres_exporter/queries.go index 903e1a277..e872b8802 100644 --- a/cmd/postgres_exporter/queries.go +++ b/cmd/postgres_exporter/queries.go @@ -18,7 +18,7 @@ import ( "fmt" "github.com/blang/semver" - "github.com/go-kit/kit/log/level" + "github.com/go-kit/log/level" "gopkg.in/yaml.v2" ) diff --git a/cmd/postgres_exporter/server.go b/cmd/postgres_exporter/server.go index cf2469cc9..8747dffa0 100644 --- a/cmd/postgres_exporter/server.go +++ b/cmd/postgres_exporter/server.go @@ -20,7 +20,7 @@ import ( "time" "github.com/blang/semver" - "github.com/go-kit/kit/log/level" + "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) diff --git a/cmd/postgres_exporter/util.go b/cmd/postgres_exporter/util.go index b8ddfe080..3a125f1d3 100644 --- a/cmd/postgres_exporter/util.go +++ b/cmd/postgres_exporter/util.go @@ -21,7 +21,7 @@ import ( "strings" "time" - "github.com/go-kit/kit/log/level" + "github.com/go-kit/log/level" "github.com/lib/pq" ) diff --git a/go.mod b/go.mod index 4012c360a..5b7c64777 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/blang/semver v3.5.1+incompatible - github.com/go-kit/kit v0.11.0 + github.com/go-kit/log v0.1.0 github.com/lib/pq v1.10.1 github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_model v0.2.0 diff --git a/go.sum b/go.sum index 3e9df6e05..ddcde887b 100644 --- a/go.sum +++ b/go.sum @@ -33,11 +33,6 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 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= @@ -45,64 +40,32 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 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/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.38.68/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go-v2 v1.7.0/go.mod h1:tb9wi5s61kTDA5qCkcDbt3KRVV74GGslQkl/DRdX/P4= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0/go.mod h1:acH3+MQoiMzozT/ivU+DbRg7Ooo2298RdRaWcOv+4vM= -github.com/aws/smithy-go v1.5.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/casbin/casbin/v2 v2.31.6/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.11.0 h1:IGmIEl7aHTYh6E2HlT+ptILBotjo4xl8PMDl852etiI= -github.com/go-kit/kit v0.11.0/go.mod h1:73/6Ixaufkvb5Osvkls8C79vuQ49Ba1rUEUYNSf+FUw= github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -111,10 +74,7 @@ github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -139,11 +99,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -153,7 +110,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -168,40 +124,11 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.8.1/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= -github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -209,17 +136,13 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.11.12/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -227,24 +150,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.10.1 h1:6VXZrLU0jHBYyAqrSPa+MgPfnSvTPuMgK+k0o5kVFWo= github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -252,31 +159,12 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= -github.com/nats-io/jwt/v2 v2.0.2/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= -github.com/nats-io/nats-server/v2 v2.2.6/go.mod h1:sEnFaxqe09cDmfMgACxZbziXnhQFhwk+aKkZjBBRYrI= -github.com/nats-io/nats.go v1.11.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= -github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= -github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -299,58 +187,30 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -375,7 +235,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -384,11 +243,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -401,7 +257,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -416,10 +271,7 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -437,18 +289,11 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -457,18 +302,12 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -482,13 +321,9 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -498,20 +333,17 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -519,7 +351,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -544,12 +375,9 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -601,14 +429,12 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -621,9 +447,6 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -634,10 +457,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -646,22 +467,13 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -672,4 +484,3 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/scripts/errcheck_excludes.txt b/scripts/errcheck_excludes.txt index e759ce68a..58c2051ac 100644 --- a/scripts/errcheck_excludes.txt +++ b/scripts/errcheck_excludes.txt @@ -1,2 +1,2 @@ // Never check for logger errors. -(github.com/go-kit/kit/log.Logger).Log +(github.com/go-kit/log.Logger).Log From cd98cf7c33194a1e7b84b54b70f4af52d4670a30 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Thu, 15 Jul 2021 21:51:25 -0400 Subject: [PATCH 009/228] Add a warning for pg_stat_statements This metric can be very expensive to store in prometheus and has the potential to create an unreasonably large cardinality set of metrics so warn the user. Signed-off-by: Joe Adams --- queries.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/queries.yaml b/queries.yaml index 35b754319..d0fd3997d 100644 --- a/queries.yaml +++ b/queries.yaml @@ -158,6 +158,7 @@ pg_database: usage: "GAUGE" description: "Disk space used by the database" +# Note that this set of metrics can be very expensive on a busy server as every unique query executed will create an additional time series pg_stat_statements: query: "SELECT t2.rolname, t3.datname, queryid, calls, total_time / 1000 as total_time_seconds, min_time / 1000 as min_time_seconds, max_time / 1000 as max_time_seconds, mean_time / 1000 as mean_time_seconds, stddev_time / 1000 as stddev_time_seconds, rows, shared_blks_hit, shared_blks_read, shared_blks_dirtied, shared_blks_written, local_blks_hit, local_blks_read, local_blks_dirtied, local_blks_written, temp_blks_read, temp_blks_written, blk_read_time / 1000 as blk_read_time_seconds, blk_write_time / 1000 as blk_write_time_seconds FROM pg_stat_statements t1 JOIN pg_roles t2 ON (t1.userid=t2.oid) JOIN pg_database t3 ON (t1.dbid=t3.oid) WHERE t2.rolname != 'rdsadmin'" master: true From d9eb99555bf9742fa4ccf1e6120e4bf880084c7c Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Thu, 15 Jul 2021 21:54:39 -0400 Subject: [PATCH 010/228] Adjust comment to WARNING Signed-off-by: Joe Adams --- queries.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/queries.yaml b/queries.yaml index d0fd3997d..1102da447 100644 --- a/queries.yaml +++ b/queries.yaml @@ -158,7 +158,7 @@ pg_database: usage: "GAUGE" description: "Disk space used by the database" -# Note that this set of metrics can be very expensive on a busy server as every unique query executed will create an additional time series +# WARNING: This set of metrics can be very expensive on a busy server as every unique query executed will create an additional time series pg_stat_statements: query: "SELECT t2.rolname, t3.datname, queryid, calls, total_time / 1000 as total_time_seconds, min_time / 1000 as min_time_seconds, max_time / 1000 as max_time_seconds, mean_time / 1000 as mean_time_seconds, stddev_time / 1000 as stddev_time_seconds, rows, shared_blks_hit, shared_blks_read, shared_blks_dirtied, shared_blks_written, local_blks_hit, local_blks_read, local_blks_dirtied, local_blks_written, temp_blks_read, temp_blks_written, blk_read_time / 1000 as blk_read_time_seconds, blk_write_time / 1000 as blk_write_time_seconds FROM pg_stat_statements t1 JOIN pg_roles t2 ON (t1.userid=t2.oid) JOIN pg_database t3 ON (t1.dbid=t3.oid) WHERE t2.rolname != 'rdsadmin'" master: true From d9a081d6d98a36b0416bdd2c25da1996ae3b4faf Mon Sep 17 00:00:00 2001 From: Alex Vandiver Date: Mon, 2 Aug 2021 11:43:20 -0700 Subject: [PATCH 011/228] Remove misplaced and duplicated phrase in README Signed-off-by: Alex Vandiver --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 13875fca6..8bcbe1b83 100644 --- a/README.md +++ b/README.md @@ -186,8 +186,8 @@ The -extend.query-path command-line argument specifies a YAML file containing ad Some examples are provided in [queries.yaml](queries.yaml). ### Disabling default metrics -To work with non-officially-supported postgres versions you can try disabling (e.g. 8.2.15) -or a variant of postgres (e.g. Greenplum) you can disable the default metrics with the `--disable-default-metrics` +To work with non-officially-supported postgres versions (e.g. 8.2.15), +or variants of postgres (e.g. Greenplum), you can disable the default metrics with the `--disable-default-metrics` flag. This removes all built-in metrics, and uses only metrics defined by queries in the `queries.yaml` file you supply (so you must supply one, otherwise the exporter will return nothing but internal statuses and not your database). From d9435b4c80bce5abbe0d56212d7f54a52634db62 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Tue, 24 Aug 2021 13:26:11 +0200 Subject: [PATCH 012/228] Fix typos in README Signed-off-by: Magnus Hagander --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 13875fca6..fa247631c 100644 --- a/README.md +++ b/README.md @@ -126,10 +126,10 @@ The following environment variables configure the exporter: Use only metrics supplied from `queries.yaml`. Value can be `true` or `false`. Default is `false`. * `PG_EXPORTER_DISABLE_SETTINGS_METRICS` - Use the flag if you don't want to scrape `pg_settings`. Value can be `true` or `false`. Defauls is `false`. + Use the flag if you don't want to scrape `pg_settings`. Value can be `true` or `false`. Default is `false`. * `PG_EXPORTER_AUTO_DISCOVER_DATABASES` - Whether to discover the databases on a server dynamically. Value can be `true` or `false`. Defauls is `false`. + Whether to discover the databases on a server dynamically. Value can be `true` or `false`. Default is `false`. * `PG_EXPORTER_EXTEND_QUERY_PATH` Path to a YAML file containing custom queries to run. Check out [`queries.yaml`](queries.yaml) From 20aefc2e15ca95dfcd1051e3ba97e606866a84c0 Mon Sep 17 00:00:00 2001 From: Xela Date: Wed, 4 Aug 2021 20:26:46 +0300 Subject: [PATCH 013/228] Add some SQL in README.md Getting the error when adding non-root postgres user for exporter: ``` postgres=# CREATE OR REPLACE FUNCTION get_pg_stat_statements() RETURNS SETOF pg_stat_statements AS postgres-# $$ SELECT * FROM public.pg_stat_statements; $$ postgres-# LANGUAGE sql postgres-# VOLATILE postgres-# SECURITY DEFINER; ERROR: type "pg_stat_statements" does not exist ``` Add following sql command for enable pg_stat_statements: ``` CREATE EXTENSION IF NOT EXISTS pg_stat_statements; ``` Signed-off-by: Xela Tirdan --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 13875fca6..19481654a 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,7 @@ AS GRANT SELECT ON postgres_exporter.pg_stat_replication TO postgres_exporter; +CREATE EXTENSION IF NOT EXISTS pg_stat_statements; CREATE OR REPLACE FUNCTION get_pg_stat_statements() RETURNS SETOF pg_stat_statements AS $$ SELECT * FROM public.pg_stat_statements; $$ LANGUAGE sql From 545c3b7ebab77d4224792c2b6cb98d98cca85433 Mon Sep 17 00:00:00 2001 From: "juris.greitans" Date: Wed, 17 Nov 2021 11:48:23 +0200 Subject: [PATCH 014/228] #258 Document running as non-superuser on PostgreSQL versions 10 or newer. Signed-off-by: juris.greitans --- README.md | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fa247631c..2e7c92cb4 100644 --- a/README.md +++ b/README.md @@ -203,14 +203,10 @@ If you want to include only subset of databases, you can use option `--include-d ### Running as non-superuser -To be able to collect metrics from `pg_stat_activity` and `pg_stat_replication` -as non-superuser you have to create functions and views as a superuser, and -assign permissions separately to those. - -In PostgreSQL, views run with the permissions of the user that created them so -they can act as security barriers. Functions need to be created to share this -data with the non-superuser. Only creating the views will leave out the most -important bits of data. +To be able to collect metrics from `pg_stat*` views as non-superuser in PostgreSQL +server versions >= 10 you can grant pg_monitor built-in role to the user. If +you need to monitor older PostgreSQL servers, you will have to create functions +and views as a superuser, and assign permissions separately to those. ```sql -- To use IF statements, hence to be able to check if the user exists before @@ -239,9 +235,23 @@ ALTER USER postgres_exporter SET SEARCH_PATH TO postgres_exporter,pg_catalog; -- If deploying as non-superuser (for example in AWS RDS), uncomment the GRANT -- line below and replace with your root user. -- GRANT postgres_exporter TO ; + +GRANT CONNECT ON DATABASE postgres TO postgres_exporter; +``` + +Run following command if you use PostgreSQL versions >= 10 +```sql +GRANT pg_monitor to postgres_exporter; +``` + +Run following SQL commands only if you use PostgreSQL versions older than 10. +In PostgreSQL, views run with the permissions of the user that created them so +they can act as security barriers. Functions need to be created to share this +data with the non-superuser. Only creating the views will leave out the most +important bits of data. +```sql CREATE SCHEMA IF NOT EXISTS postgres_exporter; GRANT USAGE ON SCHEMA postgres_exporter TO postgres_exporter; -GRANT CONNECT ON DATABASE postgres TO postgres_exporter; CREATE OR REPLACE FUNCTION get_pg_stat_activity() RETURNS SETOF pg_stat_activity AS $$ SELECT * FROM pg_catalog.pg_stat_activity; $$ From 5d6e42935dc499f423027d4d924240be48a04641 Mon Sep 17 00:00:00 2001 From: Michael Banck Date: Wed, 10 Nov 2021 17:01:17 +0100 Subject: [PATCH 015/228] Avoid parsing error from bogus Azure Flexible Server custom GUC Signed-off-by: Michael Banck --- cmd/postgres_exporter/pg_setting.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/pg_setting.go b/cmd/postgres_exporter/pg_setting.go index 4b0e2124f..abfc26c65 100644 --- a/cmd/postgres_exporter/pg_setting.go +++ b/cmd/postgres_exporter/pg_setting.go @@ -31,7 +31,7 @@ func querySettings(ch chan<- prometheus.Metric, server *Server) error { // // NOTE: If you add more vartypes here, you must update the supported // types in normaliseUnit() below - query := "SELECT name, setting, COALESCE(unit, ''), short_desc, vartype FROM pg_settings WHERE vartype IN ('bool', 'integer', 'real');" + query := "SELECT name, setting, COALESCE(unit, ''), short_desc, vartype FROM pg_settings WHERE vartype IN ('bool', 'integer', 'real') AND name != 'sync_commit_cancel_wait';" rows, err := server.db.Query(query) if err != nil { From 7c76896aa87d6aba2619a0a25250276cc4df8909 Mon Sep 17 00:00:00 2001 From: "juris.greitans" Date: Mon, 29 Nov 2021 13:13:14 +0200 Subject: [PATCH 016/228] Fix issues mentioned in review. Add link to PostgreSQL documentation about pre-defined roles. Signed-off-by: juris.greitans --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e7c92cb4..69b1568f3 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ If you want to include only subset of databases, you can use option `--include-d ### Running as non-superuser To be able to collect metrics from `pg_stat*` views as non-superuser in PostgreSQL -server versions >= 10 you can grant pg_monitor built-in role to the user. If +server versions >= 10 you can grant the `pg_monitor` or `pg_read_all_stats` [built-in roles](https://www.postgresql.org/docs/current/predefined-roles.html) to the user. If you need to monitor older PostgreSQL servers, you will have to create functions and views as a superuser, and assign permissions separately to those. From 21c9b0d80d4bd9184aee3d761542804c28ae5595 Mon Sep 17 00:00:00 2001 From: t-inoue Date: Tue, 11 Jan 2022 13:35:00 +0900 Subject: [PATCH 017/228] change version for pg_stat_archiver Signed-off-by: t-inoue --- cmd/postgres_exporter/queries.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/queries.go b/cmd/postgres_exporter/queries.go index 903e1a277..3beaa2638 100644 --- a/cmd/postgres_exporter/queries.go +++ b/cmd/postgres_exporter/queries.go @@ -120,7 +120,7 @@ var queryOverrides = map[string][]OverrideQuery{ "pg_stat_archiver": { { - semver.MustParseRange(">=0.0.0"), + semver.MustParseRange(">=9.4.0"), ` SELECT *, extract(epoch from now() - last_archived_time) AS last_archive_age From fcb2535affa0f97c7a11439c19de6a7ff793e0df Mon Sep 17 00:00:00 2001 From: SuperQ Date: Fri, 14 Jan 2022 17:22:03 +0100 Subject: [PATCH 018/228] Release 0.10.1 * [BUGFIX] Fix broken log-level for values other than debug. #560 Signed-off-by: SuperQ --- .circleci/config.yml | 10 +++----- .promu.yml | 2 +- CHANGELOG.md | 4 +++ Makefile.common | 25 +++++++++++++++---- VERSION | 2 +- cmd/postgres_exporter/pg_setting_test.go | 1 + .../postgres_exporter_integration_test.go | 1 + .../postgres_exporter_test.go | 1 + go.mod | 8 +++--- go.sum | 18 +++++++------ 10 files changed, 47 insertions(+), 25 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3d80a4d1c..18f50cfc4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,13 +2,13 @@ version: 2.1 orbs: - prometheus: prometheus/prometheus@0.11.0 + prometheus: prometheus/prometheus@0.15.0 executors: # This must match .promu.yml. golang: docker: - - image: circleci/golang:1.16 + - image: circleci/golang:1.17 jobs: test: @@ -22,7 +22,7 @@ jobs: integration: docker: - - image: circleci/golang:1.16 + - image: circleci/golang:1.17 - image: << parameters.postgres_image >> environment: POSTGRES_DB: circle_test @@ -56,13 +56,11 @@ workflows: matrix: parameters: postgres_image: - - circleci/postgres:9.4 - - circleci/postgres:9.5 - - circleci/postgres:9.6 - circleci/postgres:10 - circleci/postgres:11 - circleci/postgres:12 - circleci/postgres:13 + - cimg/postgres:14.1 - prometheus/build: name: build filters: diff --git a/.promu.yml b/.promu.yml index a4c4c598c..8414f69eb 100644 --- a/.promu.yml +++ b/.promu.yml @@ -1,6 +1,6 @@ go: # This must match .circle/config.yml. - version: 1.16 + version: 1.17 repository: path: github.com/prometheus-community/postgres_exporter build: diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d17767ad..b97bd9f92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.1 / 2022-01-14 + +* [BUGFIX] Fix broken log-level for values other than debug. #560 + ## 0.10.0 / 2021-07-08 * [ENHANCEMENT] Add ability to set included databases when autoDiscoverDatabases is enabled #499 diff --git a/Makefile.common b/Makefile.common index ce80d530a..bf7304e58 100644 --- a/Makefile.common +++ b/Makefile.common @@ -78,17 +78,23 @@ ifneq ($(shell which gotestsum),) endif endif -PROMU_VERSION ?= 0.12.0 +PROMU_VERSION ?= 0.13.0 PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.39.0 +GOLANGCI_LINT_VERSION ?= v1.42.0 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) - GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint + # If we're in CI and there is an Actions file, that means the linter + # is being run in Actions, so we don't need to run it here. + ifeq (,$(CIRCLE_JOB)) + GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint + else ifeq (,$(wildcard .github/workflows/golangci-lint.yml)) + GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint + endif endif endif @@ -118,7 +124,7 @@ endif %: common-% ; .PHONY: common-all -common-all: precheck style check_license lint unused build test +common-all: precheck style check_license lint yamllint unused build test .PHONY: common-style common-style: @@ -154,7 +160,7 @@ endif update-go-deps: @echo ">> updating Go dependencies" @for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ - $(GO) get $$m; \ + $(GO) get -d $$m; \ done GO111MODULE=$(GO111MODULE) $(GO) mod tidy ifneq (,$(wildcard vendor)) @@ -198,6 +204,15 @@ else endif endif +.PHONY: common-yamllint +common-yamllint: + @echo ">> running yamllint on all YAML files in the repository" +ifeq (, $(shell which yamllint)) + @echo "yamllint not installed so skipping" +else + yamllint . +endif + # For backward-compatibility. .PHONY: common-staticcheck common-staticcheck: lint diff --git a/VERSION b/VERSION index 78bc1abd1..571215736 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.10.0 +0.10.1 diff --git a/cmd/postgres_exporter/pg_setting_test.go b/cmd/postgres_exporter/pg_setting_test.go index 8dd92bc56..8f8f9c058 100644 --- a/cmd/postgres_exporter/pg_setting_test.go +++ b/cmd/postgres_exporter/pg_setting_test.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build !integration // +build !integration package main diff --git a/cmd/postgres_exporter/postgres_exporter_integration_test.go b/cmd/postgres_exporter/postgres_exporter_integration_test.go index 5d479d7a5..7043c1e88 100644 --- a/cmd/postgres_exporter/postgres_exporter_integration_test.go +++ b/cmd/postgres_exporter/postgres_exporter_integration_test.go @@ -14,6 +14,7 @@ // These are specialized integration tests. We only build them when we're doing // a lot of additional work to keep the external docker environment they require // working. +//go:build integration // +build integration package main diff --git a/cmd/postgres_exporter/postgres_exporter_test.go b/cmd/postgres_exporter/postgres_exporter_test.go index 5747f0b07..6017756a8 100644 --- a/cmd/postgres_exporter/postgres_exporter_test.go +++ b/cmd/postgres_exporter/postgres_exporter_test.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build !integration // +build !integration package main diff --git a/go.mod b/go.mod index 5b7c64777..6fb663aaf 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,12 @@ go 1.14 require ( github.com/blang/semver v3.5.1+incompatible - github.com/go-kit/log v0.1.0 - github.com/lib/pq v1.10.1 + github.com/go-kit/log v0.2.0 + github.com/lib/pq v1.10.4 github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.29.0 - github.com/prometheus/exporter-toolkit v0.6.0 + github.com/prometheus/common v0.32.1 + github.com/prometheus/exporter-toolkit v0.7.1 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index ddcde887b..c1669ca25 100644 --- a/go.sum +++ b/go.sum @@ -66,13 +66,14 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -148,8 +149,8 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.10.1 h1:6VXZrLU0jHBYyAqrSPa+MgPfnSvTPuMgK+k0o5kVFWo= -github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= +github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -178,10 +179,11 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.29.0 h1:3jqPBvKT4OHAbje2Ql7KeaaSicDBCxMYwEJU1zRJceE= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/exporter-toolkit v0.6.0 h1:rGoS9gIqj3sXaw+frvo0ozCs1CxBRqpOCGsbixC52UI= -github.com/prometheus/exporter-toolkit v0.6.0/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/exporter-toolkit v0.7.1 h1:c6RXaK8xBVercEeUQ4tRNL8UGWzDHfvj9dseo1FcK1Y= +github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= From 7f357bc89ef592081851729aeb4226c00055f191 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Fri, 14 Jan 2022 11:30:09 -0500 Subject: [PATCH 019/228] Add @sysadmind as a maintainer Signed-off-by: Joe Adams --- MAINTAINERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 69b8113b9..a3032f51d 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -1,2 +1,3 @@ * Ben Kochie @SuperQ * William Rouesnel @wrouesnel +* Joe Adams @sysadmind From 99f0b4c63cd3bc06923fc286574daf79ea771e65 Mon Sep 17 00:00:00 2001 From: Daniel Swarbrick Date: Sun, 16 Jan 2022 19:54:56 +0100 Subject: [PATCH 020/228] Fix misspelling of PostgreSQL Signed-off-by: Daniel Swarbrick --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- cmd/postgres_exporter/postgres_exporter.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f75e9b5ab..22f42bc20 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -37,7 +37,7 @@ assignees: '' insert list of flags used here ``` -* PostgresSQL version: +* PostgreSQL version: insert PostgreSQL version here diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index ff6993dab..2594a9649 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -576,14 +576,14 @@ func (e *Exporter) setupInternalMetrics() { Namespace: namespace, Subsystem: exporter, Name: "last_scrape_duration_seconds", - Help: "Duration of the last scrape of metrics from PostgresSQL.", + Help: "Duration of the last scrape of metrics from PostgreSQL.", ConstLabels: e.constantLabels, }) e.totalScrapes = prometheus.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Subsystem: exporter, Name: "scrapes_total", - Help: "Total number of times PostgresSQL was scraped for metrics.", + Help: "Total number of times PostgreSQL was scraped for metrics.", ConstLabels: e.constantLabels, }) e.error = prometheus.NewGauge(prometheus.GaugeOpts{ From b10a7b7d3b4862961a41d9bc916a85a696b85ccc Mon Sep 17 00:00:00 2001 From: Alex <52292902+alexrudd2@users.noreply.github.com> Date: Tue, 18 Jan 2022 11:57:25 -0600 Subject: [PATCH 021/228] Clarify default values for CLI flags Reference here: https://grafana.com/docs/agent/latest/configuration/integrations/postgres-exporter-config/ Also, matches the environment variables section. Signed-off-by: Alex Ruddick --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fa247631c..4d722a22a 100644 --- a/README.md +++ b/README.md @@ -48,13 +48,13 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra Path under which to expose metrics. Default is `/metrics`. * `disable-default-metrics` - Use only metrics supplied from `queries.yaml` via `--extend.query-path`. + Use only metrics supplied from `queries.yaml` via `--extend.query-path`. Default is `false`. * `disable-settings-metrics` - Use the flag if you don't want to scrape `pg_settings`. + Use the flag if you don't want to scrape `pg_settings`. Default is `false`. * `auto-discover-databases` - Whether to discover the databases on a server dynamically. + Whether to discover the databases on a server dynamically. Default is `false`. * `extend.query-path` Path to a YAML file containing custom queries to run. Check out [`queries.yaml`](queries.yaml) From 21a19ed252ef2a7106ce511fd701b937481a7a45 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 9 Feb 2022 21:28:40 -0500 Subject: [PATCH 022/228] Add pg_database collector Converts the pg_database metrics from queries.yaml to a built in collector. This is enabled by default because it is not likely to be a performance problem and likely very useful data. Signed-off-by: Joe Adams --- CHANGELOG.md | 4 +++ cmd/postgres_exporter/server.go | 14 ++++++++ collector/pg_database.go | 63 +++++++++++++++++++++++++++++++++ queries.yaml | 12 ------- 4 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 collector/pg_database.go diff --git a/CHANGELOG.md b/CHANGELOG.md index b97bd9f92..4ac268c86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## master / unreleased + +* [ENHANCEMENT] Add pg_database_size_bytes metric #613 + ## 0.10.1 / 2022-01-14 * [BUGFIX] Fix broken log-level for values other than debug. #560 diff --git a/cmd/postgres_exporter/server.go b/cmd/postgres_exporter/server.go index 8747dffa0..6a08e9981 100644 --- a/cmd/postgres_exporter/server.go +++ b/cmd/postgres_exporter/server.go @@ -14,13 +14,16 @@ package main import ( + "context" "database/sql" "fmt" + "log" "sync" "time" "github.com/blang/semver" "github.com/go-kit/log/level" + "github.com/prometheus-community/postgres_exporter/collector" "github.com/prometheus/client_golang/prometheus" ) @@ -128,6 +131,17 @@ func (s *Server) Scrape(ch chan<- prometheus.Metric, disableSettingsMetrics bool err = fmt.Errorf("queryNamespaceMappings returned %d errors", len(errMap)) } + { + pgdb := collector.NewPGDatabaseCollector() + metrics, err := pgdb.Update(context.TODO(), s.db, s.String()) + if err != nil { + log.Printf("Failed to scrape pg_database metrics: %s", err) + } + for _, m := range metrics { + ch <- m + } + } + return err } diff --git a/collector/pg_database.go b/collector/pg_database.go new file mode 100644 index 000000000..a7cb66f9a --- /dev/null +++ b/collector/pg_database.go @@ -0,0 +1,63 @@ +// Copyright 2021 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 collector + +import ( + "context" + "database/sql" + + "github.com/prometheus/client_golang/prometheus" +) + +type PGDatabaseCollector struct{} + +func NewPGDatabaseCollector() *PGDatabaseCollector { + return &PGDatabaseCollector{} +} + +var pgDatabase = map[string]*prometheus.Desc{ + "size_bytes": prometheus.NewDesc( + "pg_database_size_bytes", + "Disk space used by the database", + []string{"datname"}, nil, + ), +} + +func (PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, server string) ([]prometheus.Metric, error) { + metrics := []prometheus.Metric{} + rows, err := db.QueryContext(ctx, + `SELECT pg_database.datname + ,pg_database_size(pg_database.datname) + FROM pg_database;`) + if err != nil { + return metrics, err + } + defer rows.Close() + + for rows.Next() { + var datname string + var size int64 + if err := rows.Scan(&datname, &size); err != nil { + return metrics, err + } + metrics = append(metrics, prometheus.MustNewConstMetric( + pgDatabase["size_bytes"], + prometheus.GaugeValue, float64(size), datname, + )) + } + if err := rows.Err(); err != nil { + return metrics, err + } + return metrics, nil +} diff --git a/queries.yaml b/queries.yaml index 1102da447..6f2008cbe 100644 --- a/queries.yaml +++ b/queries.yaml @@ -146,18 +146,6 @@ pg_statio_user_tables: usage: "COUNTER" description: "Number of buffer hits in this table's TOAST table indexes (if any)" -pg_database: - query: "SELECT pg_database.datname, pg_database_size(pg_database.datname) as size_bytes FROM pg_database" - master: true - cache_seconds: 30 - metrics: - - datname: - usage: "LABEL" - description: "Name of the database" - - size_bytes: - usage: "GAUGE" - description: "Disk space used by the database" - # WARNING: This set of metrics can be very expensive on a busy server as every unique query executed will create an additional time series pg_stat_statements: query: "SELECT t2.rolname, t3.datname, queryid, calls, total_time / 1000 as total_time_seconds, min_time / 1000 as min_time_seconds, max_time / 1000 as max_time_seconds, mean_time / 1000 as mean_time_seconds, stddev_time / 1000 as stddev_time_seconds, rows, shared_blks_hit, shared_blks_read, shared_blks_dirtied, shared_blks_written, local_blks_hit, local_blks_read, local_blks_dirtied, local_blks_written, temp_blks_read, temp_blks_written, blk_read_time / 1000 as blk_read_time_seconds, blk_write_time / 1000 as blk_write_time_seconds FROM pg_stat_statements t1 JOIN pg_roles t2 ON (t1.userid=t2.oid) JOIN pg_database t3 ON (t1.dbid=t3.oid) WHERE t2.rolname != 'rdsadmin'" From 1981623d9d391a8076d52d3938d56f0648e11344 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 9 Feb 2022 21:56:48 -0500 Subject: [PATCH 023/228] Add missing server label Signed-off-by: Joe Adams --- collector/pg_database.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/collector/pg_database.go b/collector/pg_database.go index a7cb66f9a..824750456 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -30,7 +30,7 @@ var pgDatabase = map[string]*prometheus.Desc{ "size_bytes": prometheus.NewDesc( "pg_database_size_bytes", "Disk space used by the database", - []string{"datname"}, nil, + []string{"datname", "server"}, nil, ), } @@ -53,7 +53,7 @@ func (PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, server string } metrics = append(metrics, prometheus.MustNewConstMetric( pgDatabase["size_bytes"], - prometheus.GaugeValue, float64(size), datname, + prometheus.GaugeValue, float64(size), datname, server, )) } if err := rows.Err(); err != nil { From 53b24d7a33463457f102abd5058640f9fba1c6d5 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 9 Feb 2022 22:13:18 -0500 Subject: [PATCH 024/228] Update rc file to reflect newer args Signed-off-by: Joe Adams --- postgres_exporter.rc | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/postgres_exporter.rc b/postgres_exporter.rc index 2dd4a6025..d7c554689 100644 --- a/postgres_exporter.rc +++ b/postgres_exporter.rc @@ -4,7 +4,7 @@ # REQUIRE: LOGIN # KEYWORD: shutdown # -# rc-script for postgres_exporter +# rc-script for postgres_exporter # # # Add the following lines to /etc/rc.conf.local or /etc/rc.conf @@ -29,23 +29,8 @@ # postgres_exporter_pg_port (string): Set the Postgres database port # Defaults to "5432" -# Add extra arguments via "postgres_exporter_args" which could be choosen from: +# Add extra arguments via "postgres_exporter_args" # (see $ postgres_exporter --help) -# -# -dumpmaps -# Do not run, simply dump the maps. -# -extend.query-path string -# Path to custom queries to run. -# -log.level value -# Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]. -# -version -# print version and exit -# -web.telemetry-path string -# Path under which to expose metrics. (default "/metrics") -# -log.format value -# If set use a syslog logger or JSON logging. Example: logger:syslog?appname=bob&local=7 or logger:stdout?json=true. Defaults to stderr. -# -extend.query-path string -# Path to custom queries to run. . /etc/rc.subr @@ -72,7 +57,7 @@ pidfile=/var/run/postgres_exporter.pid command="/usr/sbin/daemon" procname="/usr/local/bin/postgres_exporter" command_args="-p ${pidfile} /usr/bin/env DATA_SOURCE_NAME="${postgres_exporter_data_source_name}" ${procname} \ - -web.listen-address=${postgres_exporter_listen_address} \ + --web.listen-address=${postgres_exporter_listen_address} \ ${postgres_exporter_args}" start_precmd=postgres_exporter_startprecmd @@ -86,4 +71,3 @@ postgres_exporter_startprecmd() load_rc_config $name run_rc_command "$1" - From c3b02063690499f33e94ad9343e2c6922fe4f1af Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Mon, 14 Feb 2022 21:12:27 -0500 Subject: [PATCH 025/228] Add collector interface Uses node_exporter style collector registration Signed-off-by: Joe Adams --- cmd/postgres_exporter/main.go | 8 ++ cmd/postgres_exporter/server.go | 14 --- collector/collector.go | 210 ++++++++++++++++++++++++++++++++ collector/pg_database.go | 38 +++--- collector/server.go | 100 +++++++++++++++ 5 files changed, 342 insertions(+), 28 deletions(-) create mode 100644 collector/collector.go create mode 100644 collector/server.go diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 87ce17c83..987ea9176 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -19,6 +19,7 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" + "github.com/prometheus-community/postgres_exporter/collector" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/promlog" @@ -114,6 +115,13 @@ func main() { prometheus.MustRegister(exporter) + pe, err := collector.NewPostgresCollector(logger, dsn) + if err != nil { + level.Error(logger).Log("msg", "Failed to create PostgresCollector", "err", err.Error()) + os.Exit(1) + } + prometheus.MustRegister(pe) + http.Handle(*metricPath, promhttp.Handler()) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=UTF-8") // nolint: errcheck diff --git a/cmd/postgres_exporter/server.go b/cmd/postgres_exporter/server.go index 6a08e9981..8747dffa0 100644 --- a/cmd/postgres_exporter/server.go +++ b/cmd/postgres_exporter/server.go @@ -14,16 +14,13 @@ package main import ( - "context" "database/sql" "fmt" - "log" "sync" "time" "github.com/blang/semver" "github.com/go-kit/log/level" - "github.com/prometheus-community/postgres_exporter/collector" "github.com/prometheus/client_golang/prometheus" ) @@ -131,17 +128,6 @@ func (s *Server) Scrape(ch chan<- prometheus.Metric, disableSettingsMetrics bool err = fmt.Errorf("queryNamespaceMappings returned %d errors", len(errMap)) } - { - pgdb := collector.NewPGDatabaseCollector() - metrics, err := pgdb.Update(context.TODO(), s.db, s.String()) - if err != nil { - log.Printf("Failed to scrape pg_database metrics: %s", err) - } - for _, m := range metrics { - ch <- m - } - } - return err } diff --git a/collector/collector.go b/collector/collector.go new file mode 100644 index 000000000..60a5510e9 --- /dev/null +++ b/collector/collector.go @@ -0,0 +1,210 @@ +// Copyright 2022 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 collector + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus/client_golang/prometheus" + "gopkg.in/alecthomas/kingpin.v2" +) + +var ( + factories = make(map[string]func(logger log.Logger) (Collector, error)) + initiatedCollectorsMtx = sync.Mutex{} + initiatedCollectors = make(map[string]Collector) + collectorState = make(map[string]*bool) + forcedCollectors = map[string]bool{} // collectors which have been explicitly enabled or disabled +) + +const ( + // Namespace for all metrics. + namespace = "pg" + + defaultEnabled = true + defaultDisabled = false +) + +var ( + scrapeDurationDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, "scrape", "collector_duration_seconds"), + "postgres_exporter: Duration of a collector scrape.", + []string{"collector"}, + nil, + ) + scrapeSuccessDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, "scrape", "collector_success"), + "postgres_exporter: Whether a collector succeeded.", + []string{"collector"}, + nil, + ) +) + +type Collector interface { + Update(ctx context.Context, server *server, ch chan<- prometheus.Metric) error +} + +func registerCollector(name string, isDefaultEnabled bool, createFunc func(logger log.Logger) (Collector, error)) { + var helpDefaultState string + if isDefaultEnabled { + helpDefaultState = "enabled" + } else { + helpDefaultState = "disabled" + } + + // Create flag for this collector + flagName := fmt.Sprintf("collector.%s", name) + flagHelp := fmt.Sprintf("Enable the %s collector (default: %s).", name, helpDefaultState) + defaultValue := fmt.Sprintf("%v", isDefaultEnabled) + + flag := kingpin.Flag(flagName, flagHelp).Default(defaultValue).Action(collectorFlagAction(name)).Bool() + collectorState[name] = flag + + // Register the create function for this collector + factories[name] = createFunc +} + +// PostgresCollector implements the prometheus.Collector interface. +type PostgresCollector struct { + Collectors map[string]Collector + logger log.Logger + + servers map[string]*server +} + +// NewPostgresCollector creates a new PostgresCollector. +func NewPostgresCollector(logger log.Logger, dsns []string, filters ...string) (*PostgresCollector, error) { + f := make(map[string]bool) + for _, filter := range filters { + enabled, exist := collectorState[filter] + if !exist { + return nil, fmt.Errorf("missing collector: %s", filter) + } + if !*enabled { + return nil, fmt.Errorf("disabled collector: %s", filter) + } + f[filter] = true + } + collectors := make(map[string]Collector) + initiatedCollectorsMtx.Lock() + defer initiatedCollectorsMtx.Unlock() + for key, enabled := range collectorState { + if !*enabled || (len(f) > 0 && !f[key]) { + continue + } + if collector, ok := initiatedCollectors[key]; ok { + collectors[key] = collector + } else { + collector, err := factories[key](log.With(logger, "collector", key)) + if err != nil { + return nil, err + } + collectors[key] = collector + initiatedCollectors[key] = collector + } + } + + servers := make(map[string]*server) + for _, dsn := range dsns { + s, err := makeServer(dsn) + if err != nil { + return nil, err + } + servers[dsn] = s + } + + return &PostgresCollector{ + Collectors: collectors, + logger: logger, + servers: servers, + }, nil +} + +// Describe implements the prometheus.Collector interface. +func (n PostgresCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- scrapeDurationDesc + ch <- scrapeSuccessDesc +} + +// Collect implements the prometheus.Collector interface. +func (n PostgresCollector) Collect(ch chan<- prometheus.Metric) { + ctx := context.TODO() + wg := sync.WaitGroup{} + wg.Add(len(n.servers)) + for _, s := range n.servers { + go func(s *server) { + n.subCollect(ctx, s, ch) + wg.Done() + }(s) + } + wg.Wait() +} + +func (n PostgresCollector) subCollect(ctx context.Context, server *server, ch chan<- prometheus.Metric) { + wg := sync.WaitGroup{} + wg.Add(len(n.Collectors)) + for name, c := range n.Collectors { + go func(name string, c Collector) { + execute(ctx, name, c, server, ch, n.logger) + wg.Done() + }(name, c) + } + wg.Wait() +} + +func execute(ctx context.Context, name string, c Collector, s *server, ch chan<- prometheus.Metric, logger log.Logger) { + begin := time.Now() + err := c.Update(ctx, s, ch) + duration := time.Since(begin) + var success float64 + + if err != nil { + if IsNoDataError(err) { + level.Debug(logger).Log("msg", "collector returned no data", "name", name, "duration_seconds", duration.Seconds(), "err", err) + } else { + level.Error(logger).Log("msg", "collector failed", "name", name, "duration_seconds", duration.Seconds(), "err", err) + } + success = 0 + } else { + level.Debug(logger).Log("msg", "collector succeeded", "name", name, "duration_seconds", duration.Seconds()) + success = 1 + } + ch <- prometheus.MustNewConstMetric(scrapeDurationDesc, prometheus.GaugeValue, duration.Seconds(), name) + ch <- prometheus.MustNewConstMetric(scrapeSuccessDesc, prometheus.GaugeValue, success, name) +} + +// collectorFlagAction generates a new action function for the given collector +// to track whether it has been explicitly enabled or disabled from the command line. +// A new action function is needed for each collector flag because the ParseContext +// does not contain information about which flag called the action. +// See: https://github.com/alecthomas/kingpin/issues/294 +func collectorFlagAction(collector string) func(ctx *kingpin.ParseContext) error { + return func(ctx *kingpin.ParseContext) error { + forcedCollectors[collector] = true + return nil + } +} + +// ErrNoData indicates the collector found no data to collect, but had no other error. +var ErrNoData = errors.New("collector returned no data") + +func IsNoDataError(err error) bool { + return err == ErrNoData +} diff --git a/collector/pg_database.go b/collector/pg_database.go index 824750456..5868f66d8 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -1,4 +1,4 @@ -// Copyright 2021 The Prometheus Authors +// Copyright 2022 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 @@ -15,15 +15,21 @@ package collector import ( "context" - "database/sql" + "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) -type PGDatabaseCollector struct{} +func init() { + registerCollector("database", defaultEnabled, NewPGDatabaseCollector) +} + +type PGDatabaseCollector struct { + log log.Logger +} -func NewPGDatabaseCollector() *PGDatabaseCollector { - return &PGDatabaseCollector{} +func NewPGDatabaseCollector(logger log.Logger) (Collector, error) { + return &PGDatabaseCollector{log: logger}, nil } var pgDatabase = map[string]*prometheus.Desc{ @@ -34,14 +40,17 @@ var pgDatabase = map[string]*prometheus.Desc{ ), } -func (PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, server string) ([]prometheus.Metric, error) { - metrics := []prometheus.Metric{} +func (PGDatabaseCollector) Update(ctx context.Context, server *server, ch chan<- prometheus.Metric) error { + db, err := server.GetDB() + if err != nil { + return err + } rows, err := db.QueryContext(ctx, `SELECT pg_database.datname ,pg_database_size(pg_database.datname) FROM pg_database;`) if err != nil { - return metrics, err + return err } defer rows.Close() @@ -49,15 +58,16 @@ func (PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, server string var datname string var size int64 if err := rows.Scan(&datname, &size); err != nil { - return metrics, err + return err } - metrics = append(metrics, prometheus.MustNewConstMetric( + + ch <- prometheus.MustNewConstMetric( pgDatabase["size_bytes"], - prometheus.GaugeValue, float64(size), datname, server, - )) + prometheus.GaugeValue, float64(size), datname, server.GetName(), + ) } if err := rows.Err(); err != nil { - return metrics, err + return err } - return metrics, nil + return nil } diff --git a/collector/server.go b/collector/server.go new file mode 100644 index 000000000..fa490a2c6 --- /dev/null +++ b/collector/server.go @@ -0,0 +1,100 @@ +// Copyright 2022 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 collector + +import ( + "database/sql" + "fmt" + "strings" + + "github.com/lib/pq" +) + +type server struct { + dsn string + name string + db *sql.DB +} + +func makeServer(dsn string) (*server, error) { + name, err := parseServerName(dsn) + if err != nil { + return nil, err + } + return &server{ + dsn: dsn, + name: name, + }, nil +} + +func (s *server) GetDB() (*sql.DB, error) { + if s.db != nil { + return s.db, nil + } + + db, err := sql.Open("postgres", s.dsn) + if err != nil { + return nil, err + } + db.SetMaxOpenConns(1) + db.SetMaxIdleConns(1) + + s.db = db + + return s.db, nil +} + +func (s *server) GetName() string { + return s.name +} + +func (s *server) String() string { + return s.name +} + +func parseServerName(url string) (string, error) { + dsn, err := pq.ParseURL(url) + if err != nil { + dsn = url + } + + pairs := strings.Split(dsn, " ") + kv := make(map[string]string, len(pairs)) + for _, pair := range pairs { + splitted := strings.SplitN(pair, "=", 2) + if len(splitted) != 2 { + return "", fmt.Errorf("malformed dsn %q", dsn) + } + // Newer versions of pq.ParseURL quote values so trim them off if they exist + key := strings.Trim(splitted[0], "'\"") + value := strings.Trim(splitted[1], "'\"") + kv[key] = value + } + + var fingerprint string + + if host, ok := kv["host"]; ok { + fingerprint += host + } else { + fingerprint += "localhost" + } + + if port, ok := kv["port"]; ok { + fingerprint += ":" + port + } else { + fingerprint += ":5432" + } + + return fingerprint, nil +} From 9dad33c39711b7e71dfae75320f8ecf33ca13be4 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Mon, 14 Feb 2022 21:14:17 -0500 Subject: [PATCH 026/228] Comment unused var Signed-off-by: Joe Adams --- collector/collector.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/collector/collector.go b/collector/collector.go index 60a5510e9..f6a80b602 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -38,8 +38,8 @@ const ( // Namespace for all metrics. namespace = "pg" - defaultEnabled = true - defaultDisabled = false + defaultEnabled = true + // defaultDisabled = false ) var ( From 27d23d02ef107068df81d42ba50ecb4f5068e3db Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Tue, 6 Jul 2021 22:07:23 -0400 Subject: [PATCH 027/228] refactor pg_stat_bgwriter metrics into standalone collector This moves the metrics that are queried from pg_stat_bgwriter into a dedicated collector instead of dynamically generating queries and metrics from a map. It renames some metrics including adding the `_total` suffix on all of the counters to match prometheus standards. This implementation uses QueryRowContext to allow for later addition of context for cancellation. From the Postgres documentation, it states that there is one line per WAL sender process, but it is unclear how to differentiate between them in any meaningful way. When querying the table, there is no column to identify the row, only metrics about bgwriter. Signed-off-by: Joe Adams --- CHANGELOG.md | 1 + README.md | 6 + cmd/postgres_exporter/main.go | 7 +- cmd/postgres_exporter/postgres_exporter.go | 17 -- collector/collector.go | 61 +++-- collector/pg_stat_bgwriter.go | 212 ++++++++++++++++++ collector/server.go | 7 +- .../dashboards/postgres-overview.json | 10 +- 8 files changed, 280 insertions(+), 41 deletions(-) create mode 100644 collector/pg_stat_bgwriter.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ac268c86..0572bf5dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## master / unreleased +* [CHANGE] pg_stat_bgwriter counter metrics had the `_total` suffix added #556 * [ENHANCEMENT] Add pg_database_size_bytes metric #613 ## 0.10.1 / 2022-01-14 diff --git a/README.md b/README.md index 19afadbd8..bb7c90d46 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,12 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra * `help` Show context-sensitive help (also try --help-long and --help-man). +* `collector.database` + Enable the pg_database collector. Default is `enabled` + +* `collector.bgwriter` + Enable the pg_stat_bgwriter collector. Default is `enabled` + * `web.listen-address` Address to listen on for web interface and telemetry. Default is `:9187`. diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 987ea9176..39e401e53 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -115,7 +115,12 @@ func main() { prometheus.MustRegister(exporter) - pe, err := collector.NewPostgresCollector(logger, dsn) + pe, err := collector.NewPostgresCollector( + logger, + dsn, + []string{}, + collector.WithAutoDiscoverDatabases(*autoDiscoverDatabases), + ) if err != nil { level.Error(logger).Log("msg", "Failed to create PostgresCollector", "err", err.Error()) os.Exit(1) diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index 2594a9649..2574e0252 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -163,23 +163,6 @@ func dumpMaps() { } var builtinMetricMaps = map[string]intermediateMetricMap{ - "pg_stat_bgwriter": { - map[string]ColumnMapping{ - "checkpoints_timed": {COUNTER, "Number of scheduled checkpoints that have been performed", nil, nil}, - "checkpoints_req": {COUNTER, "Number of requested checkpoints that have been performed", nil, nil}, - "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}, - "checkpoint_sync_time": {COUNTER, "Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in milliseconds", nil, nil}, - "buffers_checkpoint": {COUNTER, "Number of buffers written during checkpoints", nil, nil}, - "buffers_clean": {COUNTER, "Number of buffers written by the background writer", nil, nil}, - "maxwritten_clean": {COUNTER, "Number of times the background writer stopped a cleaning scan because it had written too many buffers", nil, nil}, - "buffers_backend": {COUNTER, "Number of buffers written directly by a backend", nil, nil}, - "buffers_backend_fsync": {COUNTER, "Number of times a backend had to execute its own fsync call (normally the background writer handles those even when the backend does its own write)", nil, nil}, - "buffers_alloc": {COUNTER, "Number of buffers allocated", nil, nil}, - "stats_reset": {COUNTER, "Time at which these statistics were last reset", nil, nil}, - }, - true, - 0, - }, "pg_stat_database": { map[string]ColumnMapping{ "datid": {LABEL, "OID of a database", nil, nil}, diff --git a/collector/collector.go b/collector/collector.go index f6a80b602..e75f67ddc 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -87,10 +87,27 @@ type PostgresCollector struct { logger log.Logger servers map[string]*server + + // autoDiscoverDatabases will cause the collector to query the database + // to find other servers and also scrape them. + autoDiscoverDatabases bool } +type Option func(*PostgresCollector) error + // NewPostgresCollector creates a new PostgresCollector. -func NewPostgresCollector(logger log.Logger, dsns []string, filters ...string) (*PostgresCollector, error) { +func NewPostgresCollector(logger log.Logger, dsns []string, filters []string, options ...Option) (*PostgresCollector, error) { + p := &PostgresCollector{ + logger: logger, + } + // Apply options to customize the collector + for _, o := range options { + err := o(p) + if err != nil { + return nil, err + } + } + f := make(map[string]bool) for _, filter := range filters { enabled, exist := collectorState[filter] @@ -121,48 +138,62 @@ func NewPostgresCollector(logger log.Logger, dsns []string, filters ...string) ( } } + p.Collectors = collectors + servers := make(map[string]*server) for _, dsn := range dsns { s, err := makeServer(dsn) if err != nil { return nil, err } + // Manually provided servers are always classified as "primary" + s.isPrimary = true + + // TODO(@sysadmind): We need to discover the downstream servers and add them here. + // if p.autoDiscoverDatabases { + // } + servers[dsn] = s } - return &PostgresCollector{ - Collectors: collectors, - logger: logger, - servers: servers, - }, nil + p.servers = servers + + return p, nil +} + +func WithAutoDiscoverDatabases(discover bool) Option { + return func(p *PostgresCollector) error { + p.autoDiscoverDatabases = discover + return nil + } } // Describe implements the prometheus.Collector interface. -func (n PostgresCollector) Describe(ch chan<- *prometheus.Desc) { +func (p PostgresCollector) Describe(ch chan<- *prometheus.Desc) { ch <- scrapeDurationDesc ch <- scrapeSuccessDesc } // Collect implements the prometheus.Collector interface. -func (n PostgresCollector) Collect(ch chan<- prometheus.Metric) { +func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) { ctx := context.TODO() wg := sync.WaitGroup{} - wg.Add(len(n.servers)) - for _, s := range n.servers { + wg.Add(len(p.servers)) + for _, s := range p.servers { go func(s *server) { - n.subCollect(ctx, s, ch) + p.subCollect(ctx, s, ch) wg.Done() }(s) } wg.Wait() } -func (n PostgresCollector) subCollect(ctx context.Context, server *server, ch chan<- prometheus.Metric) { +func (p PostgresCollector) subCollect(ctx context.Context, server *server, ch chan<- prometheus.Metric) { wg := sync.WaitGroup{} - wg.Add(len(n.Collectors)) - for name, c := range n.Collectors { + wg.Add(len(p.Collectors)) + for name, c := range p.Collectors { go func(name string, c Collector) { - execute(ctx, name, c, server, ch, n.logger) + execute(ctx, name, c, server, ch, p.logger) wg.Done() }(name, c) } diff --git a/collector/pg_stat_bgwriter.go b/collector/pg_stat_bgwriter.go new file mode 100644 index 000000000..7e7d09c72 --- /dev/null +++ b/collector/pg_stat_bgwriter.go @@ -0,0 +1,212 @@ +// Copyright 2021 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 collector + +import ( + "context" + "time" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +func init() { + registerCollector("bgwriter", defaultEnabled, NewPGStatBGWriterCollector) +} + +type PGStatBGWriterCollector struct { +} + +func NewPGStatBGWriterCollector(logger log.Logger) (Collector, error) { + return &PGStatBGWriterCollector{}, nil +} + +const bgWriterSubsystem = "stat_bgwriter" + +var statBGWriter = map[string]*prometheus.Desc{ + "checkpoints_timed": prometheus.NewDesc( + prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_timed_total"), + "Number of scheduled checkpoints that have been performed", + []string{"server"}, + prometheus.Labels{}, + ), + "checkpoints_req": prometheus.NewDesc( + prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_req_total"), + "Number of requested checkpoints that have been performed", + []string{"server"}, + prometheus.Labels{}, + ), + "checkpoint_write_time": prometheus.NewDesc( + prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoint_write_time_total"), + "Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in milliseconds", + []string{"server"}, + prometheus.Labels{}, + ), + "checkpoint_sync_time": prometheus.NewDesc( + prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoint_sync_time_total"), + "Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in milliseconds", + []string{"server"}, + prometheus.Labels{}, + ), + "buffers_checkpoint": prometheus.NewDesc( + prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_checkpoint_total"), + "Number of buffers written during checkpoints", + []string{"server"}, + prometheus.Labels{}, + ), + "buffers_clean": prometheus.NewDesc( + prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_clean_total"), + "Number of buffers written by the background writer", + []string{"server"}, + prometheus.Labels{}, + ), + "maxwritten_clean": prometheus.NewDesc( + prometheus.BuildFQName(namespace, bgWriterSubsystem, "maxwritten_clean_total"), + "Number of times the background writer stopped a cleaning scan because it had written too many buffers", + []string{"server"}, + prometheus.Labels{}, + ), + "buffers_backend": prometheus.NewDesc( + prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_backend_total"), + "Number of buffers written directly by a backend", + []string{"server"}, + prometheus.Labels{}, + ), + "buffers_backend_fsync": prometheus.NewDesc( + prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_backend_fsync_total"), + "Number of times a backend had to execute its own fsync call (normally the background writer handles those even when the backend does its own write)", + []string{"server"}, + prometheus.Labels{}, + ), + "buffers_alloc": prometheus.NewDesc( + prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_alloc_total"), + "Number of buffers allocated", + []string{"server"}, + prometheus.Labels{}, + ), + "stats_reset": prometheus.NewDesc( + prometheus.BuildFQName(namespace, bgWriterSubsystem, "stats_reset_total"), + "Time at which these statistics were last reset", + []string{"server"}, + prometheus.Labels{}, + ), +} + +func (PGStatBGWriterCollector) Update(ctx context.Context, server *server, ch chan<- prometheus.Metric) error { + db, err := server.GetDB() + if err != nil { + return err + } + + row := db.QueryRowContext(ctx, + `SELECT + checkpoints_timed + ,checkpoints_req + ,checkpoint_write_time + ,checkpoint_sync_time + ,buffers_checkpoint + ,buffers_clean + ,maxwritten_clean + ,buffers_backend + ,buffers_backend_fsync + ,buffers_alloc + ,stats_reset + FROM pg_stat_bgwriter;`) + + var cpt int + var cpr int + var cpwt int + var cpst int + var bcp int + var bc int + var mwc int + var bb int + var bbf int + var ba int + var sr time.Time + + err = row.Scan(&cpt, &cpr, &cpwt, &cpst, &bcp, &bc, &mwc, &bb, &bbf, &ba, &sr) + if err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric( + statBGWriter["checkpoints_timed"], + prometheus.CounterValue, + float64(cpt), + server.GetName(), + ) + ch <- prometheus.MustNewConstMetric( + statBGWriter["checkpoints_req"], + prometheus.CounterValue, + float64(cpr), + server.GetName(), + ) + ch <- prometheus.MustNewConstMetric( + statBGWriter["checkpoint_write_time"], + prometheus.CounterValue, + float64(cpwt), + server.GetName(), + ) + ch <- prometheus.MustNewConstMetric( + statBGWriter["checkpoint_sync_time"], + prometheus.CounterValue, + float64(cpst), + server.GetName(), + ) + ch <- prometheus.MustNewConstMetric( + statBGWriter["buffers_checkpoint"], + prometheus.CounterValue, + float64(bcp), + server.GetName(), + ) + ch <- prometheus.MustNewConstMetric( + statBGWriter["buffers_clean"], + prometheus.CounterValue, + float64(bc), + server.GetName(), + ) + ch <- prometheus.MustNewConstMetric( + statBGWriter["maxwritten_clean"], + prometheus.CounterValue, + float64(mwc), + server.GetName(), + ) + ch <- prometheus.MustNewConstMetric( + statBGWriter["buffers_backend"], + prometheus.CounterValue, + float64(bb), + server.GetName(), + ) + ch <- prometheus.MustNewConstMetric( + statBGWriter["buffers_backend_fsync"], + prometheus.CounterValue, + float64(bbf), + server.GetName(), + ) + ch <- prometheus.MustNewConstMetric( + statBGWriter["buffers_alloc"], + prometheus.CounterValue, + float64(ba), + server.GetName(), + ) + ch <- prometheus.MustNewConstMetric( + statBGWriter["stats_reset"], + prometheus.CounterValue, + float64(sr.Unix()), + server.GetName(), + ) + + return nil +} diff --git a/collector/server.go b/collector/server.go index fa490a2c6..3c6d1c858 100644 --- a/collector/server.go +++ b/collector/server.go @@ -22,9 +22,10 @@ import ( ) type server struct { - dsn string - name string - db *sql.DB + dsn string + name string + db *sql.DB + isPrimary bool // Certain queries are only run on the primary server } func makeServer(dsn string) (*server, error) { diff --git a/postgres_mixin/dashboards/postgres-overview.json b/postgres_mixin/dashboards/postgres-overview.json index 24b7bc92d..5bea49262 100644 --- a/postgres_mixin/dashboards/postgres-overview.json +++ b/postgres_mixin/dashboards/postgres-overview.json @@ -584,7 +584,7 @@ { "alias": "Buffers Allocated", "dsType": "prometheus", - "expr": "irate(pg_stat_bgwriter_buffers_alloc{instance='$instance'}[5m])", + "expr": "irate(pg_stat_bgwriter_buffers_alloc_total{instance='$instance'}[5m])", "format": "time_series", "groupBy": [ { @@ -636,7 +636,7 @@ { "alias": "Buffers Allocated", "dsType": "prometheus", - "expr": "irate(pg_stat_bgwriter_buffers_backend_fsync{instance='$instance'}[5m])", + "expr": "irate(pg_stat_bgwriter_buffers_backend_fsync_total{instance='$instance'}[5m])", "format": "time_series", "groupBy": [ { @@ -688,7 +688,7 @@ { "alias": "Buffers Allocated", "dsType": "prometheus", - "expr": "irate(pg_stat_bgwriter_buffers_backend{instance='$instance'}[5m])", + "expr": "irate(pg_stat_bgwriter_buffers_backend_total{instance='$instance'}[5m])", "format": "time_series", "groupBy": [ { @@ -740,7 +740,7 @@ { "alias": "Buffers Allocated", "dsType": "prometheus", - "expr": "irate(pg_stat_bgwriter_buffers_clean{instance='$instance'}[5m])", + "expr": "irate(pg_stat_bgwriter_buffers_clean_total{instance='$instance'}[5m])", "format": "time_series", "groupBy": [ { @@ -792,7 +792,7 @@ { "alias": "Buffers Allocated", "dsType": "prometheus", - "expr": "irate(pg_stat_bgwriter_buffers_checkpoint{instance='$instance'}[5m])", + "expr": "irate(pg_stat_bgwriter_buffers_checkpoint_total{instance='$instance'}[5m])", "format": "time_series", "groupBy": [ { From 9704b9fb2e0cab389bb69f8fd98ac6afa54ed41a Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Fri, 25 Feb 2022 08:11:22 -0500 Subject: [PATCH 028/228] Clean up autoDiscoverDatabases in the new collector Signed-off-by: Joe Adams --- cmd/postgres_exporter/main.go | 1 - collector/collector.go | 17 ----------------- collector/server.go | 7 +++---- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 39e401e53..35db723a2 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -119,7 +119,6 @@ func main() { logger, dsn, []string{}, - collector.WithAutoDiscoverDatabases(*autoDiscoverDatabases), ) if err != nil { level.Error(logger).Log("msg", "Failed to create PostgresCollector", "err", err.Error()) diff --git a/collector/collector.go b/collector/collector.go index e75f67ddc..58765b659 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -87,10 +87,6 @@ type PostgresCollector struct { logger log.Logger servers map[string]*server - - // autoDiscoverDatabases will cause the collector to query the database - // to find other servers and also scrape them. - autoDiscoverDatabases bool } type Option func(*PostgresCollector) error @@ -146,12 +142,6 @@ func NewPostgresCollector(logger log.Logger, dsns []string, filters []string, op if err != nil { return nil, err } - // Manually provided servers are always classified as "primary" - s.isPrimary = true - - // TODO(@sysadmind): We need to discover the downstream servers and add them here. - // if p.autoDiscoverDatabases { - // } servers[dsn] = s } @@ -161,13 +151,6 @@ func NewPostgresCollector(logger log.Logger, dsns []string, filters []string, op return p, nil } -func WithAutoDiscoverDatabases(discover bool) Option { - return func(p *PostgresCollector) error { - p.autoDiscoverDatabases = discover - return nil - } -} - // Describe implements the prometheus.Collector interface. func (p PostgresCollector) Describe(ch chan<- *prometheus.Desc) { ch <- scrapeDurationDesc diff --git a/collector/server.go b/collector/server.go index 3c6d1c858..fa490a2c6 100644 --- a/collector/server.go +++ b/collector/server.go @@ -22,10 +22,9 @@ import ( ) type server struct { - dsn string - name string - db *sql.DB - isPrimary bool // Certain queries are only run on the primary server + dsn string + name string + db *sql.DB } func makeServer(dsn string) (*server, error) { From be308594171257fdc86d238e2697d1ce39ed58e0 Mon Sep 17 00:00:00 2001 From: Angus Dippenaar Date: Thu, 3 Mar 2022 15:31:53 +0100 Subject: [PATCH 029/228] Remove unit from setting because of Aurora Signed-off-by: Angus Dippenaar --- cmd/postgres_exporter/pg_setting.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/cmd/postgres_exporter/pg_setting.go b/cmd/postgres_exporter/pg_setting.go index b361ac483..bfe4c6c52 100644 --- a/cmd/postgres_exporter/pg_setting.go +++ b/cmd/postgres_exporter/pg_setting.go @@ -23,6 +23,13 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +var ( + settingUnits = []string{ + "ms", "s", "min", "h", "d", + "B", "kB", "MB", "GB", "TB", + } +) + // Query the pg_settings view containing runtime variables func querySettings(ch chan<- prometheus.Metric, server *Server) error { level.Debug(logger).Log("msg", "Querying pg_setting view", "server", server) @@ -93,9 +100,24 @@ func (s *pgSetting) metric(labels prometheus.Labels) prometheus.Metric { return prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, val) } +// Removes units from any of the setting values. +// This is mostly because of a irregularity regarding AWS RDS Aurora +// https://github.com/prometheus-community/postgres_exporter/issues/619 +func (s *pgSetting) sanitizeValue() { + for _, unit := range settingUnits { + if strings.HasSuffix(s.setting, unit) { + endPos := len(s.setting) - len(unit) - 1 + s.setting = s.setting[:endPos] + return + } + } +} + // TODO: fix linter override // nolint: nakedret func (s *pgSetting) normaliseUnit() (val float64, unit string, err error) { + s.sanitizeValue() + val, err = strconv.ParseFloat(s.setting, 64) if err != nil { return val, unit, fmt.Errorf("Error converting setting %q value %q to float: %s", s.name, s.setting, err) From ecd002833d64d4ac8ba73cc6bc7f35a9c3c8e5b2 Mon Sep 17 00:00:00 2001 From: Antoine Barbare Date: Fri, 11 Mar 2022 08:16:07 +0100 Subject: [PATCH 030/228] fix: CVE-2022-21698 Signed-off-by: Antoine Barbare --- go.mod | 2 +- go.sum | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 6fb663aaf..e2b5398fa 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/blang/semver v3.5.1+incompatible github.com/go-kit/log v0.2.0 github.com/lib/pq v1.10.4 - github.com/prometheus/client_golang v1.11.0 + github.com/prometheus/client_golang v1.12.1 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.32.1 github.com/prometheus/exporter-toolkit v0.7.1 diff --git a/go.sum b/go.sum index c1669ca25..7302e2287 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,9 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -100,8 +101,10 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -135,6 +138,7 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -157,6 +161,7 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -169,8 +174,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -187,8 +193,9 @@ github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQY github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -327,8 +334,9 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -459,8 +467,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 4e78805496b095818a98ea19ee197321290b7fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Krupa=20=28paulfantom=29?= Date: Sun, 10 Apr 2022 15:36:24 +0200 Subject: [PATCH 031/228] postgres_mixin: jsonnify alerts file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Krupa (paulfantom) --- postgres_mixin/alerts/alerts.libsonnet | 1 + postgres_mixin/alerts/alerts.yaml | 57 ------------- postgres_mixin/alerts/postgres.libsonnet | 83 +++++++++++++++++++ .../dashboards/dashboards.libsonnet | 5 ++ postgres_mixin/mixin.libsonnet | 15 +--- 5 files changed, 91 insertions(+), 70 deletions(-) create mode 100644 postgres_mixin/alerts/alerts.libsonnet delete mode 100644 postgres_mixin/alerts/alerts.yaml create mode 100644 postgres_mixin/alerts/postgres.libsonnet create mode 100644 postgres_mixin/dashboards/dashboards.libsonnet diff --git a/postgres_mixin/alerts/alerts.libsonnet b/postgres_mixin/alerts/alerts.libsonnet new file mode 100644 index 000000000..7f70d8a8d --- /dev/null +++ b/postgres_mixin/alerts/alerts.libsonnet @@ -0,0 +1 @@ +(import 'postgres.libsonnet') diff --git a/postgres_mixin/alerts/alerts.yaml b/postgres_mixin/alerts/alerts.yaml deleted file mode 100644 index ff3d75a7f..000000000 --- a/postgres_mixin/alerts/alerts.yaml +++ /dev/null @@ -1,57 +0,0 @@ ---- -groups: - - name: PostgreSQL - rules: - - alert: PostgreSQLMaxConnectionsReached - expr: sum(pg_stat_activity_count) by (instance) >= sum(pg_settings_max_connections) by (instance) - sum(pg_settings_superuser_reserved_connections) by (instance) - for: 1m - labels: - severity: email - annotations: - summary: "{{ $labels.instance }} has maxed out Postgres connections." - description: "{{ $labels.instance }} is exceeding the currently configured maximum Postgres connection limit (current value: {{ $value }}s). Services may be degraded - please take immediate action (you probably need to increase max_connections in the Docker image and re-deploy." - - - alert: PostgreSQLHighConnections - expr: sum(pg_stat_activity_count) by (instance) > (sum(pg_settings_max_connections) by (instance) - sum(pg_settings_superuser_reserved_connections) by (instance)) * 0.8 - for: 10m - labels: - severity: email - annotations: - summary: "{{ $labels.instance }} is over 80% of max Postgres connections." - description: "{{ $labels.instance }} is exceeding 80% of the currently configured maximum Postgres connection limit (current value: {{ $value }}s). Please check utilization graphs and confirm if this is normal service growth, abuse or an otherwise temporary condition or if new resources need to be provisioned (or the limits increased, which is mostly likely)." - - - alert: PostgreSQLDown - expr: pg_up != 1 - for: 1m - labels: - severity: email - annotations: - summary: "PostgreSQL is not processing queries: {{ $labels.instance }}" - description: "{{ $labels.instance }} is rejecting query requests from the exporter, and thus probably not allowing DNS requests to work either. User services should not be effected provided at least 1 node is still alive." - - - alert: PostgreSQLSlowQueries - expr: avg(rate(pg_stat_activity_max_tx_duration{datname!~"template.*"}[2m])) by (datname) > 2 * 60 - for: 2m - labels: - severity: email - annotations: - summary: "PostgreSQL high number of slow on {{ $labels.cluster }} for database {{ $labels.datname }} " - description: "PostgreSQL high number of slow queries {{ $labels.cluster }} for database {{ $labels.datname }} with a value of {{ $value }} " - - - alert: PostgreSQLQPS - expr: avg(irate(pg_stat_database_xact_commit{datname!~"template.*"}[5m]) + irate(pg_stat_database_xact_rollback{datname!~"template.*"}[5m])) by (datname) > 10000 - for: 5m - labels: - severity: email - annotations: - summary: "PostgreSQL high number of queries per second {{ $labels.cluster }} for database {{ $labels.datname }}" - description: "PostgreSQL high number of queries per second on {{ $labels.cluster }} for database {{ $labels.datname }} with a value of {{ $value }}" - - - alert: PostgreSQLCacheHitRatio - expr: avg(rate(pg_stat_database_blks_hit{datname!~"template.*"}[5m]) / (rate(pg_stat_database_blks_hit{datname!~"template.*"}[5m]) + rate(pg_stat_database_blks_read{datname!~"template.*"}[5m]))) by (datname) < 0.98 - for: 5m - labels: - severity: email - annotations: - summary: "PostgreSQL low cache hit rate on {{ $labels.cluster }} for database {{ $labels.datname }}" - description: "PostgreSQL low on cache hit rate on {{ $labels.cluster }} for database {{ $labels.datname }} with a value of {{ $value }}" diff --git a/postgres_mixin/alerts/postgres.libsonnet b/postgres_mixin/alerts/postgres.libsonnet new file mode 100644 index 000000000..29e339234 --- /dev/null +++ b/postgres_mixin/alerts/postgres.libsonnet @@ -0,0 +1,83 @@ +{ + prometheusAlerts+:: { + groups+: [ + { + name: 'PostgreSQL', + rules: [ + { + alert: 'PostgreSQLMaxConnectionsReached', + annotations: { + description: '{{ $labels.instance }} is exceeding the currently configured maximum Postgres connection limit (current value: {{ $value }}s). Services may be degraded - please take immediate action (you probably need to increase max_connections in the Docker image and re-deploy.', + summary: '{{ $labels.instance }} has maxed out Postgres connections.', + }, + expr: 'sum(pg_stat_activity_count) by (instance) >= sum(pg_settings_max_connections) by (instance) - sum(pg_settings_superuser_reserved_connections) by (instance)', + 'for': '1m', + labels: { + severity: 'email', + }, + }, + { + alert: 'PostgreSQLHighConnections', + annotations: { + description: '{{ $labels.instance }} is exceeding 80% of the currently configured maximum Postgres connection limit (current value: {{ $value }}s). Please check utilization graphs and confirm if this is normal service growth, abuse or an otherwise temporary condition or if new resources need to be provisioned (or the limits increased, which is mostly likely).', + summary: '{{ $labels.instance }} is over 80% of max Postgres connections.', + }, + expr: 'sum(pg_stat_activity_count) by (instance) > (sum(pg_settings_max_connections) by (instance) - sum(pg_settings_superuser_reserved_connections) by (instance)) * 0.8', + 'for': '10m', + labels: { + severity: 'email', + }, + }, + { + alert: 'PostgreSQLDown', + annotations: { + description: '{{ $labels.instance }} is rejecting query requests from the exporter, and thus probably not allowing DNS requests to work either. User services should not be effected provided at least 1 node is still alive.', + summary: 'PostgreSQL is not processing queries: {{ $labels.instance }}', + }, + expr: 'pg_up != 1', + 'for': '1m', + labels: { + severity: 'email', + }, + }, + { + alert: 'PostgreSQLSlowQueries', + annotations: { + description: 'PostgreSQL high number of slow queries {{ $labels.cluster }} for database {{ $labels.datname }} with a value of {{ $value }} ', + summary: 'PostgreSQL high number of slow on {{ $labels.cluster }} for database {{ $labels.datname }} ', + }, + expr: 'avg(rate(pg_stat_activity_max_tx_duration{datname!~"template.*"}[2m])) by (datname) > 2 * 60', + 'for': '2m', + labels: { + severity: 'email', + }, + }, + { + alert: 'PostgreSQLQPS', + annotations: { + description: 'PostgreSQL high number of queries per second on {{ $labels.cluster }} for database {{ $labels.datname }} with a value of {{ $value }}', + summary: 'PostgreSQL high number of queries per second {{ $labels.cluster }} for database {{ $labels.datname }}', + }, + expr: 'avg(irate(pg_stat_database_xact_commit{datname!~"template.*"}[5m]) + irate(pg_stat_database_xact_rollback{datname!~"template.*"}[5m])) by (datname) > 10000', + 'for': '5m', + labels: { + severity: 'email', + }, + }, + { + alert: 'PostgreSQLCacheHitRatio', + annotations: { + description: 'PostgreSQL low on cache hit rate on {{ $labels.cluster }} for database {{ $labels.datname }} with a value of {{ $value }}', + summary: 'PostgreSQL low cache hit rate on {{ $labels.cluster }} for database {{ $labels.datname }}', + }, + expr: 'avg(rate(pg_stat_database_blks_hit{datname!~"template.*"}[5m]) / (rate(pg_stat_database_blks_hit{datname!~"template.*"}[5m]) + rate(pg_stat_database_blks_read{datname!~"template.*"}[5m]))) by (datname) < 0.98', + 'for': '5m', + labels: { + severity: 'email', + }, + }, + ], + }, + ], + }, +} diff --git a/postgres_mixin/dashboards/dashboards.libsonnet b/postgres_mixin/dashboards/dashboards.libsonnet new file mode 100644 index 000000000..d55f1ef5c --- /dev/null +++ b/postgres_mixin/dashboards/dashboards.libsonnet @@ -0,0 +1,5 @@ +{ + grafanaDashboards+:: { + 'postgres-overview.json': (import 'postgres-overview.json'), + }, +} diff --git a/postgres_mixin/mixin.libsonnet b/postgres_mixin/mixin.libsonnet index 98c7ea7d1..6dac631cd 100644 --- a/postgres_mixin/mixin.libsonnet +++ b/postgres_mixin/mixin.libsonnet @@ -1,13 +1,2 @@ -{ - grafanaDashboards: { - 'postgres-overview.json': (import 'dashboards/postgres-overview.json'), - }, - - // Helper function to ensure that we don't override other rules, by forcing - // the patching of the groups list, and not the overall rules object. - local importRules(rules) = { - groups+: std.native('parseYaml')(rules)[0].groups, - }, - - prometheusAlerts+: importRules(importstr 'alerts/alerts.yaml'), -} +(import 'alerts/alerts.libsonnet') + +(import 'dashboards/dashboards.libsonnet') \ No newline at end of file From aa38fa6ba641d1656b3a62121bd72b6c5e93d153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Krupa=20=28paulfantom=29?= Date: Sun, 10 Apr 2022 16:22:25 +0200 Subject: [PATCH 032/228] postgres_mixin/alerts: change severity to "warning" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changing severity to align with mixin recommendations from https://github.com/monitoring-mixins/docs#guidelines-for-alert-names-labels-and-annotations Signed-off-by: Paweł Krupa (paulfantom) --- postgres_mixin/alerts/postgres.libsonnet | 68 +++++++++++++++++++----- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/postgres_mixin/alerts/postgres.libsonnet b/postgres_mixin/alerts/postgres.libsonnet index 29e339234..d70f669d5 100644 --- a/postgres_mixin/alerts/postgres.libsonnet +++ b/postgres_mixin/alerts/postgres.libsonnet @@ -10,10 +10,16 @@ description: '{{ $labels.instance }} is exceeding the currently configured maximum Postgres connection limit (current value: {{ $value }}s). Services may be degraded - please take immediate action (you probably need to increase max_connections in the Docker image and re-deploy.', summary: '{{ $labels.instance }} has maxed out Postgres connections.', }, - expr: 'sum(pg_stat_activity_count) by (instance) >= sum(pg_settings_max_connections) by (instance) - sum(pg_settings_superuser_reserved_connections) by (instance)', + expr: ||| + sum by (instance) (pg_stat_activity_count{%(postgresExporterSelector)s}) + >= + sum by (instance) (pg_settings_max_connections{%(postgresExporterSelector)s}) + - + sum by (instance) (pg_settings_superuser_reserved_connections{%(postgresExporterSelector)s}) + ||| % $._config, 'for': '1m', labels: { - severity: 'email', + severity: 'warning', }, }, { @@ -22,10 +28,18 @@ description: '{{ $labels.instance }} is exceeding 80% of the currently configured maximum Postgres connection limit (current value: {{ $value }}s). Please check utilization graphs and confirm if this is normal service growth, abuse or an otherwise temporary condition or if new resources need to be provisioned (or the limits increased, which is mostly likely).', summary: '{{ $labels.instance }} is over 80% of max Postgres connections.', }, - expr: 'sum(pg_stat_activity_count) by (instance) > (sum(pg_settings_max_connections) by (instance) - sum(pg_settings_superuser_reserved_connections) by (instance)) * 0.8', + expr: ||| + sum by (instance) (pg_stat_activity_count{%(postgresExporterSelector)s}) + > + ( + sum by (instance) (pg_settings_max_connections{%(postgresExporterSelector)s}) + - + sum by (instance) (pg_settings_superuser_reserved_connections{%(postgresExporterSelector)s}) + ) * 0.8 + ||| % $._config, 'for': '10m', labels: { - severity: 'email', + severity: 'warning', }, }, { @@ -34,10 +48,10 @@ description: '{{ $labels.instance }} is rejecting query requests from the exporter, and thus probably not allowing DNS requests to work either. User services should not be effected provided at least 1 node is still alive.', summary: 'PostgreSQL is not processing queries: {{ $labels.instance }}', }, - expr: 'pg_up != 1', + expr: 'pg_up{%(postgresExporterSelector)s} != 1' % $._config, 'for': '1m', labels: { - severity: 'email', + severity: 'warning', }, }, { @@ -46,10 +60,16 @@ description: 'PostgreSQL high number of slow queries {{ $labels.cluster }} for database {{ $labels.datname }} with a value of {{ $value }} ', summary: 'PostgreSQL high number of slow on {{ $labels.cluster }} for database {{ $labels.datname }} ', }, - expr: 'avg(rate(pg_stat_activity_max_tx_duration{datname!~"template.*"}[2m])) by (datname) > 2 * 60', + expr: ||| + avg( + rate by (datname) ( + pg_stat_activity_max_tx_duration{datname!~"template.*",%(postgresExporterSelector)s}[2m] + ) + ) > 2 * 60 + ||| % $._config, 'for': '2m', labels: { - severity: 'email', + severity: 'warning', }, }, { @@ -58,10 +78,20 @@ description: 'PostgreSQL high number of queries per second on {{ $labels.cluster }} for database {{ $labels.datname }} with a value of {{ $value }}', summary: 'PostgreSQL high number of queries per second {{ $labels.cluster }} for database {{ $labels.datname }}', }, - expr: 'avg(irate(pg_stat_database_xact_commit{datname!~"template.*"}[5m]) + irate(pg_stat_database_xact_rollback{datname!~"template.*"}[5m])) by (datname) > 10000', + expr: ||| + avg by (datname) ( + irate( + pg_stat_database_xact_commit{datname!~"template.*",%(postgresExporterSelector)s}[5m] + ) + + + irate( + pg_stat_database_xact_rollback{datname!~"template.*",%(postgresExporterSelector)s}[5m] + ) + ) > 10000 + ||| % $._config, 'for': '5m', labels: { - severity: 'email', + severity: 'warning', }, }, { @@ -70,10 +100,24 @@ description: 'PostgreSQL low on cache hit rate on {{ $labels.cluster }} for database {{ $labels.datname }} with a value of {{ $value }}', summary: 'PostgreSQL low cache hit rate on {{ $labels.cluster }} for database {{ $labels.datname }}', }, - expr: 'avg(rate(pg_stat_database_blks_hit{datname!~"template.*"}[5m]) / (rate(pg_stat_database_blks_hit{datname!~"template.*"}[5m]) + rate(pg_stat_database_blks_read{datname!~"template.*"}[5m]))) by (datname) < 0.98', + expr: ||| + avg by (datname) ( + rate(pg_stat_database_blks_hit{datname!~"template.*",%(postgresExporterSelector)s}[5m]) + / + ( + rate( + pg_stat_database_blks_hit{datname!~"template.*",%(postgresExporterSelector)s}[5m] + ) + + + rate( + pg_stat_database_blks_read{datname!~"template.*",%(postgresExporterSelector)s}[5m] + ) + ) + ) < 0.98 + ||| % $._config, 'for': '5m', labels: { - severity: 'email', + severity: 'warning', }, }, ], From c95fd0d482d359844c8ef081c7e3da86c6fe2f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Krupa=20=28paulfantom=29?= Date: Sun, 10 Apr 2022 16:23:24 +0200 Subject: [PATCH 033/228] postgres_mixin: allow parametrization of mixin by using _config object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Krupa (paulfantom) --- postgres_mixin/config.libsonnet | 5 +++++ postgres_mixin/mixin.libsonnet | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 postgres_mixin/config.libsonnet diff --git a/postgres_mixin/config.libsonnet b/postgres_mixin/config.libsonnet new file mode 100644 index 000000000..d7bd7ac1b --- /dev/null +++ b/postgres_mixin/config.libsonnet @@ -0,0 +1,5 @@ +{ + _config+:: { + postgresExporterSelector: '', + }, +} diff --git a/postgres_mixin/mixin.libsonnet b/postgres_mixin/mixin.libsonnet index 6dac631cd..119d2cdde 100644 --- a/postgres_mixin/mixin.libsonnet +++ b/postgres_mixin/mixin.libsonnet @@ -1,2 +1,3 @@ (import 'alerts/alerts.libsonnet') + -(import 'dashboards/dashboards.libsonnet') \ No newline at end of file +(import 'dashboards/dashboards.libsonnet') + +(import 'config.libsonnet') From db429bd4b1be2f22e01017abe0bd9b35417c1ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Krupa=20=28paulfantom=29?= Date: Sat, 23 Apr 2022 08:34:39 +0200 Subject: [PATCH 034/228] postgres_mixin/alerts: fix incorrect promql aggregation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Krupa (paulfantom) --- postgres_mixin/alerts/postgres.libsonnet | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres_mixin/alerts/postgres.libsonnet b/postgres_mixin/alerts/postgres.libsonnet index d70f669d5..4b0275df1 100644 --- a/postgres_mixin/alerts/postgres.libsonnet +++ b/postgres_mixin/alerts/postgres.libsonnet @@ -61,8 +61,8 @@ summary: 'PostgreSQL high number of slow on {{ $labels.cluster }} for database {{ $labels.datname }} ', }, expr: ||| - avg( - rate by (datname) ( + avg by (datname) ( + rate ( pg_stat_activity_max_tx_duration{datname!~"template.*",%(postgresExporterSelector)s}[2m] ) ) > 2 * 60 From 81c49339860692b39b043a946b9167df1b28d938 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Wed, 25 May 2022 11:27:42 +0200 Subject: [PATCH 035/228] Update build * Update to Go 1.18. * Update minimum Go version to 1.17. * Update Go modules for 1.17 format. * Bump Go modules * Enable dependabot. * Update Prometheus common files. * Fixup yamllint. Signed-off-by: SuperQ --- .circleci/config.yml | 6 ++-- .github/dependabot.yml | 6 ++++ .github/workflows/golangci-lint.yml | 30 +++++++++++++++++ .promu.yml | 2 +- .yamllint | 28 ++++++++++++++++ Makefile.common | 2 +- .../docker-compose.yml | 12 +++---- go.mod | 33 ++++++++++++++++--- go.sum | 25 +++++++++----- 9 files changed, 120 insertions(+), 24 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/golangci-lint.yml create mode 100644 .yamllint diff --git a/.circleci/config.yml b/.circleci/config.yml index 18f50cfc4..db3cad4e5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,13 +2,13 @@ version: 2.1 orbs: - prometheus: prometheus/prometheus@0.15.0 + prometheus: prometheus/prometheus@0.16.0 executors: # This must match .promu.yml. golang: docker: - - image: circleci/golang:1.17 + - image: cimg/go:1.18 jobs: test: @@ -22,7 +22,7 @@ jobs: integration: docker: - - image: circleci/golang:1.17 + - image: cimg/go:1.18 - image: << parameters.postgres_image >> environment: POSTGRES_DB: circle_test diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..202ae2366 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "monthly" diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 000000000..136d7d4b9 --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,30 @@ +name: golangci-lint +on: + push: + paths: + - "go.sum" + - "go.mod" + - "**.go" + - "scripts/errcheck_excludes.txt" + - ".github/workflows/golangci-lint.yml" + - ".golangci.yml" + pull_request: + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: install Go + uses: actions/setup-go@v2 + with: + go-version: 1.18.x + - name: Install snmp_exporter/generator dependencies + run: sudo apt-get update && sudo apt-get -y install libsnmp-dev + if: github.repository == 'prometheus/snmp_exporter' + - name: Lint + uses: golangci/golangci-lint-action@v3.1.0 + with: + version: v1.45.2 diff --git a/.promu.yml b/.promu.yml index 8414f69eb..d63d0444d 100644 --- a/.promu.yml +++ b/.promu.yml @@ -1,6 +1,6 @@ go: # This must match .circle/config.yml. - version: 1.17 + version: 1.18 repository: path: github.com/prometheus-community/postgres_exporter build: diff --git a/.yamllint b/.yamllint new file mode 100644 index 000000000..3878a31d3 --- /dev/null +++ b/.yamllint @@ -0,0 +1,28 @@ +--- +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + commas: disable + comments: disable + comments-indentation: disable + document-start: disable + indentation: + spaces: consistent + indent-sequences: consistent + key-duplicates: + ignore: | + config/testdata/section_key_dup.bad.yml + line-length: disable + truthy: + ignore: | + .github/workflows/codeql-analysis.yml + .github/workflows/funcbench.yml + .github/workflows/fuzzing.yml + .github/workflows/prombench.yml + .github/workflows/golangci-lint.yml diff --git a/Makefile.common b/Makefile.common index bf7304e58..c263b733f 100644 --- a/Makefile.common +++ b/Makefile.common @@ -83,7 +83,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.42.0 +GOLANGCI_LINT_VERSION ?= v1.45.2 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) diff --git a/cmd/postgres_exporter/tests/docker-postgres-replication/docker-compose.yml b/cmd/postgres_exporter/tests/docker-postgres-replication/docker-compose.yml index 81a66da10..3ea59a85b 100644 --- a/cmd/postgres_exporter/tests/docker-postgres-replication/docker-compose.yml +++ b/cmd/postgres_exporter/tests/docker-postgres-replication/docker-compose.yml @@ -1,4 +1,4 @@ - +--- version: '2' services: @@ -11,9 +11,9 @@ services: POSTGRES_PASSWORD: 'postgres' PGDATA: '/var/lib/postgresql/data/pgdata' volumes: - - '/var/lib/postgresql/data' + - '/var/lib/postgresql/data' expose: - - '5432' + - '5432' pg-slave: build: '.' @@ -25,8 +25,8 @@ services: PGDATA: '/var/lib/postgresql/data/pgdata' REPLICATE_FROM: 'pg-master' volumes: - - '/var/lib/postgresql/data' + - '/var/lib/postgresql/data' expose: - - '5432' + - '5432' links: - - 'pg-master' + - 'pg-master' diff --git a/go.mod b/go.mod index e2b5398fa..c2505f7fe 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,39 @@ module github.com/prometheus-community/postgres_exporter -go 1.14 +go 1.17 require ( github.com/blang/semver v3.5.1+incompatible - github.com/go-kit/log v0.2.0 - github.com/lib/pq v1.10.4 - github.com/prometheus/client_golang v1.12.1 + github.com/go-kit/log v0.2.1 + github.com/lib/pq v1.10.6 + github.com/prometheus/client_golang v1.12.2 github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.32.1 + github.com/prometheus/common v0.34.0 github.com/prometheus/exporter-toolkit v0.7.1 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 ) + +require ( + github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect + github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/jpillora/backoff v1.0.0 // indirect + github.com/kr/pretty v0.2.1 // indirect + github.com/kr/text v0.1.0 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect + golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect + golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect + golang.org/x/text v0.3.7 // indirect + google.golang.org/appengine v1.6.6 // indirect + google.golang.org/protobuf v1.26.0 // indirect +) diff --git a/go.sum b/go.sum index 7302e2287..8bc754b16 100644 --- a/go.sum +++ b/go.sum @@ -68,8 +68,9 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -153,8 +154,8 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= -github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= +github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -175,8 +176,9 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -186,8 +188,9 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.34.0 h1:RBmGO9d/FVjqHT0yUGQwBJhkwKV+wPCn7KGpvfab0uE= +github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= github.com/prometheus/exporter-toolkit v0.7.1 h1:c6RXaK8xBVercEeUQ4tRNL8UGWzDHfvj9dseo1FcK1Y= github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -281,15 +284,18 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -335,16 +341,19 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From db436ebcdea1b2ac6ed80318f3b0e2b469606e61 Mon Sep 17 00:00:00 2001 From: prombot Date: Wed, 25 May 2022 19:51:00 +0000 Subject: [PATCH 036/228] Update common Prometheus files Signed-off-by: prombot --- CODE_OF_CONDUCT.md | 4 ++-- SECURITY.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 9a1aff412..d325872bd 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,3 @@ -## Prometheus Community Code of Conduct +# Prometheus Community Code of Conduct -Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). +Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). diff --git a/SECURITY.md b/SECURITY.md index 67741f015..fed02d85c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -3,4 +3,4 @@ The Prometheus security policy, including how to report vulnerabilities, can be found here: -https://prometheus.io/docs/operating/security/ + From 9003ac8f0a3046426f7f829fc61dae566a7068de Mon Sep 17 00:00:00 2001 From: "Ryan J. Geyer" Date: Wed, 25 May 2022 14:32:00 -0700 Subject: [PATCH 037/228] Dashboard linting improvements for mixin Signed-off-by: Ryan J. Geyer --- .../dashboards/postgres-overview.json | 140 +++++++----------- 1 file changed, 57 insertions(+), 83 deletions(-) diff --git a/postgres_mixin/dashboards/postgres-overview.json b/postgres_mixin/dashboards/postgres-overview.json index 5bea49262..9bf41be6a 100644 --- a/postgres_mixin/dashboards/postgres-overview.json +++ b/postgres_mixin/dashboards/postgres-overview.json @@ -25,7 +25,7 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "Postgres Overview", + "datasource": "$datasource", "editable": true, "error": false, "fieldConfig": { @@ -77,7 +77,7 @@ { "alias": "fetched", "dsType": "prometheus", - "expr": "sum(irate(pg_stat_database_tup_fetched{datname=~\"$db\",instance=~\"$instance\"}[5m]))", + "expr": "sum(irate(pg_stat_database_tup_fetched{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval]))", "format": "time_series", "groupBy": [ { @@ -131,7 +131,7 @@ { "alias": "fetched", "dsType": "prometheus", - "expr": "sum(irate(pg_stat_database_tup_returned{datname=~\"$db\",instance=~\"$instance\"}[5m]))", + "expr": "sum(irate(pg_stat_database_tup_returned{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval]))", "format": "time_series", "groupBy": [ { @@ -185,7 +185,7 @@ { "alias": "fetched", "dsType": "prometheus", - "expr": "sum(irate(pg_stat_database_tup_inserted{datname=~\"$db\",instance=~\"$instance\"}[5m]))", + "expr": "sum(irate(pg_stat_database_tup_inserted{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval]))", "format": "time_series", "groupBy": [ { @@ -239,7 +239,7 @@ { "alias": "fetched", "dsType": "prometheus", - "expr": "sum(irate(pg_stat_database_tup_updated{datname=~\"$db\",instance=~\"$instance\"}[5m]))", + "expr": "sum(irate(pg_stat_database_tup_updated{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval]))", "format": "time_series", "groupBy": [ { @@ -293,7 +293,7 @@ { "alias": "fetched", "dsType": "prometheus", - "expr": "sum(irate(pg_stat_database_tup_deleted{datname=~\"$db\",instance=~\"$instance\"}[5m]))", + "expr": "sum(irate(pg_stat_database_tup_deleted{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval]))", "format": "time_series", "groupBy": [ { @@ -396,7 +396,7 @@ "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)" ], - "datasource": "Postgres Overview", + "datasource": "$datasource", "decimals": 0, "editable": true, "error": false, @@ -460,7 +460,7 @@ "targets": [ { "dsType": "prometheus", - "expr": "sum(irate(pg_stat_database_xact_commit{datname=~\"$db\",instance=~\"$instance\"}[5m])) + sum(irate(pg_stat_database_xact_rollback{datname=~\"$db\",instance=~\"$instance\"}[5m]))", + "expr": "sum(irate(pg_stat_database_xact_commit{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval])) + sum(irate(pg_stat_database_xact_rollback{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval]))", "format": "time_series", "groupBy": [ { @@ -530,7 +530,7 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "Postgres Overview", + "datasource": "$datasource", "decimals": 1, "editable": true, "error": false, @@ -584,7 +584,7 @@ { "alias": "Buffers Allocated", "dsType": "prometheus", - "expr": "irate(pg_stat_bgwriter_buffers_alloc_total{instance='$instance'}[5m])", + "expr": "irate(pg_stat_bgwriter_buffers_alloc{job=~\"$job\",instance=~\"$instance\"}[$__rate_interval])", "format": "time_series", "groupBy": [ { @@ -636,7 +636,7 @@ { "alias": "Buffers Allocated", "dsType": "prometheus", - "expr": "irate(pg_stat_bgwriter_buffers_backend_fsync_total{instance='$instance'}[5m])", + "expr": "irate(pg_stat_bgwriter_buffers_backend_fsync{job=~\"$job\",instance=~\"$instance\"}[$__rate_interval])", "format": "time_series", "groupBy": [ { @@ -688,7 +688,7 @@ { "alias": "Buffers Allocated", "dsType": "prometheus", - "expr": "irate(pg_stat_bgwriter_buffers_backend_total{instance='$instance'}[5m])", + "expr": "irate(pg_stat_bgwriter_buffers_backend{job=~\"$job\",instance=~\"$instance\"}[$__rate_interval])", "format": "time_series", "groupBy": [ { @@ -740,7 +740,7 @@ { "alias": "Buffers Allocated", "dsType": "prometheus", - "expr": "irate(pg_stat_bgwriter_buffers_clean_total{instance='$instance'}[5m])", + "expr": "irate(pg_stat_bgwriter_buffers_clean{job=~\"$job\",instance=~\"$instance\"}[$__rate_interval])", "format": "time_series", "groupBy": [ { @@ -792,7 +792,7 @@ { "alias": "Buffers Allocated", "dsType": "prometheus", - "expr": "irate(pg_stat_bgwriter_buffers_checkpoint_total{instance='$instance'}[5m])", + "expr": "irate(pg_stat_bgwriter_buffers_checkpoint{job=~\"$job\",instance=~\"$instance\"}[$__rate_interval])", "format": "time_series", "groupBy": [ { @@ -889,7 +889,7 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "Postgres Overview", + "datasource": "$datasource", "editable": true, "error": false, "fieldConfig": { @@ -939,7 +939,7 @@ { "alias": "conflicts", "dsType": "prometheus", - "expr": "sum(rate(pg_stat_database_deadlocks{datname=~\"$db\",instance=~\"$instance\"}[5m]))", + "expr": "sum(rate(pg_stat_database_deadlocks{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval]))", "format": "time_series", "groupBy": [ { @@ -991,7 +991,7 @@ { "alias": "deadlocks", "dsType": "prometheus", - "expr": "sum(rate(pg_stat_database_conflicts{datname=~\"$db\",instance=~\"$instance\"}[5m]))", + "expr": "sum(rate(pg_stat_database_conflicts{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval]))", "format": "time_series", "groupBy": [ { @@ -1088,7 +1088,7 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "Postgres Overview", + "datasource": "$datasource", "editable": true, "error": false, "fieldConfig": { @@ -1136,10 +1136,10 @@ "steppedLine": false, "targets": [ { - "expr": "sum(pg_stat_database_blks_hit{datname=~\"$db\",instance=~\"$instance\"}) / (sum(pg_stat_database_blks_hit{datname=~\"$db\",instance=~\"$instance\"}) + sum(pg_stat_database_blks_read{datname=~\"$db\",instance=~\"$instance\"}))", + "expr": "sum by (datname) (rate(pg_stat_database_blks_hit{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval])) / (sum by (datname)(rate(pg_stat_database_blks_hit{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval])) + sum by (datname)(rate(pg_stat_database_blks_read{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}[$__rate_interval])))", "format": "time_series", "intervalFactor": 2, - "legendFormat": "cache hit rate", + "legendFormat": "{{datname}} - cache hit rate", "refId": "A", "step": 240 } @@ -1191,7 +1191,7 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "Postgres Overview", + "datasource": "$datasource", "editable": true, "error": false, "fieldConfig": { @@ -1239,10 +1239,10 @@ "steppedLine": false, "targets": [ { - "expr": "pg_stat_database_numbackends{datname=~\"$db\",instance=~\"$instance\"}", + "expr": "pg_stat_database_numbackends{datname=~\"$db\",job=~\"$job\",instance=~\"$instance\"}", "format": "time_series", "intervalFactor": 2, - "legendFormat": "{{__name__}}", + "legendFormat": "{{datname}} - {{__name__}}", "refId": "A", "step": 240 } @@ -1299,24 +1299,32 @@ "templating": { "list": [ { - "allValue": ".*", - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": "Postgres Overview", - "definition": "", "hide": 0, - "includeAll": true, - "label": null, + "includeAll": false, + "label": "Data Source", "multi": false, - "name": "instance", + "name": "datasource", "options": [], - "query": "label_values(up{job=~\"postgres.*\"},instance)", + "query": "prometheus", "refresh": 1, "regex": "", "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": ".+", + "datasource": "$datasource", + "definition": "label_values(pg_up, job)", + "hide": 0, + "includeAll": true, + "label": "job", + "multi": true, + "name": "job", + "options": [], + "query": "label_values(pg_up, job)", + "refresh": 0, + "regex": "", + "skipUrlSync": false, "sort": 0, "tagValuesQuery": "", "tags": [], @@ -1325,21 +1333,16 @@ "useTags": false }, { - "allValue": ".*", - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": "Postgres Overview", - "definition": "label_values(pg_stat_database_tup_fetched{instance=~\"$instance\",datname!~\"template.*|postgres\"},datname)", + "allValue": ".+", + "datasource": "$datasource", + "definition": "", "hide": 0, "includeAll": true, - "label": "db", - "multi": false, - "name": "db", + "label": "instance", + "multi": true, + "name": "instance", "options": [], - "query": "label_values(pg_stat_database_tup_fetched{instance=~\"$instance\",datname!~\"template.*|postgres\"},datname)", + "query": "label_values(up{job=~\"$job\"},instance)", "refresh": 1, "regex": "", "skipUrlSync": false, @@ -1351,48 +1354,19 @@ "useTags": false }, { - "current": { - "selected": false, - "text": "Postgres Overview", - "value": "Postgres Overview" - }, + "allValue": ".+", + "datasource": "$datasource", + "definition": "label_values(pg_stat_database_tup_fetched{instance=~\"$instance\",datname!~\"template.*|postgres\"},datname)", "hide": 0, - "includeAll": false, - "label": "datasource", + "includeAll": true, + "label": "db", "multi": false, - "name": "datasource", + "name": "db", "options": [], - "query": "prometheus", + "query": "label_values(pg_stat_database_tup_fetched{instance=~\"$instance\",datname!~\"template.*|postgres\"},datname)", "refresh": 1, "regex": "", "skipUrlSync": false, - "type": "datasource" - }, - { - "allValue": null, - "current": { - "selected": true, - "text": "postgres", - "value": "postgres" - }, - "datasource": "$datasource", - "definition": "label_values(pg_up, job)", - "hide": 0, - "includeAll": false, - "label": "job", - "multi": false, - "name": "job", - "options": [ - { - "selected": true, - "text": "postgres", - "value": "postgres" - } - ], - "query": "label_values(pg_up, job)", - "refresh": 0, - "regex": "", - "skipUrlSync": false, "sort": 0, "tagValuesQuery": "", "tags": [], From 9d67be63088d30bb2b1fb55895c13a93a214568e Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Tue, 14 Jun 2022 00:33:08 +0200 Subject: [PATCH 038/228] Update common Prometheus files (#650) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 136d7d4b9..6034bcbf8 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -25,6 +25,6 @@ jobs: run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@v3.1.0 + uses: golangci/golangci-lint-action@v3.2.0 with: version: v1.45.2 From 73cda17d556b9191994f95ce9a9b8a354799c63b Mon Sep 17 00:00:00 2001 From: prombot Date: Tue, 14 Jun 2022 19:51:35 +0000 Subject: [PATCH 039/228] Update common Prometheus files Signed-off-by: prombot --- Makefile.common | 75 ++++++++----------------------------------------- 1 file changed, 11 insertions(+), 64 deletions(-) diff --git a/Makefile.common b/Makefile.common index c263b733f..6c8e3e219 100644 --- a/Makefile.common +++ b/Makefile.common @@ -36,29 +36,6 @@ GO_VERSION ?= $(shell $(GO) version) GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') -GOVENDOR := -GO111MODULE := -ifeq (, $(PRE_GO_111)) - ifneq (,$(wildcard go.mod)) - # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). - GO111MODULE := on - - ifneq (,$(wildcard vendor)) - # Always use the local vendor/ directory to satisfy the dependencies. - GOOPTS := $(GOOPTS) -mod=vendor - endif - endif -else - ifneq (,$(wildcard go.mod)) - ifneq (,$(wildcard vendor)) -$(warning This repository requires Go >= 1.11 because of Go modules) -$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)') - endif - else - # This repository isn't using Go modules (yet). - GOVENDOR := $(FIRST_GOPATH)/bin/govendor - endif -endif PROMU := $(FIRST_GOPATH)/bin/promu pkgs = ./... @@ -150,11 +127,7 @@ common-check_license: .PHONY: common-deps common-deps: @echo ">> getting dependencies" -ifdef GO111MODULE - GO111MODULE=$(GO111MODULE) $(GO) mod download -else - $(GO) get $(GOOPTS) -t ./... -endif + $(GO) mod download .PHONY: update-go-deps update-go-deps: @@ -162,20 +135,17 @@ update-go-deps: @for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ $(GO) get -d $$m; \ done - GO111MODULE=$(GO111MODULE) $(GO) mod tidy -ifneq (,$(wildcard vendor)) - GO111MODULE=$(GO111MODULE) $(GO) mod vendor -endif + $(GO) mod tidy .PHONY: common-test-short common-test-short: $(GOTEST_DIR) @echo ">> running short tests" - GO111MODULE=$(GO111MODULE) $(GOTEST) -short $(GOOPTS) $(pkgs) + $(GOTEST) -short $(GOOPTS) $(pkgs) .PHONY: common-test common-test: $(GOTEST_DIR) @echo ">> running all tests" - GO111MODULE=$(GO111MODULE) $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs) + $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs) $(GOTEST_DIR): @mkdir -p $@ @@ -183,25 +153,21 @@ $(GOTEST_DIR): .PHONY: common-format common-format: @echo ">> formatting code" - GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs) + $(GO) fmt $(pkgs) .PHONY: common-vet common-vet: @echo ">> vetting code" - GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) + $(GO) vet $(GOOPTS) $(pkgs) .PHONY: common-lint common-lint: $(GOLANGCI_LINT) ifdef GOLANGCI_LINT @echo ">> running golangci-lint" -ifdef GO111MODULE # 'go list' needs to be executed before staticcheck to prepopulate the modules cache. # Otherwise staticcheck might fail randomly for some reason not yet explained. - GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null - GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) -else - $(GOLANGCI_LINT) run $(pkgs) -endif + $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null + $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) endif .PHONY: common-yamllint @@ -218,28 +184,15 @@ endif common-staticcheck: lint .PHONY: common-unused -common-unused: $(GOVENDOR) -ifdef GOVENDOR - @echo ">> running check for unused packages" - @$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages' -else -ifdef GO111MODULE +common-unused: @echo ">> running check for unused/missing packages in go.mod" - GO111MODULE=$(GO111MODULE) $(GO) mod tidy -ifeq (,$(wildcard vendor)) + $(GO) mod tidy @git diff --exit-code -- go.sum go.mod -else - @echo ">> running check for unused packages in vendor/" - GO111MODULE=$(GO111MODULE) $(GO) mod vendor - @git diff --exit-code -- go.sum go.mod vendor/ -endif -endif -endif .PHONY: common-build common-build: promu @echo ">> building binaries" - GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES) + $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES) .PHONY: common-tarball common-tarball: promu @@ -295,12 +248,6 @@ $(GOLANGCI_LINT): | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION) endif -ifdef GOVENDOR -.PHONY: $(GOVENDOR) -$(GOVENDOR): - GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor -endif - .PHONY: precheck precheck:: From d80081e638d4d760fe8cecd5feef0f46e2d09fad Mon Sep 17 00:00:00 2001 From: Austin Godber Date: Wed, 15 Jun 2022 14:17:55 -0700 Subject: [PATCH 040/228] Update readme to include Postgres 14 support It looks like postgres 14.1 was added to CI here: https://github.com/prometheus-community/postgres_exporter/commit/fcb2535affa0f97c7a11439c19de6a7ff793e0df See also: https://github.com/prometheus-community/postgres_exporter/issues/651#issuecomment-1156947591 Signed-off-by: Austin Godber --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb7c90d46..4d23603a6 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Prometheus exporter for PostgreSQL server metrics. -CI Tested PostgreSQL versions: `9.4`, `9.5`, `9.6`, `10`, `11`, `12`, `13` +CI Tested PostgreSQL versions: `9.4`, `9.5`, `9.6`, `10`, `11`, `12`, `13`, `14` ## Quick Start This package is available for Docker: From a167b9165406f9411b845b731c9a142d4267e648 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 17:06:17 +0000 Subject: [PATCH 041/228] Bump github.com/prometheus/common from 0.34.0 to 0.35.0 Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.34.0 to 0.35.0. - [Release notes](https://github.com/prometheus/common/releases) - [Commits](https://github.com/prometheus/common/compare/v0.34.0...v0.35.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c2505f7fe..f27c896ba 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/lib/pq v1.10.6 github.com/prometheus/client_golang v1.12.2 github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.34.0 + github.com/prometheus/common v0.35.0 github.com/prometheus/exporter-toolkit v0.7.1 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c diff --git a/go.sum b/go.sum index 8bc754b16..3f9003a23 100644 --- a/go.sum +++ b/go.sum @@ -189,8 +189,8 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.34.0 h1:RBmGO9d/FVjqHT0yUGQwBJhkwKV+wPCn7KGpvfab0uE= -github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= +github.com/prometheus/common v0.35.0 h1:Eyr+Pw2VymWejHqCugNaQXkAi6KayVNxaHeu6khmFBE= +github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/exporter-toolkit v0.7.1 h1:c6RXaK8xBVercEeUQ4tRNL8UGWzDHfvj9dseo1FcK1Y= github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= From da63601f5718aa61c55c890601dd42513ee8eadd Mon Sep 17 00:00:00 2001 From: SuperQ Date: Thu, 28 Jul 2022 13:42:32 +0200 Subject: [PATCH 042/228] Release v0.11.0 NOTE: pg_stat_bgwriter counter metrics had the `_total` suffix added #556 * [CHANGE] refactor pg_stat_bgwriter metrics into standalone collector #556 * [FEATURE] Add pg_database collector #613 * [ENHANCEMENT] Add pg_database_size_bytes metric #613 * [BUGFIX] Avoid parsing error from bogus Azure Flexible Server custom GUC #587 * [BUGFIX] Fix pg_stat_archiver error in 9.4 and earlier. #599 * [BUGFIX] Sanitize setting values because of Aurora irregularity #620 Signed-off-by: SuperQ --- .circleci/config.yml | 18 +++++++++++++++--- CHANGELOG.md | 10 +++++++++- VERSION | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index db3cad4e5..ae168f04e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -63,16 +63,28 @@ workflows: - cimg/postgres:14.1 - prometheus/build: name: build + parallelism: 3 + promu_opts: "-p linux/amd64 -p windows/amd64 -p linux/arm64 -p darwin/amd64 -p darwin/arm64 -p linux/386" filters: tags: - only: /.*/ + ignore: /^v.*/ + branches: + ignore: /^(main|master|release-.*|.*build-all.*)$/ + - prometheus/build: + name: build_all + parallelism: 12 + filters: + branches: + only: /^(main|master|release-.*|.*build-all.*)$/ + tags: + only: /^v.*/ - prometheus/publish_master: context: org-context docker_hub_organization: prometheuscommunity quay_io_organization: prometheuscommunity requires: - test - - build + - build_all filters: branches: only: master @@ -82,7 +94,7 @@ workflows: quay_io_organization: prometheuscommunity requires: - test - - build + - build_all filters: tags: only: /^v.*/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 0572bf5dc..a8f7b92f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,15 @@ ## master / unreleased -* [CHANGE] pg_stat_bgwriter counter metrics had the `_total` suffix added #556 +## 0.11.0 / 2022-07-28 + +NOTE: pg_stat_bgwriter counter metrics had the `_total` suffix added #556 + +* [CHANGE] refactor pg_stat_bgwriter metrics into standalone collector #556 +* [FEATURE] Add pg_database collector #613 * [ENHANCEMENT] Add pg_database_size_bytes metric #613 +* [BUGFIX] Avoid parsing error from bogus Azure Flexible Server custom GUC #587 +* [BUGFIX] Fix pg_stat_archiver error in 9.4 and earlier. #599 +* [BUGFIX] Sanitize setting values because of Aurora irregularity #620 ## 0.10.1 / 2022-01-14 diff --git a/VERSION b/VERSION index 571215736..d9df1bbc0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.10.1 +0.11.0 From 713461df9847bd50d47b0df2b5a4f1f01206bdb8 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Fri, 25 Feb 2022 11:45:15 -0500 Subject: [PATCH 043/228] WIP: Add prelim multi-target support - Remove multi server support from new collector package - Add http handler for multi-target support Signed-off-by: Joe Adams --- cmd/postgres_exporter/datasource.go | 6 ++ cmd/postgres_exporter/main.go | 25 ++++--- cmd/postgres_exporter/probe.go | 91 +++++++++++++++++++++++++ collector/collector.go | 42 +++++------- collector/pg_database.go | 11 ++- collector/pg_stat_bgwriter.go | 43 ++++-------- collector/probe.go | 90 +++++++++++++++++++++++++ collector/server.go | 100 ---------------------------- 8 files changed, 238 insertions(+), 170 deletions(-) create mode 100644 cmd/postgres_exporter/probe.go create mode 100644 collector/probe.go delete mode 100644 collector/server.go diff --git a/cmd/postgres_exporter/datasource.go b/cmd/postgres_exporter/datasource.go index 90d797b63..716138f32 100644 --- a/cmd/postgres_exporter/datasource.go +++ b/cmd/postgres_exporter/datasource.go @@ -162,6 +162,12 @@ func getDataSources() ([]string, error) { uri = os.Getenv("DATA_SOURCE_URI") } + // No datasources found. This allows us to support the multi-target pattern + // withouth an explicit datasource. + if uri == "" { + return []string{}, nil + } + dsn = "postgresql://" + ui + "@" + uri return []string{dsn}, nil diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 35db723a2..2ec1bf269 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -85,16 +85,17 @@ func main() { return } - dsn, err := getDataSources() + dsns, err := getDataSources() if err != nil { level.Error(logger).Log("msg", "Failed reading data sources", "err", err.Error()) os.Exit(1) } - if len(dsn) == 0 { - level.Error(logger).Log("msg", "Couldn't find environment variables describing the datasource to use") - os.Exit(1) - } + // TODO(@sysadmind): Remove this with multi-target support + // if len(dsn) == 0 { + // level.Error(logger).Log("msg", "Couldn't find environment variables describing the datasource to use") + // os.Exit(1) + // } opts := []ExporterOpt{ DisableDefaultMetrics(*disableDefaultMetrics), @@ -106,7 +107,7 @@ func main() { IncludeDatabases(*includeDatabases), } - exporter := NewExporter(dsn, opts...) + exporter := NewExporter(dsns, opts...) defer func() { exporter.servers.Close() }() @@ -115,6 +116,12 @@ func main() { prometheus.MustRegister(exporter) + // TODO(@sysadmind): Remove this with multi-target support. We are removing multiple DSN support + dsn := "" + if len(dsns) > 0 { + dsn = dsns[0] + } + pe, err := collector.NewPostgresCollector( logger, dsn, @@ -122,9 +129,9 @@ func main() { ) if err != nil { level.Error(logger).Log("msg", "Failed to create PostgresCollector", "err", err.Error()) - os.Exit(1) + } else { + prometheus.MustRegister(pe) } - prometheus.MustRegister(pe) http.Handle(*metricPath, promhttp.Handler()) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { @@ -132,6 +139,8 @@ func main() { w.Write(landingPage) // nolint: errcheck }) + http.HandleFunc("/probe", handleProbe(logger)) + level.Info(logger).Log("msg", "Listening on address", "address", *listenAddress) srv := &http.Server{Addr: *listenAddress} if err := web.ListenAndServe(srv, *webConfig, logger); err != nil { diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go new file mode 100644 index 000000000..c23777b45 --- /dev/null +++ b/cmd/postgres_exporter/probe.go @@ -0,0 +1,91 @@ +// Copyright 2022 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 main + +import ( + "net/http" + "time" + + "github.com/go-kit/log" + "github.com/prometheus-community/postgres_exporter/collector" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +func handleProbe(logger log.Logger) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + params := r.URL.Query() + target := params.Get("target") + if target == "" { + http.Error(w, "target is required", http.StatusBadRequest) + return + } + + // TODO: Timeout + // TODO: Auth Module + + probeSuccessGauge := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "probe_success", + Help: "Displays whether or not the probe was a success", + }) + probeDurationGauge := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "probe_duration_seconds", + Help: "Returns how long the probe took to complete in seconds", + }) + + tl := log.With(logger, "target", target) + _ = tl + + start := time.Now() + registry := prometheus.NewRegistry() + registry.MustRegister(probeSuccessGauge) + registry.MustRegister(probeDurationGauge) + + // TODO(@sysadmind): this is a temp hack until we have a proper auth module + target = "postgres://postgres:test@localhost:5432/circle_test?sslmode=disable" + + // Run the probe + pc, err := collector.NewProbeCollector(tl, registry, target) + if err != nil { + probeSuccessGauge.Set(0) + probeDurationGauge.Set(time.Since(start).Seconds()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + _ = ctx + + // TODO: Which way should this be? Register or handle the collection manually? + // Also, what about the context? + + // Option 1: Register the collector + registry.MustRegister(pc) + + // Option 2: Handle the collection manually. This allows us to collect duration metrics. + // The collectors themselves already support their own duration metrics. + // err = pc.Update(ctx) + // if err != nil { + // probeSuccessGauge.Set(0) + // } else { + // probeSuccessGauge.Set(1) + // } + + duration := time.Since(start).Seconds() + probeDurationGauge.Set(duration) + + // TODO check success, etc + h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{}) + h.ServeHTTP(w, r) + } +} diff --git a/collector/collector.go b/collector/collector.go index 58765b659..6d1a4dd11 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -15,6 +15,7 @@ package collector import ( "context" + "database/sql" "errors" "fmt" "sync" @@ -58,7 +59,7 @@ var ( ) type Collector interface { - Update(ctx context.Context, server *server, ch chan<- prometheus.Metric) error + Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error } func registerCollector(name string, isDefaultEnabled bool, createFunc func(logger log.Logger) (Collector, error)) { @@ -86,13 +87,13 @@ type PostgresCollector struct { Collectors map[string]Collector logger log.Logger - servers map[string]*server + db *sql.DB } type Option func(*PostgresCollector) error // NewPostgresCollector creates a new PostgresCollector. -func NewPostgresCollector(logger log.Logger, dsns []string, filters []string, options ...Option) (*PostgresCollector, error) { +func NewPostgresCollector(logger log.Logger, dsn string, filters []string, options ...Option) (*PostgresCollector, error) { p := &PostgresCollector{ logger: logger, } @@ -136,17 +137,18 @@ func NewPostgresCollector(logger log.Logger, dsns []string, filters []string, op p.Collectors = collectors - servers := make(map[string]*server) - for _, dsn := range dsns { - s, err := makeServer(dsn) - if err != nil { - return nil, err - } + if dsn == "" { + return nil, errors.New("empty dsn") + } - servers[dsn] = s + db, err := sql.Open("postgres", dsn) + if err != nil { + return nil, err } + db.SetMaxOpenConns(1) + db.SetMaxIdleConns(1) - p.servers = servers + p.db = db return p, nil } @@ -160,32 +162,20 @@ func (p PostgresCollector) Describe(ch chan<- *prometheus.Desc) { // Collect implements the prometheus.Collector interface. func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) { ctx := context.TODO() - wg := sync.WaitGroup{} - wg.Add(len(p.servers)) - for _, s := range p.servers { - go func(s *server) { - p.subCollect(ctx, s, ch) - wg.Done() - }(s) - } - wg.Wait() -} - -func (p PostgresCollector) subCollect(ctx context.Context, server *server, ch chan<- prometheus.Metric) { wg := sync.WaitGroup{} wg.Add(len(p.Collectors)) for name, c := range p.Collectors { go func(name string, c Collector) { - execute(ctx, name, c, server, ch, p.logger) + execute(ctx, name, c, p.db, ch, p.logger) wg.Done() }(name, c) } wg.Wait() } -func execute(ctx context.Context, name string, c Collector, s *server, ch chan<- prometheus.Metric, logger log.Logger) { +func execute(ctx context.Context, name string, c Collector, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) { begin := time.Now() - err := c.Update(ctx, s, ch) + err := c.Update(ctx, db, ch) duration := time.Since(begin) var success float64 diff --git a/collector/pg_database.go b/collector/pg_database.go index 5868f66d8..8fa4dab8e 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -15,6 +15,7 @@ package collector import ( "context" + "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" @@ -36,15 +37,11 @@ var pgDatabase = map[string]*prometheus.Desc{ "size_bytes": prometheus.NewDesc( "pg_database_size_bytes", "Disk space used by the database", - []string{"datname", "server"}, nil, + []string{"datname"}, nil, ), } -func (PGDatabaseCollector) Update(ctx context.Context, server *server, ch chan<- prometheus.Metric) error { - db, err := server.GetDB() - if err != nil { - return err - } +func (PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { rows, err := db.QueryContext(ctx, `SELECT pg_database.datname ,pg_database_size(pg_database.datname) @@ -63,7 +60,7 @@ func (PGDatabaseCollector) Update(ctx context.Context, server *server, ch chan<- ch <- prometheus.MustNewConstMetric( pgDatabase["size_bytes"], - prometheus.GaugeValue, float64(size), datname, server.GetName(), + prometheus.GaugeValue, float64(size), datname, ) } if err := rows.Err(); err != nil { diff --git a/collector/pg_stat_bgwriter.go b/collector/pg_stat_bgwriter.go index 7e7d09c72..f897dbe2c 100644 --- a/collector/pg_stat_bgwriter.go +++ b/collector/pg_stat_bgwriter.go @@ -15,6 +15,7 @@ package collector import ( "context" + "database/sql" "time" "github.com/go-kit/log" @@ -38,77 +39,72 @@ var statBGWriter = map[string]*prometheus.Desc{ "checkpoints_timed": prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_timed_total"), "Number of scheduled checkpoints that have been performed", - []string{"server"}, + []string{}, prometheus.Labels{}, ), "checkpoints_req": prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_req_total"), "Number of requested checkpoints that have been performed", - []string{"server"}, + []string{}, prometheus.Labels{}, ), "checkpoint_write_time": prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoint_write_time_total"), "Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in milliseconds", - []string{"server"}, + []string{}, prometheus.Labels{}, ), "checkpoint_sync_time": prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoint_sync_time_total"), "Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in milliseconds", - []string{"server"}, + []string{}, prometheus.Labels{}, ), "buffers_checkpoint": prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_checkpoint_total"), "Number of buffers written during checkpoints", - []string{"server"}, + []string{}, prometheus.Labels{}, ), "buffers_clean": prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_clean_total"), "Number of buffers written by the background writer", - []string{"server"}, + []string{}, prometheus.Labels{}, ), "maxwritten_clean": prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "maxwritten_clean_total"), "Number of times the background writer stopped a cleaning scan because it had written too many buffers", - []string{"server"}, + []string{}, prometheus.Labels{}, ), "buffers_backend": prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_backend_total"), "Number of buffers written directly by a backend", - []string{"server"}, + []string{}, prometheus.Labels{}, ), "buffers_backend_fsync": prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_backend_fsync_total"), "Number of times a backend had to execute its own fsync call (normally the background writer handles those even when the backend does its own write)", - []string{"server"}, + []string{}, prometheus.Labels{}, ), "buffers_alloc": prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_alloc_total"), "Number of buffers allocated", - []string{"server"}, + []string{}, prometheus.Labels{}, ), "stats_reset": prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "stats_reset_total"), "Time at which these statistics were last reset", - []string{"server"}, + []string{}, prometheus.Labels{}, ), } -func (PGStatBGWriterCollector) Update(ctx context.Context, server *server, ch chan<- prometheus.Metric) error { - db, err := server.GetDB() - if err != nil { - return err - } - +func (PGStatBGWriterCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { row := db.QueryRowContext(ctx, `SELECT checkpoints_timed @@ -136,7 +132,7 @@ func (PGStatBGWriterCollector) Update(ctx context.Context, server *server, ch ch var ba int var sr time.Time - err = row.Scan(&cpt, &cpr, &cpwt, &cpst, &bcp, &bc, &mwc, &bb, &bbf, &ba, &sr) + err := row.Scan(&cpt, &cpr, &cpwt, &cpst, &bcp, &bc, &mwc, &bb, &bbf, &ba, &sr) if err != nil { return err } @@ -145,67 +141,56 @@ func (PGStatBGWriterCollector) Update(ctx context.Context, server *server, ch ch statBGWriter["checkpoints_timed"], prometheus.CounterValue, float64(cpt), - server.GetName(), ) ch <- prometheus.MustNewConstMetric( statBGWriter["checkpoints_req"], prometheus.CounterValue, float64(cpr), - server.GetName(), ) ch <- prometheus.MustNewConstMetric( statBGWriter["checkpoint_write_time"], prometheus.CounterValue, float64(cpwt), - server.GetName(), ) ch <- prometheus.MustNewConstMetric( statBGWriter["checkpoint_sync_time"], prometheus.CounterValue, float64(cpst), - server.GetName(), ) ch <- prometheus.MustNewConstMetric( statBGWriter["buffers_checkpoint"], prometheus.CounterValue, float64(bcp), - server.GetName(), ) ch <- prometheus.MustNewConstMetric( statBGWriter["buffers_clean"], prometheus.CounterValue, float64(bc), - server.GetName(), ) ch <- prometheus.MustNewConstMetric( statBGWriter["maxwritten_clean"], prometheus.CounterValue, float64(mwc), - server.GetName(), ) ch <- prometheus.MustNewConstMetric( statBGWriter["buffers_backend"], prometheus.CounterValue, float64(bb), - server.GetName(), ) ch <- prometheus.MustNewConstMetric( statBGWriter["buffers_backend_fsync"], prometheus.CounterValue, float64(bbf), - server.GetName(), ) ch <- prometheus.MustNewConstMetric( statBGWriter["buffers_alloc"], prometheus.CounterValue, float64(ba), - server.GetName(), ) ch <- prometheus.MustNewConstMetric( statBGWriter["stats_reset"], prometheus.CounterValue, float64(sr.Unix()), - server.GetName(), ) return nil diff --git a/collector/probe.go b/collector/probe.go new file mode 100644 index 000000000..8aa18b92c --- /dev/null +++ b/collector/probe.go @@ -0,0 +1,90 @@ +// Copyright 2022 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 collector + +import ( + "context" + "database/sql" + "fmt" + "strings" + "sync" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +type ProbeCollector struct { + registry *prometheus.Registry + collectors map[string]Collector + logger log.Logger + db *sql.DB +} + +func NewProbeCollector(logger log.Logger, registry *prometheus.Registry, dsn string) (*ProbeCollector, error) { + collectors := make(map[string]Collector) + initiatedCollectorsMtx.Lock() + defer initiatedCollectorsMtx.Unlock() + for key, enabled := range collectorState { + // TODO: Handle filters + // if !*enabled || (len(f) > 0 && !f[key]) { + // continue + // } + if !*enabled { + continue + } + if collector, ok := initiatedCollectors[key]; ok { + collectors[key] = collector + } else { + collector, err := factories[key](log.With(logger, "collector", key)) + if err != nil { + return nil, err + } + collectors[key] = collector + initiatedCollectors[key] = collector + } + } + + if !strings.HasPrefix(dsn, "postgres://") { + dsn = fmt.Sprintf("postgres://%s", dsn) + } + + db, err := sql.Open("postgres", dsn) + if err != nil { + return nil, err + } + db.SetMaxOpenConns(1) + db.SetMaxIdleConns(1) + + return &ProbeCollector{ + registry: registry, + collectors: collectors, + logger: logger, + db: db, + }, nil +} + +func (pc *ProbeCollector) Describe(ch chan<- *prometheus.Desc) { +} + +func (pc *ProbeCollector) Collect(ch chan<- prometheus.Metric) { + wg := sync.WaitGroup{} + wg.Add(len(pc.collectors)) + for name, c := range pc.collectors { + go func(name string, c Collector) { + execute(context.TODO(), name, c, pc.db, ch, pc.logger) + wg.Done() + }(name, c) + } + wg.Wait() +} diff --git a/collector/server.go b/collector/server.go deleted file mode 100644 index fa490a2c6..000000000 --- a/collector/server.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2022 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 collector - -import ( - "database/sql" - "fmt" - "strings" - - "github.com/lib/pq" -) - -type server struct { - dsn string - name string - db *sql.DB -} - -func makeServer(dsn string) (*server, error) { - name, err := parseServerName(dsn) - if err != nil { - return nil, err - } - return &server{ - dsn: dsn, - name: name, - }, nil -} - -func (s *server) GetDB() (*sql.DB, error) { - if s.db != nil { - return s.db, nil - } - - db, err := sql.Open("postgres", s.dsn) - if err != nil { - return nil, err - } - db.SetMaxOpenConns(1) - db.SetMaxIdleConns(1) - - s.db = db - - return s.db, nil -} - -func (s *server) GetName() string { - return s.name -} - -func (s *server) String() string { - return s.name -} - -func parseServerName(url string) (string, error) { - dsn, err := pq.ParseURL(url) - if err != nil { - dsn = url - } - - pairs := strings.Split(dsn, " ") - kv := make(map[string]string, len(pairs)) - for _, pair := range pairs { - splitted := strings.SplitN(pair, "=", 2) - if len(splitted) != 2 { - return "", fmt.Errorf("malformed dsn %q", dsn) - } - // Newer versions of pq.ParseURL quote values so trim them off if they exist - key := strings.Trim(splitted[0], "'\"") - value := strings.Trim(splitted[1], "'\"") - kv[key] = value - } - - var fingerprint string - - if host, ok := kv["host"]; ok { - fingerprint += host - } else { - fingerprint += "localhost" - } - - if port, ok := kv["port"]; ok { - fingerprint += ":" + port - } else { - fingerprint += ":5432" - } - - return fingerprint, nil -} From cc751b7966f66a60512609c7497379d32bc2847b Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Fri, 4 Mar 2022 16:39:48 -0500 Subject: [PATCH 044/228] Add config module The config module supports adding configuration to the exporter via a config file. This supports adding authentication details in a config file so that /probe requests can specify authentication for endpoints Signed-off-by: Joe Adams --- cmd/postgres_exporter/main.go | 11 ++ cmd/postgres_exporter/probe.go | 34 +++++- config/config.go | 126 ++++++++++++++++++++ config/config_test.go | 58 +++++++++ config/testdata/config-bad-auth-module.yaml | 7 ++ config/testdata/config-bad-extra-field.yaml | 8 ++ config/testdata/config-good.yaml | 8 ++ go.mod | 1 + go.sum | 2 + 9 files changed, 249 insertions(+), 6 deletions(-) create mode 100644 config/config.go create mode 100644 config/config_test.go create mode 100644 config/testdata/config-bad-auth-module.yaml create mode 100644 config/testdata/config-bad-extra-field.yaml create mode 100644 config/testdata/config-good.yaml diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 2ec1bf269..aee325039 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -20,6 +20,7 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/postgres_exporter/collector" + "github.com/prometheus-community/postgres_exporter/config" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/promlog" @@ -31,6 +32,11 @@ import ( ) var ( + c = config.ConfigHandler{ + Config: &config.Config{}, + } + + configFile = kingpin.Flag("config.file", "Promehteus exporter configuration file.").Default("postres_exporter.yml").String() listenAddress = kingpin.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9187").Envar("PG_EXPORTER_WEB_LISTEN_ADDRESS").String() webConfig = webflag.AddFlags(kingpin.CommandLine) metricPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").Envar("PG_EXPORTER_WEB_TELEMETRY_PATH").String() @@ -85,6 +91,11 @@ func main() { return } + if err := c.ReloadConfig(*configFile, logger); err != nil { + // This is not fatal, but it means that auth must be provided for every dsn. + level.Error(logger).Log("msg", "Error loading config", "err", err) + } + dsns, err := getDataSources() if err != nil { level.Error(logger).Log("msg", "Failed reading data sources", "err", err.Error()) diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go index c23777b45..813f4ea81 100644 --- a/cmd/postgres_exporter/probe.go +++ b/cmd/postgres_exporter/probe.go @@ -14,11 +14,14 @@ package main import ( + "fmt" "net/http" "time" "github.com/go-kit/log" + "github.com/go-kit/log/level" "github.com/prometheus-community/postgres_exporter/collector" + "github.com/prometheus-community/postgres_exporter/config" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) @@ -26,15 +29,38 @@ import ( func handleProbe(logger log.Logger) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() + conf := c.GetConfig() params := r.URL.Query() target := params.Get("target") if target == "" { http.Error(w, "target is required", http.StatusBadRequest) return } + var authModule config.AuthModule + authModuleName := params.Get("auth_module") + if authModuleName == "" { + level.Info(logger).Log("msg", "no auth_module specified, using default") + } else { + var ok bool + authModule, ok = conf.AuthModules[authModuleName] + if !ok { + http.Error(w, fmt.Sprintf("auth_module %s not found", authModuleName), http.StatusBadRequest) + return + } + if authModule.UserPass.Username == "" || authModule.UserPass.Password == "" { + http.Error(w, fmt.Sprintf("auth_module %s has no username or password", authModuleName), http.StatusBadRequest) + return + } + } + + dsn, err := authModule.ConfigureTarget(target) + if err != nil { + level.Error(logger).Log("msg", "failed to configure target", "err", err) + http.Error(w, fmt.Sprintf("could not configure dsn for target: %v", err), http.StatusBadRequest) + return + } // TODO: Timeout - // TODO: Auth Module probeSuccessGauge := prometheus.NewGauge(prometheus.GaugeOpts{ Name: "probe_success", @@ -46,18 +72,14 @@ func handleProbe(logger log.Logger) http.HandlerFunc { }) tl := log.With(logger, "target", target) - _ = tl start := time.Now() registry := prometheus.NewRegistry() registry.MustRegister(probeSuccessGauge) registry.MustRegister(probeDurationGauge) - // TODO(@sysadmind): this is a temp hack until we have a proper auth module - target = "postgres://postgres:test@localhost:5432/circle_test?sslmode=disable" - // Run the probe - pc, err := collector.NewProbeCollector(tl, registry, target) + pc, err := collector.NewProbeCollector(tl, registry, dsn) if err != nil { probeSuccessGauge.Set(0) probeDurationGauge.Set(time.Since(start).Seconds()) diff --git a/config/config.go b/config/config.go new file mode 100644 index 000000000..49a2dbd63 --- /dev/null +++ b/config/config.go @@ -0,0 +1,126 @@ +// Copyright 2022 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 config + +import ( + "fmt" + "net/url" + "os" + "strings" + "sync" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" + "gopkg.in/yaml.v3" +) + +var ( + configReloadSuccess = prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "postgres_exporter", + Name: "config_last_reload_successful", + Help: "Postgres exporter config loaded successfully.", + }) + + configReloadSeconds = prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "postgres_exporter", + Name: "config_last_reload_success_timestamp_seconds", + Help: "Timestamp of the last successful configuration reload.", + }) +) + +func init() { + prometheus.MustRegister(configReloadSuccess) + prometheus.MustRegister(configReloadSeconds) +} + +type Config struct { + AuthModules map[string]AuthModule `yaml:"auth_modules"` +} + +type AuthModule struct { + Type string `yaml:"type"` + UserPass UserPass `yaml:"userpass,omitempty"` + // Add alternative auth modules here + Options map[string]string `yaml:"options"` +} + +type UserPass struct { + Username string `yaml:"username"` + Password string `yaml:"password"` +} + +type ConfigHandler struct { + sync.RWMutex + Config *Config +} + +func (ch *ConfigHandler) GetConfig() *Config { + ch.RLock() + defer ch.RUnlock() + return ch.Config +} + +func (ch *ConfigHandler) ReloadConfig(f string, logger log.Logger) error { + config := &Config{} + var err error + defer func() { + if err != nil { + configReloadSuccess.Set(0) + } else { + configReloadSuccess.Set(1) + configReloadSeconds.SetToCurrentTime() + } + }() + + yamlReader, err := os.Open(f) + if err != nil { + return fmt.Errorf("Error opening config file %q: %s", f, err) + } + defer yamlReader.Close() + decoder := yaml.NewDecoder(yamlReader) + decoder.KnownFields(true) + + if err = decoder.Decode(config); err != nil { + return fmt.Errorf("Error parsing config file %q: %s", f, err) + } + + ch.Lock() + ch.Config = config + ch.Unlock() + return nil +} + +func (m AuthModule) ConfigureTarget(target string) (string, error) { + // ip:port urls do not parse properly and that is the typical way users interact with postgres + t := fmt.Sprintf("exporter://%s", target) + u, err := url.Parse(t) + if err != nil { + return "", err + } + + if m.Type == "userpass" { + u.User = url.UserPassword(m.UserPass.Username, m.UserPass.Password) + } + + query := u.Query() + for k, v := range m.Options { + query.Set(k, v) + } + u.RawQuery = query.Encode() + + parsed := u.String() + trim := strings.TrimPrefix(parsed, "exporter://") + + return trim, nil +} diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 000000000..63b932adb --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,58 @@ +// Copyright 2022 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 config + +import ( + "testing" +) + +func TestLoadConfig(t *testing.T) { + ch := &ConfigHandler{ + Config: &Config{}, + } + + err := ch.ReloadConfig("testdata/config-good.yaml", nil) + if err != nil { + t.Errorf("Error loading config: %s", err) + } +} + +func TestLoadBadConfigs(t *testing.T) { + ch := &ConfigHandler{ + Config: &Config{}, + } + + tests := []struct { + input string + want string + }{ + { + input: "testdata/config-bad-auth-module.yaml", + want: "Error parsing config file \"testdata/config-bad-auth-module.yaml\": yaml: unmarshal errors:\n line 3: field pretendauth not found in type config.AuthModule", + }, + { + input: "testdata/config-bad-extra-field.yaml", + want: "Error parsing config file \"testdata/config-bad-extra-field.yaml\": yaml: unmarshal errors:\n line 8: field doesNotExist not found in type config.AuthModule", + }, + } + + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + got := ch.ReloadConfig(test.input, nil) + if got == nil || got.Error() != test.want { + t.Fatalf("ReloadConfig(%q) = %v, want %s", test.input, got, test.want) + } + }) + } +} diff --git a/config/testdata/config-bad-auth-module.yaml b/config/testdata/config-bad-auth-module.yaml new file mode 100644 index 000000000..8f718dd5a --- /dev/null +++ b/config/testdata/config-bad-auth-module.yaml @@ -0,0 +1,7 @@ +auth_modules: + foo: + pretendauth: + username: test + password: pass + options: + extra: "1" diff --git a/config/testdata/config-bad-extra-field.yaml b/config/testdata/config-bad-extra-field.yaml new file mode 100644 index 000000000..f6ff6d6cf --- /dev/null +++ b/config/testdata/config-bad-extra-field.yaml @@ -0,0 +1,8 @@ +auth_modules: + foo: + userpass: + username: test + password: pass + options: + extra: "1" + doesNotExist: test diff --git a/config/testdata/config-good.yaml b/config/testdata/config-good.yaml new file mode 100644 index 000000000..13453e26f --- /dev/null +++ b/config/testdata/config-good.yaml @@ -0,0 +1,8 @@ +auth_modules: + first: + type: userpass + userpass: + username: first + password: firstpass + options: + sslmode: disable diff --git a/go.mod b/go.mod index f27c896ba..f2ccd64e3 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) require ( diff --git a/go.sum b/go.sum index 3f9003a23..1ad1ca5b1 100644 --- a/go.sum +++ b/go.sum @@ -494,6 +494,8 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 8f8d2208f593056b0f159466625b42d2c8a956c9 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Tue, 28 Jun 2022 22:22:14 -0400 Subject: [PATCH 045/228] cleanup and README Signed-off-by: Joe Adams Co-authored-by: Ben Kochie --- README.md | 30 ++++++++++++++++++++++++++++++ cmd/postgres_exporter/main.go | 6 ------ cmd/postgres_exporter/probe.go | 20 ++++++-------------- config/config.go | 10 +++------- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 4d23603a6..2f50fba07 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,36 @@ docker run \ quay.io/prometheuscommunity/postgres-exporter ``` +## Multi-Target Support (BETA) +**This Feature is in beta and may require changes in future releases. Feedback is welcome.** + +This exporter supports the [multi-target pattern](https://prometheus.io/docs/guides/multi-target-exporter/). This allows running a single instance of this exporter for multiple postgres targets. Using the milti-target funcationality of this exporter is **optional** and meant for users where it is impossible to install the exporter as a sidecar. For example SaaS-managed services. + +To use the multi-target functionality, send an http request to the endpoint `/probe?target=foo:5432` where target is set to the DSN of the postgres instance to scrape metrics from. + +To avoid putting sensitive information like username and password in the URL, preconfigured auth modules are supported via the [auth_modules](#auth_modules) section of the config file. auth_modules for DSNs can be used with the `/probe` endpoint by specifying the `?auth_module=foo` http parameter. + +## Configuration File + +The configuration file controls the behavior of the exporter. It can be set using the `--config.file` command line flag and defaults to `postres_exporter.yml`. + +### auth_modules +This section defines preset authentication and connection parameters for use in the [multi-target endpoint](#multi-target-support-beta). `auth_modules` is a map of modules with the key being the identifier which can be used in the `/probe` endpoint. +Currently only the `userpass` type is supported. + +Example: +```yaml +auth_modules: + foo1: # Set this to any name you want + type: userpass + userpass: + username: first + password: firstpass + options: + # options become key=value parameters of the DSN + sslmode: disable +``` + ## Building and running git clone https://github.com/prometheus-community/postgres_exporter.git diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index aee325039..d8f612956 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -102,12 +102,6 @@ func main() { os.Exit(1) } - // TODO(@sysadmind): Remove this with multi-target support - // if len(dsn) == 0 { - // level.Error(logger).Log("msg", "Couldn't find environment variables describing the datasource to use") - // os.Exit(1) - // } - opts := []ExporterOpt{ DisableDefaultMetrics(*disableDefaultMetrics), DisableSettingsMetrics(*disableSettingsMetrics), diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go index 813f4ea81..7b2154319 100644 --- a/cmd/postgres_exporter/probe.go +++ b/cmd/postgres_exporter/probe.go @@ -60,7 +60,7 @@ func handleProbe(logger log.Logger) http.HandlerFunc { return } - // TODO: Timeout + // TODO(@sysadmind): Timeout probeSuccessGauge := prometheus.NewGauge(prometheus.GaugeOpts{ Name: "probe_success", @@ -86,23 +86,15 @@ func handleProbe(logger log.Logger) http.HandlerFunc { http.Error(w, err.Error(), http.StatusInternalServerError) return } - _ = ctx - // TODO: Which way should this be? Register or handle the collection manually? - // Also, what about the context? + // TODO(@sysadmind): Remove the registry.MustRegister() call below and instead handle the collection here. That will allow + // for the passing of context, handling of timeouts, and more control over the collection. + // The current NewProbeCollector() implementation relies on the MustNewConstMetric() call to create the metrics which is not + // ideal to use without the registry.MustRegister() call. + _ = ctx - // Option 1: Register the collector registry.MustRegister(pc) - // Option 2: Handle the collection manually. This allows us to collect duration metrics. - // The collectors themselves already support their own duration metrics. - // err = pc.Update(ctx) - // if err != nil { - // probeSuccessGauge.Set(0) - // } else { - // probeSuccessGauge.Set(1) - // } - duration := time.Since(start).Seconds() probeDurationGauge.Set(duration) diff --git a/config/config.go b/config/config.go index 49a2dbd63..10e7b7337 100644 --- a/config/config.go +++ b/config/config.go @@ -22,28 +22,24 @@ import ( "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" "gopkg.in/yaml.v3" ) var ( - configReloadSuccess = prometheus.NewGauge(prometheus.GaugeOpts{ + configReloadSuccess = promauto.NewGauge(prometheus.GaugeOpts{ Namespace: "postgres_exporter", Name: "config_last_reload_successful", Help: "Postgres exporter config loaded successfully.", }) - configReloadSeconds = prometheus.NewGauge(prometheus.GaugeOpts{ + configReloadSeconds = promauto.NewGauge(prometheus.GaugeOpts{ Namespace: "postgres_exporter", Name: "config_last_reload_success_timestamp_seconds", Help: "Timestamp of the last successful configuration reload.", }) ) -func init() { - prometheus.MustRegister(configReloadSuccess) - prometheus.MustRegister(configReloadSeconds) -} - type Config struct { AuthModules map[string]AuthModule `yaml:"auth_modules"` } From 72430f8d2a7e541526a45a275b6615adabbdef48 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Thu, 28 Jul 2022 10:13:47 -0400 Subject: [PATCH 046/228] Update cmd/postgres_exporter/main.go Signed-off-by: Joe Adams --- README.md | 2 +- cmd/postgres_exporter/main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2f50fba07..c7cb46212 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ To avoid putting sensitive information like username and password in the URL, pr ## Configuration File -The configuration file controls the behavior of the exporter. It can be set using the `--config.file` command line flag and defaults to `postres_exporter.yml`. +The configuration file controls the behavior of the exporter. It can be set using the `--config.file` command line flag and defaults to `postgres_exporter.yml`. ### auth_modules This section defines preset authentication and connection parameters for use in the [multi-target endpoint](#multi-target-support-beta). `auth_modules` is a map of modules with the key being the identifier which can be used in the `/probe` endpoint. diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index d8f612956..8759f4372 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -36,7 +36,7 @@ var ( Config: &config.Config{}, } - configFile = kingpin.Flag("config.file", "Promehteus exporter configuration file.").Default("postres_exporter.yml").String() + configFile = kingpin.Flag("config.file", "Postgres exporter configuration file.").Default("postgres_exporter.yml").String() listenAddress = kingpin.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9187").Envar("PG_EXPORTER_WEB_LISTEN_ADDRESS").String() webConfig = webflag.AddFlags(kingpin.CommandLine) metricPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").Envar("PG_EXPORTER_WEB_TELEMETRY_PATH").String() From a627e7fce7027dbfe13b587ede66ccaad6e1f6ba Mon Sep 17 00:00:00 2001 From: bravosierrasierra Date: Fri, 29 Jul 2022 13:33:23 +0300 Subject: [PATCH 047/228] fix for exporter issue 633 fix for exporter issue 633: https://github.com/prometheus-community/postgres_exporter/issues/633 "Scan error on column index 2, name \"checkpoint_write_time\": converting driver.Value type float64 (\"6.594096e+06\") to a int: invalid syntax #633" Signed-off-by: bravosierrasierra --- collector/pg_stat_bgwriter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collector/pg_stat_bgwriter.go b/collector/pg_stat_bgwriter.go index f897dbe2c..482b74e98 100644 --- a/collector/pg_stat_bgwriter.go +++ b/collector/pg_stat_bgwriter.go @@ -122,7 +122,7 @@ func (PGStatBGWriterCollector) Update(ctx context.Context, db *sql.DB, ch chan<- var cpt int var cpr int - var cpwt int + var cpwt float64 var cpst int var bcp int var bc int From 8855b7a604256e019b47fab2a170bb94a0784eb6 Mon Sep 17 00:00:00 2001 From: Nicolas Rodriguez Date: Sat, 30 Jul 2022 01:54:49 +0200 Subject: [PATCH 048/228] Fix checkpoint_sync_time value type Error: sql: Scan error on column index 3, name \"checkpoint_sync_time\": converting driver.Value type float64 (\"1.876469e+06\") to a int: invalid syntax See also: https://github.com/prometheus-community/postgres_exporter/issues/633 https://github.com/prometheus-community/postgres_exporter/pull/666 Signed-off-by: Nicolas Rodriguez --- collector/pg_stat_bgwriter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collector/pg_stat_bgwriter.go b/collector/pg_stat_bgwriter.go index 482b74e98..69c75653f 100644 --- a/collector/pg_stat_bgwriter.go +++ b/collector/pg_stat_bgwriter.go @@ -123,7 +123,7 @@ func (PGStatBGWriterCollector) Update(ctx context.Context, db *sql.DB, ch chan<- var cpt int var cpr int var cpwt float64 - var cpst int + var cpst float64 var bcp int var bc int var mwc int From 926b8659a0c2b9a540c998965cdedcfc785a1eb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 17:07:11 +0000 Subject: [PATCH 049/228] Bump github.com/prometheus/common from 0.35.0 to 0.37.0 Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.35.0 to 0.37.0. - [Release notes](https://github.com/prometheus/common/releases) - [Commits](https://github.com/prometheus/common/compare/v0.35.0...v0.37.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f2ccd64e3..08fad017a 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/lib/pq v1.10.6 github.com/prometheus/client_golang v1.12.2 github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.35.0 + github.com/prometheus/common v0.37.0 github.com/prometheus/exporter-toolkit v0.7.1 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c diff --git a/go.sum b/go.sum index 1ad1ca5b1..8532a8c2b 100644 --- a/go.sum +++ b/go.sum @@ -189,8 +189,8 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.35.0 h1:Eyr+Pw2VymWejHqCugNaQXkAi6KayVNxaHeu6khmFBE= -github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/exporter-toolkit v0.7.1 h1:c6RXaK8xBVercEeUQ4tRNL8UGWzDHfvj9dseo1FcK1Y= github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= From adf8fc1d958e7b9808eb80a309247551baf21704 Mon Sep 17 00:00:00 2001 From: Luckz <224748+Luckz@users.noreply.github.com> Date: Wed, 10 Aug 2022 18:20:20 +0200 Subject: [PATCH 050/228] Correct minor typos in README.md Signed-off-by: Luckz <224748+Luckz@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c7cb46212..6af134175 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ docker run \ ## Multi-Target Support (BETA) **This Feature is in beta and may require changes in future releases. Feedback is welcome.** -This exporter supports the [multi-target pattern](https://prometheus.io/docs/guides/multi-target-exporter/). This allows running a single instance of this exporter for multiple postgres targets. Using the milti-target funcationality of this exporter is **optional** and meant for users where it is impossible to install the exporter as a sidecar. For example SaaS-managed services. +This exporter supports the [multi-target pattern](https://prometheus.io/docs/guides/multi-target-exporter/). This allows running a single instance of this exporter for multiple postgres targets. Using the multi-target funcationality of this exporter is **optional** and meant for cases where it is impossible to install the exporter as a sidecar, for example SaaS-managed services. To use the multi-target functionality, send an http request to the endpoint `/probe?target=foo:5432` where target is set to the DSN of the postgres instance to scrape metrics from. From e4b3cb580580766b9918f1a95ed75e6552cee4d3 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Thu, 18 Aug 2022 22:52:25 +0200 Subject: [PATCH 051/228] Release 0.11.1 * [BUGFIX] Fix checkpoint_write_time value type #666 * [BUGFIX] Fix checkpoint_sync_time value type #667 Signed-off-by: SuperQ --- CHANGELOG.md | 5 +++++ VERSION | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8f7b92f7..7d792d41d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## master / unreleased +## 0.11.1 / 2022-08-01 + +* [BUGFIX] Fix checkpoint_write_time value type #666 +* [BUGFIX] Fix checkpoint_sync_time value type #667 + ## 0.11.0 / 2022-07-28 NOTE: pg_stat_bgwriter counter metrics had the `_total` suffix added #556 diff --git a/VERSION b/VERSION index d9df1bbc0..af88ba824 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.11.0 +0.11.1 From de9d21df6aae924a64a798f8b2c5e734f41dfcca Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 24 Aug 2022 22:07:37 -0400 Subject: [PATCH 052/228] Add dsn type for handling datasources dsn is designed to replace the other uses of dsn as a string in the long term. dsn is designed to be safe to log, properly redacting passwords. The goal is eventually always parse datasource information into a dsn type object which can safely be passed around and logged without worrying about wrapping calls in a redaction function (today this function is loggableDSN(). This should solve the root issue in #648, #677, and #643, although the full fix will require more changes to update all code references over to use the dsn type. Signed-off-by: Joe Adams --- cmd/postgres_exporter/datasource.go | 194 +++++++++++++++++++++ cmd/postgres_exporter/datasource_test.go | 206 +++++++++++++++++++++++ 2 files changed, 400 insertions(+) create mode 100644 cmd/postgres_exporter/datasource_test.go diff --git a/cmd/postgres_exporter/datasource.go b/cmd/postgres_exporter/datasource.go index 716138f32..fdfcbd6af 100644 --- a/cmd/postgres_exporter/datasource.go +++ b/cmd/postgres_exporter/datasource.go @@ -20,6 +20,7 @@ import ( "os" "regexp" "strings" + "unicode" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" @@ -172,3 +173,196 @@ func getDataSources() ([]string, error) { return []string{dsn}, nil } + +// dsn represents a parsed datasource. It contains fields for the individual connection components. +type dsn struct { + scheme string + username string + password string + host string + path string + query string +} + +// String makes a dsn safe to print by excluding any passwords. This allows dsn to be used in +// strings and log messages without needing to call a redaction function first. +func (d dsn) String() string { + if d.password != "" { + return fmt.Sprintf("%s://%s:******@%s%s?%s", d.scheme, d.username, d.host, d.path, d.query) + } + + if d.username != "" { + return fmt.Sprintf("%s://%s@%s%s?%s", d.scheme, d.username, d.host, d.path, d.query) + } + + return fmt.Sprintf("%s://%s%s?%s", d.scheme, d.host, d.path, d.query) +} + +// dsnFromString parses a connection string into a dsn. It will attempt to parse the string as +// a URL and as a set of key=value pairs. If both attempts fail, dsnFromString will return an error. +func dsnFromString(in string) (dsn, error) { + if strings.HasPrefix(in, "postgresql://") { + return dsnFromURL(in) + } + + // Try to parse as key=value pairs + d, err := dsnFromKeyValue(in) + if err == nil { + return d, nil + } + + return dsn{}, fmt.Errorf("could not understand DSN") +} + +// dsnFromURL parses the input as a URL and returns the dsn representation. +func dsnFromURL(in string) (dsn, error) { + u, err := url.Parse(in) + if err != nil { + return dsn{}, err + } + pass, _ := u.User.Password() + user := u.User.Username() + + query := u.Query() + + if queryPass := query.Get("password"); queryPass != "" { + if pass == "" { + pass = queryPass + } + } + query.Del("password") + + if queryUser := query.Get("user"); queryUser != "" { + if user == "" { + user = queryUser + } + } + query.Del("user") + + d := dsn{ + scheme: u.Scheme, + username: user, + password: pass, + host: u.Host, + path: u.Path, + query: query.Encode(), + } + + return d, nil +} + +// dsnFromKeyValue parses the input as a set of key=value pairs and returns the dsn representation. +func dsnFromKeyValue(in string) (dsn, error) { + // Attempt to confirm at least one key=value pair before starting the rune parser + connstringRe := regexp.MustCompile(`^ *[a-zA-Z0-9]+ *= *[^= ]+`) + if !connstringRe.MatchString(in) { + return dsn{}, fmt.Errorf("input is not a key-value DSN") + } + + // Anything other than known fields should be part of the querystring + query := url.Values{} + + pairs, err := parseKeyValue(in) + if err != nil { + return dsn{}, fmt.Errorf("failed to parse key-value DSN: %v", err) + } + + // Build the dsn from the key=value pairs + d := dsn{ + scheme: "postgresql", + } + + hostname := "" + port := "" + + for k, v := range pairs { + switch k { + case "host": + hostname = v + case "port": + port = v + case "user": + d.username = v + case "password": + d.password = v + default: + query.Set(k, v) + } + } + + if hostname == "" { + hostname = "localhost" + } + + if port == "" { + d.host = hostname + } else { + d.host = fmt.Sprintf("%s:%s", hostname, port) + } + + d.query = query.Encode() + + return d, nil +} + +// parseKeyValue is a key=value parser. It loops over each rune to split out keys and values +// and attempting to honor quoted values. parseKeyValue will return an error if it is unable +// to properly parse the input. +func parseKeyValue(in string) (map[string]string, error) { + out := map[string]string{} + + inPart := false + inQuote := false + part := []rune{} + key := "" + for _, c := range in { + switch { + case unicode.In(c, unicode.Quotation_Mark): + if inQuote { + inQuote = false + } else { + inQuote = true + } + case unicode.In(c, unicode.White_Space): + if inPart { + if inQuote { + part = append(part, c) + } else { + // Are we finishing a key=value? + if key == "" { + return out, fmt.Errorf("invalid input") + } + out[key] = string(part) + inPart = false + part = []rune{} + } + } else { + // Are we finishing a key=value? + if key == "" { + return out, fmt.Errorf("invalid input") + } + out[key] = string(part) + inPart = false + part = []rune{} + // Do something with the value + } + case c == '=': + if inPart { + inPart = false + key = string(part) + part = []rune{} + } else { + return out, fmt.Errorf("invalid input") + } + default: + inPart = true + part = append(part, c) + } + } + + if key != "" && len(part) > 0 { + out[key] = string(part) + } + + return out, nil +} diff --git a/cmd/postgres_exporter/datasource_test.go b/cmd/postgres_exporter/datasource_test.go new file mode 100644 index 000000000..02fb8ddef --- /dev/null +++ b/cmd/postgres_exporter/datasource_test.go @@ -0,0 +1,206 @@ +// Copyright 2022 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 main + +import ( + "reflect" + "testing" +) + +// Test_dsn_String is designed to test different dsn combinations for their string representation. +// dsn.String() is designed to be safe to print, redacting any password information and these test +// cases are intended to cover known cases. +func Test_dsn_String(t *testing.T) { + type fields struct { + scheme string + username string + password string + host string + path string + query string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "Without Password", + fields: fields{ + scheme: "postgresql", + username: "test", + host: "localhost:5432", + query: "", + }, + want: "postgresql://test@localhost:5432?", + }, + { + name: "With Password", + fields: fields{ + scheme: "postgresql", + username: "test", + password: "supersecret", + host: "localhost:5432", + query: "", + }, + want: "postgresql://test:******@localhost:5432?", + }, + { + name: "With Password and Query String", + fields: fields{ + scheme: "postgresql", + username: "test", + password: "supersecret", + host: "localhost:5432", + query: "ssldisable=true", + }, + want: "postgresql://test:******@localhost:5432?ssldisable=true", + }, + { + name: "With Password, Path, and Query String", + fields: fields{ + scheme: "postgresql", + username: "test", + password: "supersecret", + host: "localhost:5432", + path: "/somevalue", + query: "ssldisable=true", + }, + want: "postgresql://test:******@localhost:5432/somevalue?ssldisable=true", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := dsn{ + scheme: tt.fields.scheme, + username: tt.fields.username, + password: tt.fields.password, + host: tt.fields.host, + path: tt.fields.path, + query: tt.fields.query, + } + if got := d.String(); got != tt.want { + t.Errorf("dsn.String() = %v, want %v", got, tt.want) + } + }) + } +} + +// Test_dsnFromString tests the dsnFromString function with known variations +// of connection string inputs to ensure that it properly parses the input into +// a dsn. +func Test_dsnFromString(t *testing.T) { + + tests := []struct { + name string + input string + want dsn + wantErr bool + }{ + { + name: "Key value with password", + input: "host=host.example.com user=postgres port=5432 password=s3cr3t", + want: dsn{ + scheme: "postgresql", + host: "host.example.com:5432", + username: "postgres", + password: "s3cr3t", + }, + wantErr: false, + }, + { + name: "Key value with quoted password and space", + input: "host=host.example.com user=postgres port=5432 password=\"s3cr 3t\"", + want: dsn{ + scheme: "postgresql", + host: "host.example.com:5432", + username: "postgres", + password: "s3cr 3t", + }, + wantErr: false, + }, + { + name: "Key value with different order", + input: "password=abcde host=host.example.com user=postgres port=5432", + want: dsn{ + scheme: "postgresql", + host: "host.example.com:5432", + username: "postgres", + password: "abcde", + }, + wantErr: false, + }, + { + name: "Key value with different order, quoted password, duplicate password", + input: "password=abcde host=host.example.com user=postgres port=5432 password=\"s3cr 3t\"", + want: dsn{ + scheme: "postgresql", + host: "host.example.com:5432", + username: "postgres", + password: "s3cr 3t", + }, + wantErr: false, + }, + { + name: "URL with user in query string", + input: "postgresql://host.example.com:5432/tsdb?user=postgres", + want: dsn{ + scheme: "postgresql", + host: "host.example.com:5432", + path: "/tsdb", + query: "", + username: "postgres", + }, + wantErr: false, + }, + { + name: "URL with user and password", + input: "postgresql://user:s3cret@host.example.com:5432/tsdb?user=postgres", + want: dsn{ + scheme: "postgresql", + host: "host.example.com:5432", + path: "/tsdb", + query: "", + username: "user", + password: "s3cret", + }, + wantErr: false, + }, + { + name: "URL with user and password in query string", + input: "postgresql://host.example.com:5432/tsdb?user=postgres&password=s3cr3t", + want: dsn{ + scheme: "postgresql", + host: "host.example.com:5432", + path: "/tsdb", + query: "", + username: "postgres", + password: "s3cr3t", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := dsnFromString(tt.input) + if (err != nil) != tt.wantErr { + t.Errorf("dsnFromString() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("dsnFromString() = %+v, want %+v", got, tt.want) + } + }) + } +} From d86dd06ffe9af7b5c1faa37ea3098c3552df5904 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Fri, 26 Aug 2022 16:49:54 +0200 Subject: [PATCH 053/228] Release 0.12.0-rc.0 BREAKING CHANGES: This release changes support for multiple postgres servers to use the multi-target exporter pattern. This makes it much easier to monitor multiple PostgreSQL servers from a single exporter by passing the target via URL params. See the Multi-Target Support section of the README. * [CHANGE] Add multi-target support #618 * [BUGFIX] Add dsn type for handling datasources #678 Signed-off-by: SuperQ --- CHANGELOG.md | 12 +++++++++ VERSION | 2 +- cmd/postgres_exporter/namespace.go | 2 +- cmd/postgres_exporter/postgres_exporter.go | 2 +- .../postgres_exporter_test.go | 2 +- cmd/postgres_exporter/queries.go | 2 +- cmd/postgres_exporter/server.go | 2 +- go.mod | 12 ++++----- go.sum | 26 +++++++++++-------- 9 files changed, 39 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d792d41d..38d7e4d90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ ## master / unreleased +## 0.12.0-rc.0 / 2022-08-26 + +BREAKING CHANGES: + +This release changes support for multiple postgres servers to use the +multi-target exporter pattern. This makes it much easier to monitor multiple +PostgreSQL servers from a single exporter by passing the target via URL +params. See the Multi-Target Support section of the README. + +* [CHANGE] Add multi-target support #618 +* [BUGFIX] Add dsn type for handling datasources #678 + ## 0.11.1 / 2022-08-01 * [BUGFIX] Fix checkpoint_write_time value type #666 diff --git a/VERSION b/VERSION index af88ba824..68f8b7694 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.11.1 +0.12.0-rc.0 diff --git a/cmd/postgres_exporter/namespace.go b/cmd/postgres_exporter/namespace.go index ab1e74ea0..41674007d 100644 --- a/cmd/postgres_exporter/namespace.go +++ b/cmd/postgres_exporter/namespace.go @@ -19,7 +19,7 @@ import ( "fmt" "time" - "github.com/blang/semver" + "github.com/blang/semver/v4" "github.com/go-kit/log/level" "github.com/lib/pq" "github.com/prometheus/client_golang/prometheus" diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index 2574e0252..af973d5d5 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -24,7 +24,7 @@ import ( "strings" "time" - "github.com/blang/semver" + "github.com/blang/semver/v4" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) diff --git a/cmd/postgres_exporter/postgres_exporter_test.go b/cmd/postgres_exporter/postgres_exporter_test.go index 6017756a8..468aa39b9 100644 --- a/cmd/postgres_exporter/postgres_exporter_test.go +++ b/cmd/postgres_exporter/postgres_exporter_test.go @@ -24,7 +24,7 @@ import ( "testing" "time" - "github.com/blang/semver" + "github.com/blang/semver/v4" "github.com/prometheus/client_golang/prometheus" . "gopkg.in/check.v1" ) diff --git a/cmd/postgres_exporter/queries.go b/cmd/postgres_exporter/queries.go index e27480f4f..b17420d28 100644 --- a/cmd/postgres_exporter/queries.go +++ b/cmd/postgres_exporter/queries.go @@ -17,7 +17,7 @@ import ( "errors" "fmt" - "github.com/blang/semver" + "github.com/blang/semver/v4" "github.com/go-kit/log/level" "gopkg.in/yaml.v2" ) diff --git a/cmd/postgres_exporter/server.go b/cmd/postgres_exporter/server.go index 8747dffa0..bcfee6812 100644 --- a/cmd/postgres_exporter/server.go +++ b/cmd/postgres_exporter/server.go @@ -19,7 +19,7 @@ import ( "sync" "time" - "github.com/blang/semver" + "github.com/blang/semver/v4" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) diff --git a/go.mod b/go.mod index 08fad017a..5f5d6195f 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,17 @@ module github.com/prometheus-community/postgres_exporter go 1.17 require ( - github.com/blang/semver v3.5.1+incompatible + github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 github.com/lib/pq v1.10.6 - github.com/prometheus/client_golang v1.12.2 + github.com/prometheus/client_golang v1.13.0 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.37.0 github.com/prometheus/exporter-toolkit v0.7.1 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b + gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -29,12 +29,12 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect + github.com/prometheus/procfs v0.8.0 // indirect golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect - golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/appengine v1.6.6 // indirect - google.golang.org/protobuf v1.26.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect ) diff --git a/go.sum b/go.sum index 8532a8c2b..fcd14c6b4 100644 --- a/go.sum +++ b/go.sum @@ -44,8 +44,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -116,8 +116,9 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -177,8 +178,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= -github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -197,8 +198,9 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -305,6 +307,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -342,8 +345,9 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -400,7 +404,6 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -477,8 +480,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -494,8 +498,8 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 9ae347519b63942d85565b33f815f52df7394df9 Mon Sep 17 00:00:00 2001 From: Yoan Blanc Date: Tue, 30 Aug 2022 06:48:06 +0200 Subject: [PATCH 054/228] fix: typo Signed-off-by: Yoan Blanc --- cmd/postgres_exporter/datasource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/datasource.go b/cmd/postgres_exporter/datasource.go index fdfcbd6af..0a2b943a7 100644 --- a/cmd/postgres_exporter/datasource.go +++ b/cmd/postgres_exporter/datasource.go @@ -164,7 +164,7 @@ func getDataSources() ([]string, error) { } // No datasources found. This allows us to support the multi-target pattern - // withouth an explicit datasource. + // without an explicit datasource. if uri == "" { return []string{}, nil } From 7ffba684de577fe07673b10ddc1dace286d099ec Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Fri, 2 Sep 2022 10:32:44 -0400 Subject: [PATCH 055/228] Update multi-target handler to use new DSN type - Moves new dsn type to config.DSN. This will prevent circular dependencies. - Change DSN.query to be url.Values. This allows the multi-target functionality to merge values without re-parsing the query string - Change NewProbeCollector to use the new config.DSN type - Add DSN.GetConnectionString to return a string formatted for the sql driver to use during connection Signed-off-by: Joe Adams --- cmd/postgres_exporter/datasource.go | 194 --------------- collector/probe.go | 11 +- config/config.go | 28 +-- config/dsn.go | 225 ++++++++++++++++++ .../datasource_test.go => config/dsn_test.go | 45 ++-- 5 files changed, 268 insertions(+), 235 deletions(-) create mode 100644 config/dsn.go rename cmd/postgres_exporter/datasource_test.go => config/dsn_test.go (90%) diff --git a/cmd/postgres_exporter/datasource.go b/cmd/postgres_exporter/datasource.go index 0a2b943a7..97f7ecd8b 100644 --- a/cmd/postgres_exporter/datasource.go +++ b/cmd/postgres_exporter/datasource.go @@ -20,7 +20,6 @@ import ( "os" "regexp" "strings" - "unicode" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" @@ -173,196 +172,3 @@ func getDataSources() ([]string, error) { return []string{dsn}, nil } - -// dsn represents a parsed datasource. It contains fields for the individual connection components. -type dsn struct { - scheme string - username string - password string - host string - path string - query string -} - -// String makes a dsn safe to print by excluding any passwords. This allows dsn to be used in -// strings and log messages without needing to call a redaction function first. -func (d dsn) String() string { - if d.password != "" { - return fmt.Sprintf("%s://%s:******@%s%s?%s", d.scheme, d.username, d.host, d.path, d.query) - } - - if d.username != "" { - return fmt.Sprintf("%s://%s@%s%s?%s", d.scheme, d.username, d.host, d.path, d.query) - } - - return fmt.Sprintf("%s://%s%s?%s", d.scheme, d.host, d.path, d.query) -} - -// dsnFromString parses a connection string into a dsn. It will attempt to parse the string as -// a URL and as a set of key=value pairs. If both attempts fail, dsnFromString will return an error. -func dsnFromString(in string) (dsn, error) { - if strings.HasPrefix(in, "postgresql://") { - return dsnFromURL(in) - } - - // Try to parse as key=value pairs - d, err := dsnFromKeyValue(in) - if err == nil { - return d, nil - } - - return dsn{}, fmt.Errorf("could not understand DSN") -} - -// dsnFromURL parses the input as a URL and returns the dsn representation. -func dsnFromURL(in string) (dsn, error) { - u, err := url.Parse(in) - if err != nil { - return dsn{}, err - } - pass, _ := u.User.Password() - user := u.User.Username() - - query := u.Query() - - if queryPass := query.Get("password"); queryPass != "" { - if pass == "" { - pass = queryPass - } - } - query.Del("password") - - if queryUser := query.Get("user"); queryUser != "" { - if user == "" { - user = queryUser - } - } - query.Del("user") - - d := dsn{ - scheme: u.Scheme, - username: user, - password: pass, - host: u.Host, - path: u.Path, - query: query.Encode(), - } - - return d, nil -} - -// dsnFromKeyValue parses the input as a set of key=value pairs and returns the dsn representation. -func dsnFromKeyValue(in string) (dsn, error) { - // Attempt to confirm at least one key=value pair before starting the rune parser - connstringRe := regexp.MustCompile(`^ *[a-zA-Z0-9]+ *= *[^= ]+`) - if !connstringRe.MatchString(in) { - return dsn{}, fmt.Errorf("input is not a key-value DSN") - } - - // Anything other than known fields should be part of the querystring - query := url.Values{} - - pairs, err := parseKeyValue(in) - if err != nil { - return dsn{}, fmt.Errorf("failed to parse key-value DSN: %v", err) - } - - // Build the dsn from the key=value pairs - d := dsn{ - scheme: "postgresql", - } - - hostname := "" - port := "" - - for k, v := range pairs { - switch k { - case "host": - hostname = v - case "port": - port = v - case "user": - d.username = v - case "password": - d.password = v - default: - query.Set(k, v) - } - } - - if hostname == "" { - hostname = "localhost" - } - - if port == "" { - d.host = hostname - } else { - d.host = fmt.Sprintf("%s:%s", hostname, port) - } - - d.query = query.Encode() - - return d, nil -} - -// parseKeyValue is a key=value parser. It loops over each rune to split out keys and values -// and attempting to honor quoted values. parseKeyValue will return an error if it is unable -// to properly parse the input. -func parseKeyValue(in string) (map[string]string, error) { - out := map[string]string{} - - inPart := false - inQuote := false - part := []rune{} - key := "" - for _, c := range in { - switch { - case unicode.In(c, unicode.Quotation_Mark): - if inQuote { - inQuote = false - } else { - inQuote = true - } - case unicode.In(c, unicode.White_Space): - if inPart { - if inQuote { - part = append(part, c) - } else { - // Are we finishing a key=value? - if key == "" { - return out, fmt.Errorf("invalid input") - } - out[key] = string(part) - inPart = false - part = []rune{} - } - } else { - // Are we finishing a key=value? - if key == "" { - return out, fmt.Errorf("invalid input") - } - out[key] = string(part) - inPart = false - part = []rune{} - // Do something with the value - } - case c == '=': - if inPart { - inPart = false - key = string(part) - part = []rune{} - } else { - return out, fmt.Errorf("invalid input") - } - default: - inPart = true - part = append(part, c) - } - } - - if key != "" && len(part) > 0 { - out[key] = string(part) - } - - return out, nil -} diff --git a/collector/probe.go b/collector/probe.go index 8aa18b92c..37cb151b9 100644 --- a/collector/probe.go +++ b/collector/probe.go @@ -16,11 +16,10 @@ package collector import ( "context" "database/sql" - "fmt" - "strings" "sync" "github.com/go-kit/log" + "github.com/prometheus-community/postgres_exporter/config" "github.com/prometheus/client_golang/prometheus" ) @@ -31,7 +30,7 @@ type ProbeCollector struct { db *sql.DB } -func NewProbeCollector(logger log.Logger, registry *prometheus.Registry, dsn string) (*ProbeCollector, error) { +func NewProbeCollector(logger log.Logger, registry *prometheus.Registry, dsn config.DSN) (*ProbeCollector, error) { collectors := make(map[string]Collector) initiatedCollectorsMtx.Lock() defer initiatedCollectorsMtx.Unlock() @@ -55,11 +54,7 @@ func NewProbeCollector(logger log.Logger, registry *prometheus.Registry, dsn str } } - if !strings.HasPrefix(dsn, "postgres://") { - dsn = fmt.Sprintf("postgres://%s", dsn) - } - - db, err := sql.Open("postgres", dsn) + db, err := sql.Open("postgres", dsn.GetConnectionString()) if err != nil { return nil, err } diff --git a/config/config.go b/config/config.go index 10e7b7337..9e514f413 100644 --- a/config/config.go +++ b/config/config.go @@ -15,9 +15,7 @@ package config import ( "fmt" - "net/url" "os" - "strings" "sync" "github.com/go-kit/log" @@ -97,26 +95,26 @@ func (ch *ConfigHandler) ReloadConfig(f string, logger log.Logger) error { return nil } -func (m AuthModule) ConfigureTarget(target string) (string, error) { - // ip:port urls do not parse properly and that is the typical way users interact with postgres - t := fmt.Sprintf("exporter://%s", target) - u, err := url.Parse(t) +func (m AuthModule) ConfigureTarget(target string) (DSN, error) { + dsn, err := dsnFromString(target) if err != nil { - return "", err + return DSN{}, err } + // Set the credentials from the authentication module + // TODO(@sysadmind): What should the order of precedence be? if m.Type == "userpass" { - u.User = url.UserPassword(m.UserPass.Username, m.UserPass.Password) + if m.UserPass.Username != "" { + dsn.username = m.UserPass.Username + } + if m.UserPass.Password != "" { + dsn.password = m.UserPass.Password + } } - query := u.Query() for k, v := range m.Options { - query.Set(k, v) + dsn.query.Set(k, v) } - u.RawQuery = query.Encode() - - parsed := u.String() - trim := strings.TrimPrefix(parsed, "exporter://") - return trim, nil + return dsn, nil } diff --git a/config/dsn.go b/config/dsn.go new file mode 100644 index 000000000..182a0aae7 --- /dev/null +++ b/config/dsn.go @@ -0,0 +1,225 @@ +package config + +import ( + "fmt" + "net/url" + "regexp" + "strings" + "unicode" +) + +// DSN represents a parsed datasource. It contains fields for the individual connection components. +type DSN struct { + scheme string + username string + password string + host string + path string + query url.Values +} + +// String makes a dsn safe to print by excluding any passwords. This allows dsn to be used in +// strings and log messages without needing to call a redaction function first. +func (d DSN) String() string { + if d.password != "" { + return fmt.Sprintf("%s://%s:******@%s%s?%s", d.scheme, d.username, d.host, d.path, d.query.Encode()) + } + + if d.username != "" { + return fmt.Sprintf("%s://%s@%s%s?%s", d.scheme, d.username, d.host, d.path, d.query.Encode()) + } + + return fmt.Sprintf("%s://%s%s?%s", d.scheme, d.host, d.path, d.query.Encode()) +} + +// GetConnectionString returns the URL to pass to the driver for database connections. This value should not be logged. +func (d DSN) GetConnectionString() string { + u := url.URL{ + Scheme: d.scheme, + Host: d.host, + Path: d.path, + RawQuery: d.query.Encode(), + } + + // Username and Password + if d.username != "" { + u.User = url.UserPassword(d.username, d.password) + } + + return u.String() +} + +// dsnFromString parses a connection string into a dsn. It will attempt to parse the string as +// a URL and as a set of key=value pairs. If both attempts fail, dsnFromString will return an error. +func dsnFromString(in string) (DSN, error) { + if strings.HasPrefix(in, "postgresql://") { + return dsnFromURL(in) + } + + // Try to parse as key=value pairs + d, err := dsnFromKeyValue(in) + if err == nil { + return d, nil + } + + // Parse the string as a URL, with the scheme prefixed + d, err = dsnFromURL(fmt.Sprintf("postgresql://%s", in)) + if err == nil { + return d, nil + } + + return DSN{}, fmt.Errorf("could not understand DSN") +} + +// dsnFromURL parses the input as a URL and returns the dsn representation. +func dsnFromURL(in string) (DSN, error) { + u, err := url.Parse(in) + if err != nil { + return DSN{}, err + } + pass, _ := u.User.Password() + user := u.User.Username() + + query := u.Query() + + if queryPass := query.Get("password"); queryPass != "" { + if pass == "" { + pass = queryPass + } + } + query.Del("password") + + if queryUser := query.Get("user"); queryUser != "" { + if user == "" { + user = queryUser + } + } + query.Del("user") + + d := DSN{ + scheme: u.Scheme, + username: user, + password: pass, + host: u.Host, + path: u.Path, + query: query, + } + + return d, nil +} + +// dsnFromKeyValue parses the input as a set of key=value pairs and returns the dsn representation. +func dsnFromKeyValue(in string) (DSN, error) { + // Attempt to confirm at least one key=value pair before starting the rune parser + connstringRe := regexp.MustCompile(`^ *[a-zA-Z0-9]+ *= *[^= ]+`) + if !connstringRe.MatchString(in) { + return DSN{}, fmt.Errorf("input is not a key-value DSN") + } + + // Anything other than known fields should be part of the querystring + query := url.Values{} + + pairs, err := parseKeyValue(in) + if err != nil { + return DSN{}, fmt.Errorf("failed to parse key-value DSN: %v", err) + } + + // Build the dsn from the key=value pairs + d := DSN{ + scheme: "postgresql", + } + + hostname := "" + port := "" + + for k, v := range pairs { + switch k { + case "host": + hostname = v + case "port": + port = v + case "user": + d.username = v + case "password": + d.password = v + default: + query.Set(k, v) + } + } + + if hostname == "" { + hostname = "localhost" + } + + if port == "" { + d.host = hostname + } else { + d.host = fmt.Sprintf("%s:%s", hostname, port) + } + + d.query = query + + return d, nil +} + +// parseKeyValue is a key=value parser. It loops over each rune to split out keys and values +// and attempting to honor quoted values. parseKeyValue will return an error if it is unable +// to properly parse the input. +func parseKeyValue(in string) (map[string]string, error) { + out := map[string]string{} + + inPart := false + inQuote := false + part := []rune{} + key := "" + for _, c := range in { + switch { + case unicode.In(c, unicode.Quotation_Mark): + if inQuote { + inQuote = false + } else { + inQuote = true + } + case unicode.In(c, unicode.White_Space): + if inPart { + if inQuote { + part = append(part, c) + } else { + // Are we finishing a key=value? + if key == "" { + return out, fmt.Errorf("invalid input") + } + out[key] = string(part) + inPart = false + part = []rune{} + } + } else { + // Are we finishing a key=value? + if key == "" { + return out, fmt.Errorf("invalid input") + } + out[key] = string(part) + inPart = false + part = []rune{} + // Do something with the value + } + case c == '=': + if inPart { + inPart = false + key = string(part) + part = []rune{} + } else { + return out, fmt.Errorf("invalid input") + } + default: + inPart = true + part = append(part, c) + } + } + + if key != "" && len(part) > 0 { + out[key] = string(part) + } + + return out, nil +} diff --git a/cmd/postgres_exporter/datasource_test.go b/config/dsn_test.go similarity index 90% rename from cmd/postgres_exporter/datasource_test.go rename to config/dsn_test.go index 02fb8ddef..637a3568e 100644 --- a/cmd/postgres_exporter/datasource_test.go +++ b/config/dsn_test.go @@ -11,9 +11,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -package main +package config import ( + "net/url" "reflect" "testing" ) @@ -28,7 +29,7 @@ func Test_dsn_String(t *testing.T) { password string host string path string - query string + query url.Values } tests := []struct { name string @@ -41,7 +42,7 @@ func Test_dsn_String(t *testing.T) { scheme: "postgresql", username: "test", host: "localhost:5432", - query: "", + query: url.Values{}, }, want: "postgresql://test@localhost:5432?", }, @@ -52,7 +53,7 @@ func Test_dsn_String(t *testing.T) { username: "test", password: "supersecret", host: "localhost:5432", - query: "", + query: url.Values{}, }, want: "postgresql://test:******@localhost:5432?", }, @@ -63,7 +64,9 @@ func Test_dsn_String(t *testing.T) { username: "test", password: "supersecret", host: "localhost:5432", - query: "ssldisable=true", + query: url.Values{ + "ssldisable": []string{"true"}, + }, }, want: "postgresql://test:******@localhost:5432?ssldisable=true", }, @@ -75,14 +78,16 @@ func Test_dsn_String(t *testing.T) { password: "supersecret", host: "localhost:5432", path: "/somevalue", - query: "ssldisable=true", + query: url.Values{ + "ssldisable": []string{"true"}, + }, }, want: "postgresql://test:******@localhost:5432/somevalue?ssldisable=true", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - d := dsn{ + d := DSN{ scheme: tt.fields.scheme, username: tt.fields.username, password: tt.fields.password, @@ -105,61 +110,65 @@ func Test_dsnFromString(t *testing.T) { tests := []struct { name string input string - want dsn + want DSN wantErr bool }{ { name: "Key value with password", input: "host=host.example.com user=postgres port=5432 password=s3cr3t", - want: dsn{ + want: DSN{ scheme: "postgresql", host: "host.example.com:5432", username: "postgres", password: "s3cr3t", + query: url.Values{}, }, wantErr: false, }, { name: "Key value with quoted password and space", input: "host=host.example.com user=postgres port=5432 password=\"s3cr 3t\"", - want: dsn{ + want: DSN{ scheme: "postgresql", host: "host.example.com:5432", username: "postgres", password: "s3cr 3t", + query: url.Values{}, }, wantErr: false, }, { name: "Key value with different order", input: "password=abcde host=host.example.com user=postgres port=5432", - want: dsn{ + want: DSN{ scheme: "postgresql", host: "host.example.com:5432", username: "postgres", password: "abcde", + query: url.Values{}, }, wantErr: false, }, { name: "Key value with different order, quoted password, duplicate password", input: "password=abcde host=host.example.com user=postgres port=5432 password=\"s3cr 3t\"", - want: dsn{ + want: DSN{ scheme: "postgresql", host: "host.example.com:5432", username: "postgres", password: "s3cr 3t", + query: url.Values{}, }, wantErr: false, }, { name: "URL with user in query string", input: "postgresql://host.example.com:5432/tsdb?user=postgres", - want: dsn{ + want: DSN{ scheme: "postgresql", host: "host.example.com:5432", path: "/tsdb", - query: "", + query: url.Values{}, username: "postgres", }, wantErr: false, @@ -167,11 +176,11 @@ func Test_dsnFromString(t *testing.T) { { name: "URL with user and password", input: "postgresql://user:s3cret@host.example.com:5432/tsdb?user=postgres", - want: dsn{ + want: DSN{ scheme: "postgresql", host: "host.example.com:5432", path: "/tsdb", - query: "", + query: url.Values{}, username: "user", password: "s3cret", }, @@ -180,11 +189,11 @@ func Test_dsnFromString(t *testing.T) { { name: "URL with user and password in query string", input: "postgresql://host.example.com:5432/tsdb?user=postgres&password=s3cr3t", - want: dsn{ + want: DSN{ scheme: "postgresql", host: "host.example.com:5432", path: "/tsdb", - query: "", + query: url.Values{}, username: "postgres", password: "s3cr3t", }, From 69a802493b821aa67d9813d95841521819ad86d5 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Fri, 2 Sep 2022 11:09:01 -0400 Subject: [PATCH 056/228] Add missing license header Signed-off-by: Joe Adams --- config/dsn.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/config/dsn.go b/config/dsn.go index 182a0aae7..78d798d5f 100644 --- a/config/dsn.go +++ b/config/dsn.go @@ -1,3 +1,16 @@ +// Copyright 2022 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 config import ( From 73b0b42c8d408a19ee773b5ac12f75745e8cf3f9 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Fri, 2 Sep 2022 12:24:25 -0400 Subject: [PATCH 057/228] Convert pg_stat_database to new collector model Signed-off-by: Joe Adams --- cmd/postgres_exporter/postgres_exporter.go | 25 -- collector/pg_stat_database.go | 432 +++++++++++++++++++++ 2 files changed, 432 insertions(+), 25 deletions(-) create mode 100644 collector/pg_stat_database.go diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index af973d5d5..879322659 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -163,31 +163,6 @@ func dumpMaps() { } var builtinMetricMaps = map[string]intermediateMetricMap{ - "pg_stat_database": { - map[string]ColumnMapping{ - "datid": {LABEL, "OID of a database", nil, nil}, - "datname": {LABEL, "Name of this database", nil, nil}, - "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}, - "xact_commit": {COUNTER, "Number of transactions in this database that have been committed", nil, nil}, - "xact_rollback": {COUNTER, "Number of transactions in this database that have been rolled back", nil, nil}, - "blks_read": {COUNTER, "Number of disk blocks read in this database", nil, nil}, - "blks_hit": {COUNTER, "Number of times disk blocks were found already in the buffer cache, so that a read was not necessary (this only includes hits in the PostgreSQL buffer cache, not the operating system's file system cache)", nil, nil}, - "tup_returned": {COUNTER, "Number of rows returned by queries in this database", nil, nil}, - "tup_fetched": {COUNTER, "Number of rows fetched by queries in this database", nil, nil}, - "tup_inserted": {COUNTER, "Number of rows inserted by queries in this database", nil, nil}, - "tup_updated": {COUNTER, "Number of rows updated by queries in this database", nil, nil}, - "tup_deleted": {COUNTER, "Number of rows deleted by queries in this database", nil, nil}, - "conflicts": {COUNTER, "Number of queries canceled due to conflicts with recovery in this database. (Conflicts occur only on standby servers; see pg_stat_database_conflicts for details.)", nil, nil}, - "temp_files": {COUNTER, "Number of temporary files created by queries in this database. All temporary files are counted, regardless of why the temporary file was created (e.g., sorting or hashing), and regardless of the log_temp_files setting.", nil, nil}, - "temp_bytes": {COUNTER, "Total amount of data written to temporary files by queries in this database. All temporary files are counted, regardless of why the temporary file was created, and regardless of the log_temp_files setting.", nil, nil}, - "deadlocks": {COUNTER, "Number of deadlocks detected in this database", nil, nil}, - "blk_read_time": {COUNTER, "Time spent reading data file blocks by backends in this database, in milliseconds", nil, nil}, - "blk_write_time": {COUNTER, "Time spent writing data file blocks by backends in this database, in milliseconds", nil, nil}, - "stats_reset": {COUNTER, "Time at which these statistics were last reset", nil, nil}, - }, - true, - 0, - }, "pg_stat_database_conflicts": { map[string]ColumnMapping{ "datid": {LABEL, "OID of a database", nil, nil}, diff --git a/collector/pg_stat_database.go b/collector/pg_stat_database.go new file mode 100644 index 000000000..387094e08 --- /dev/null +++ b/collector/pg_stat_database.go @@ -0,0 +1,432 @@ +// Copyright 2022 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 collector + +import ( + "context" + "database/sql" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +func init() { + registerCollector("stat_database", defaultEnabled, NewPGStatDatabaseCollector) +} + +type PGStatDatabaseCollector struct{} + +func NewPGStatDatabaseCollector(logger log.Logger) (Collector, error) { + return &PGStatDatabaseCollector{}, nil +} + +const statDatabaseSubsystem = "stat_database" + +var statDatabase = map[string]*prometheus.Desc{ + "numbackends": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "numbackends", + ), + "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.", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "xact_commit": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "xact_commit", + ), + "Number of transactions in this database that have been committed", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "xact_rollback": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "xact_rollback", + ), + "Number of transactions in this database that have been rolled back", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "blks_read": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "blks_read", + ), + "Number of disk blocks read in this database", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "blks_hit": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "blks_hit", + ), + "Number of times disk blocks were found already in the buffer cache, so that a read was not necessary (this only includes hits in the PostgreSQL buffer cache, not the operating system's file system cache)", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "tup_returned": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "tup_returned", + ), + "Number of rows returned by queries in this database", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "tup_fetched": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "tup_fetched", + ), + "Number of rows fetched by queries in this database", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "tup_inserted": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "tup_inserted", + ), + "Number of rows inserted by queries in this database", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "tup_updated": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "tup_updated", + ), + "Number of rows updated by queries in this database", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "tup_deleted": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "tup_deleted", + ), + "Number of rows deleted by queries in this database", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "conflicts": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "conflicts", + ), + "Number of queries canceled due to conflicts with recovery in this database. (Conflicts occur only on standby servers; see pg_stat_database_conflicts for details.)", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "temp_files": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "temp_files", + ), + "Number of temporary files created by queries in this database. All temporary files are counted, regardless of why the temporary file was created (e.g., sorting or hashing), and regardless of the log_temp_files setting.", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "temp_bytes": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "temp_bytes", + ), + "Total amount of data written to temporary files by queries in this database. All temporary files are counted, regardless of why the temporary file was created, and regardless of the log_temp_files setting.", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "deadlocks": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "deadlocks", + ), + "Number of deadlocks detected in this database", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "blk_read_time": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "blk_read_time", + ), + "Time spent reading data file blocks by backends in this database, in milliseconds", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "blk_write_time": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "blk_write_time", + ), + "Time spent writing data file blocks by backends in this database, in milliseconds", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), + "stats_reset": prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "stats_reset", + ), + "Time at which these statistics were last reset", + []string{"datid", "datname"}, + prometheus.Labels{}, + ), +} + +func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { + rows, err := db.QueryContext(ctx, + `SELECT + datid + ,datname + ,numbackends + ,xact_commit + ,xact_rollback + ,blks_read + ,blks_hit + ,tup_returned + ,tup_fetched + ,tup_inserted + ,tup_updated + ,tup_deleted + ,conflicts + ,temp_files + ,temp_bytes + ,deadlocks + ,blk_read_time + ,blk_write_time + ,stats_reset + FROM pg_stat_database; + `, + ) + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var datid string + var datname string + var numBackends float64 + var xactCommit float64 + var xactRollback float64 + var blksRead float64 + var blksHit float64 + var tupReturned float64 + var tupFetched float64 + var tupInserted float64 + var tupUpdated float64 + var tupDeleted float64 + var conflicts float64 + var tempFiles float64 + var tempBytes float64 + var deadlocks float64 + var blkReadTime float64 + var blkWriteTime float64 + var statsReset sql.NullTime + + err := rows.Scan( + &datid, + &datname, + &numBackends, + &xactCommit, + &xactRollback, + &blksRead, + &blksHit, + &tupReturned, + &tupFetched, + &tupInserted, + &tupUpdated, + &tupDeleted, + &conflicts, + &tempFiles, + &tempBytes, + &deadlocks, + &blkReadTime, + &blkWriteTime, + &statsReset, + ) + if err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric( + statDatabase["numbackends"], + prometheus.GaugeValue, + numBackends, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["xact_commit"], + prometheus.CounterValue, + xactCommit, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["xact_rollback"], + prometheus.CounterValue, + xactRollback, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["blks_read"], + prometheus.CounterValue, + blksRead, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["blks_hit"], + prometheus.CounterValue, + blksHit, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["tup_returned"], + prometheus.CounterValue, + tupReturned, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["tup_fetched"], + prometheus.CounterValue, + tupFetched, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["tup_inserted"], + prometheus.CounterValue, + tupInserted, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["tup_updated"], + prometheus.CounterValue, + tupUpdated, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["tup_deleted"], + prometheus.CounterValue, + tupDeleted, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["conflicts"], + prometheus.CounterValue, + conflicts, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["temp_files"], + prometheus.CounterValue, + tempFiles, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["temp_bytes"], + prometheus.CounterValue, + tempBytes, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["deadlocks"], + prometheus.CounterValue, + deadlocks, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["blk_read_time"], + prometheus.CounterValue, + blkReadTime, + datid, + datname, + ) + + ch <- prometheus.MustNewConstMetric( + statDatabase["blk_write_time"], + prometheus.CounterValue, + blkWriteTime, + datid, + datname, + ) + + if statsReset.Valid { + ch <- prometheus.MustNewConstMetric( + statDatabase["stats_reset"], + prometheus.CounterValue, + float64(statsReset.Time.Unix()), + datid, + datname, + ) + } else { + ch <- prometheus.MustNewConstMetric( + statDatabase["stats_reset"], + prometheus.CounterValue, + 0, + datid, + datname, + ) + } + } + return nil +} From ad8b5608f8f48d11740099c021116338fcedae83 Mon Sep 17 00:00:00 2001 From: Ildar Valiullin Date: Thu, 1 Sep 2022 12:30:06 +0300 Subject: [PATCH 058/228] extended /probe path metrics Signed-off-by: Ildar Valiullin --- cmd/postgres_exporter/probe.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go index 7b2154319..6c9a46bfc 100644 --- a/cmd/postgres_exporter/probe.go +++ b/cmd/postgres_exporter/probe.go @@ -78,6 +78,23 @@ func handleProbe(logger log.Logger) http.HandlerFunc { registry.MustRegister(probeSuccessGauge) registry.MustRegister(probeDurationGauge) + opts := []ExporterOpt{ + DisableDefaultMetrics(*disableDefaultMetrics), + DisableSettingsMetrics(*disableSettingsMetrics), + AutoDiscoverDatabases(*autoDiscoverDatabases), + WithUserQueriesPath(*queriesPath), + WithConstantLabels(*constantLabelsList), + ExcludeDatabases(*excludeDatabases), + IncludeDatabases(*includeDatabases), + } + + dsns := []string{dsn.GetConnectionString()} + exporter := NewExporter(dsns, opts...) + defer func() { + exporter.servers.Close() + }() + registry.MustRegister(exporter) + // Run the probe pc, err := collector.NewProbeCollector(tl, registry, dsn) if err != nil { From 8268b7e6ffe698b6baa7588098636d10bb12ca6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 17:05:04 +0000 Subject: [PATCH 059/228] Bump github.com/lib/pq from 1.10.6 to 1.10.7 Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.6 to 1.10.7. - [Release notes](https://github.com/lib/pq/releases) - [Commits](https://github.com/lib/pq/compare/v1.10.6...v1.10.7) --- updated-dependencies: - dependency-name: github.com/lib/pq dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5f5d6195f..f8a0c26f0 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 - github.com/lib/pq v1.10.6 + github.com/lib/pq v1.10.7 github.com/prometheus/client_golang v1.13.0 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.37.0 diff --git a/go.sum b/go.sum index fcd14c6b4..631253203 100644 --- a/go.sum +++ b/go.sum @@ -155,8 +155,8 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= -github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= From 6937685907f9f4eeac4a1506a5961c8b90b98ad3 Mon Sep 17 00:00:00 2001 From: cezmunsta Date: Mon, 15 Aug 2022 11:01:41 +0100 Subject: [PATCH 060/228] Capture usename and application_name for pg_stat_activity It is necessary to be able to exclude backups from long-running transaction alerts, as they are to be expected. With the current pg_stat_activity metric there is no ability to filter out specific users or application names. Resolves #668 Signed-off-by: cezmunsta --- cmd/postgres_exporter/postgres_exporter.go | 2 ++ cmd/postgres_exporter/queries.go | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index af973d5d5..53618567c 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -284,6 +284,8 @@ var builtinMetricMaps = map[string]intermediateMetricMap{ map[string]ColumnMapping{ "datname": {LABEL, "Name of this database", nil, nil}, "state": {LABEL, "connection state", nil, semver.MustParseRange(">=9.2.0")}, + "usename": {LABEL, "connection usename", nil, nil}, + "application_name": {LABEL, "connection application_name", nil, nil}, "count": {GAUGE, "number of connections in this state", nil, nil}, "max_tx_duration": {GAUGE, "max duration in seconds any active transaction has been running", nil, nil}, }, diff --git a/cmd/postgres_exporter/queries.go b/cmd/postgres_exporter/queries.go index b17420d28..14c14b4f8 100644 --- a/cmd/postgres_exporter/queries.go +++ b/cmd/postgres_exporter/queries.go @@ -137,6 +137,8 @@ var queryOverrides = map[string][]OverrideQuery{ SELECT pg_database.datname, tmp.state, + tmp2.usename, + tmp2.application_name, COALESCE(count,0) as count, COALESCE(max_tx_duration,0) as max_tx_duration FROM @@ -153,9 +155,11 @@ var queryOverrides = map[string][]OverrideQuery{ SELECT datname, state, + usename, + application_name, count(*) AS count, MAX(EXTRACT(EPOCH FROM now() - xact_start))::float AS max_tx_duration - FROM pg_stat_activity GROUP BY datname,state) AS tmp2 + FROM pg_stat_activity GROUP BY datname,state,usename,application_name) AS tmp2 ON tmp.state = tmp2.state AND pg_database.datname = tmp2.datname `, }, @@ -165,9 +169,11 @@ var queryOverrides = map[string][]OverrideQuery{ SELECT datname, 'unknown' AS state, + usename, + application_name, COALESCE(count(*),0) AS count, COALESCE(MAX(EXTRACT(EPOCH FROM now() - xact_start))::float,0) AS max_tx_duration - FROM pg_stat_activity GROUP BY datname + FROM pg_stat_activity GROUP BY datname,usename,application_name `, }, }, From d9ac4be429756c253e83d171c2c5e672d7d4e3d8 Mon Sep 17 00:00:00 2001 From: cezmunsta Date: Fri, 19 Aug 2022 09:08:32 +0100 Subject: [PATCH 061/228] Fixed formatting Signed-off-by: cezmunsta --- cmd/postgres_exporter/postgres_exporter.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index 53618567c..40f9681d7 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -282,12 +282,12 @@ var builtinMetricMaps = map[string]intermediateMetricMap{ }, "pg_stat_activity": { map[string]ColumnMapping{ - "datname": {LABEL, "Name of this database", nil, nil}, - "state": {LABEL, "connection state", nil, semver.MustParseRange(">=9.2.0")}, + "datname": {LABEL, "Name of this database", nil, nil}, + "state": {LABEL, "connection state", nil, semver.MustParseRange(">=9.2.0")}, "usename": {LABEL, "connection usename", nil, nil}, "application_name": {LABEL, "connection application_name", nil, nil}, - "count": {GAUGE, "number of connections in this state", nil, nil}, - "max_tx_duration": {GAUGE, "max duration in seconds any active transaction has been running", nil, nil}, + "count": {GAUGE, "number of connections in this state", nil, nil}, + "max_tx_duration": {GAUGE, "max duration in seconds any active transaction has been running", nil, nil}, }, true, 0, From fc2e8f083714c11c6e9468e0b95b76726d61f8cc Mon Sep 17 00:00:00 2001 From: prombot Date: Tue, 4 Oct 2022 17:59:51 +0000 Subject: [PATCH 062/228] Update common Prometheus files Signed-off-by: prombot --- Makefile.common | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile.common b/Makefile.common index 6c8e3e219..7642c4485 100644 --- a/Makefile.common +++ b/Makefile.common @@ -58,16 +58,19 @@ endif PROMU_VERSION ?= 0.13.0 PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz +SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.45.2 +GOLANGCI_LINT_VERSION ?= v1.49.0 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) # If we're in CI and there is an Actions file, that means the linter # is being run in Actions, so we don't need to run it here. - ifeq (,$(CIRCLE_JOB)) + ifneq (,$(SKIP_GOLANGCI_LINT)) + GOLANGCI_LINT := + else ifeq (,$(CIRCLE_JOB)) GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint else ifeq (,$(wildcard .github/workflows/golangci-lint.yml)) GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint From 14c9d0370f52fdc2d69cba567b1562307dc066b5 Mon Sep 17 00:00:00 2001 From: Sergey Morozov <38383507+ken3122@users.noreply.github.com> Date: Sun, 9 Oct 2022 01:50:45 +0600 Subject: [PATCH 063/228] 4kB size added for postgres with 4kB block_size Signed-off-by: Sergey Morozov <38383507+ken3122@users.noreply.github.com> --- cmd/postgres_exporter/pg_setting.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/pg_setting.go b/cmd/postgres_exporter/pg_setting.go index bfe4c6c52..28a08a70b 100644 --- a/cmd/postgres_exporter/pg_setting.go +++ b/cmd/postgres_exporter/pg_setting.go @@ -129,7 +129,7 @@ func (s *pgSetting) normaliseUnit() (val float64, unit string, err error) { return case "ms", "s", "min", "h", "d": unit = "seconds" - case "B", "kB", "MB", "GB", "TB", "8kB", "16kB", "32kB", "16MB", "32MB", "64MB": + case "B", "kB", "MB", "GB", "TB", "4kB", "8kB", "16kB", "32kB", "16MB", "32MB", "64MB": unit = "bytes" default: err = fmt.Errorf("Unknown unit for runtime variable: %q", s.unit) @@ -158,6 +158,8 @@ func (s *pgSetting) normaliseUnit() (val float64, unit string, err error) { val *= math.Pow(2, 30) case "TB": val *= math.Pow(2, 40) + case "4kB": + val *= math.Pow(2, 12) case "8kB": val *= math.Pow(2, 13) case "16kB": From b10a942f40e6e41192afd5493d0f09a1a1032922 Mon Sep 17 00:00:00 2001 From: Luckz <224748+Luckz@users.noreply.github.com> Date: Sun, 6 Nov 2022 16:24:43 +0100 Subject: [PATCH 064/228] Correct additional typo in README.md Signed-off-by: Luckz <224748+Luckz@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6af134175..2fc0ad8bc 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ docker run \ ## Multi-Target Support (BETA) **This Feature is in beta and may require changes in future releases. Feedback is welcome.** -This exporter supports the [multi-target pattern](https://prometheus.io/docs/guides/multi-target-exporter/). This allows running a single instance of this exporter for multiple postgres targets. Using the multi-target funcationality of this exporter is **optional** and meant for cases where it is impossible to install the exporter as a sidecar, for example SaaS-managed services. +This exporter supports the [multi-target pattern](https://prometheus.io/docs/guides/multi-target-exporter/). This allows running a single instance of this exporter for multiple postgres targets. Using the multi-target functionality of this exporter is **optional** and meant for cases where it is impossible to install the exporter as a sidecar, for example SaaS-managed services. To use the multi-target functionality, send an http request to the endpoint `/probe?target=foo:5432` where target is set to the DSN of the postgres instance to scrape metrics from. From 5fcceb4105830b9642670729af55b709465bde5b Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Thu, 24 Nov 2022 14:02:37 +0100 Subject: [PATCH 065/228] Set gauge to 1 when collector is successful Signed-off-by: Julien Pivotto --- cmd/postgres_exporter/probe.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go index 6c9a46bfc..28d1395ee 100644 --- a/cmd/postgres_exporter/probe.go +++ b/cmd/postgres_exporter/probe.go @@ -114,6 +114,7 @@ func handleProbe(logger log.Logger) http.HandlerFunc { duration := time.Since(start).Seconds() probeDurationGauge.Set(duration) + probeSuccessGauge.Set(1) // TODO check success, etc h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{}) From c8991de2239d4cd01337d454c24dc26d58f8680f Mon Sep 17 00:00:00 2001 From: prombot Date: Tue, 13 Dec 2022 17:51:01 +0000 Subject: [PATCH 066/228] Update common Prometheus files Signed-off-by: prombot --- Makefile.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.common b/Makefile.common index 7642c4485..e358db69c 100644 --- a/Makefile.common +++ b/Makefile.common @@ -55,7 +55,7 @@ ifneq ($(shell which gotestsum),) endif endif -PROMU_VERSION ?= 0.13.0 +PROMU_VERSION ?= 0.14.0 PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz SKIP_GOLANGCI_LINT := From 76223cdda85972215fd99d4d6214019796faf9ec Mon Sep 17 00:00:00 2001 From: Kurtis Bass Date: Wed, 14 Dec 2022 14:30:13 -0500 Subject: [PATCH 067/228] probe: clean-up database connection after probe to prevent connection leak Signed-off-by: Kurtis Bass --- cmd/postgres_exporter/probe.go | 3 +++ collector/probe.go | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go index 28d1395ee..167e827c2 100644 --- a/cmd/postgres_exporter/probe.go +++ b/cmd/postgres_exporter/probe.go @@ -104,6 +104,9 @@ func handleProbe(logger log.Logger) http.HandlerFunc { return } + // Cleanup underlying connections to prevent connection leaks + defer pc.Close() + // TODO(@sysadmind): Remove the registry.MustRegister() call below and instead handle the collection here. That will allow // for the passing of context, handling of timeouts, and more control over the collection. // The current NewProbeCollector() implementation relies on the MustNewConstMetric() call to create the metrics which is not diff --git a/collector/probe.go b/collector/probe.go index 37cb151b9..c8bf8ee48 100644 --- a/collector/probe.go +++ b/collector/probe.go @@ -83,3 +83,7 @@ func (pc *ProbeCollector) Collect(ch chan<- prometheus.Metric) { } wg.Wait() } + +func (pc *ProbeCollector) Close() error { + return pc.db.Close() +} From dc1c19efd4012f7281d87c31c9177b3ab839d35b Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Thu, 24 Nov 2022 14:02:37 +0100 Subject: [PATCH 068/228] Set gauge to 1 when collector is successful Signed-off-by: Julien Pivotto Signed-off-by: Khiem Doan --- cmd/postgres_exporter/probe.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go index 6c9a46bfc..28d1395ee 100644 --- a/cmd/postgres_exporter/probe.go +++ b/cmd/postgres_exporter/probe.go @@ -114,6 +114,7 @@ func handleProbe(logger log.Logger) http.HandlerFunc { duration := time.Since(start).Seconds() probeDurationGauge.Set(duration) + probeSuccessGauge.Set(1) // TODO check success, etc h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{}) From 3b4534774905234ca725b4b3cd92323ea19a7e30 Mon Sep 17 00:00:00 2001 From: Khiem Doan Date: Tue, 27 Dec 2022 08:56:45 +0700 Subject: [PATCH 069/228] Add postgres 15 for CI test Signed-off-by: Khiem Doan --- .circleci/config.yml | 1 + README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ae168f04e..bcf199d1a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -61,6 +61,7 @@ workflows: - circleci/postgres:12 - circleci/postgres:13 - cimg/postgres:14.1 + - cimg/postgres:15.1 - prometheus/build: name: build parallelism: 3 diff --git a/README.md b/README.md index 2fc0ad8bc..dcaaed019 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Prometheus exporter for PostgreSQL server metrics. -CI Tested PostgreSQL versions: `9.4`, `9.5`, `9.6`, `10`, `11`, `12`, `13`, `14` +CI Tested PostgreSQL versions: `9.4`, `9.5`, `9.6`, `10`, `11`, `12`, `13`, `14`, `15` ## Quick Start This package is available for Docker: From 045f24fd63ba0d4066210a3df2128406c887d1c1 Mon Sep 17 00:00:00 2001 From: Khiem Doan Date: Tue, 27 Dec 2022 08:56:45 +0700 Subject: [PATCH 070/228] Add postgres 15 for CI test Signed-off-by: Khiem Doan --- .circleci/config.yml | 1 + README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ae168f04e..bcf199d1a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -61,6 +61,7 @@ workflows: - circleci/postgres:12 - circleci/postgres:13 - cimg/postgres:14.1 + - cimg/postgres:15.1 - prometheus/build: name: build parallelism: 3 diff --git a/README.md b/README.md index 2fc0ad8bc..dcaaed019 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Prometheus exporter for PostgreSQL server metrics. -CI Tested PostgreSQL versions: `9.4`, `9.5`, `9.6`, `10`, `11`, `12`, `13`, `14` +CI Tested PostgreSQL versions: `9.4`, `9.5`, `9.6`, `10`, `11`, `12`, `13`, `14`, `15` ## Quick Start This package is available for Docker: From 8ff0e5aa705c8febc0495d7f09cb521a2b84bb51 Mon Sep 17 00:00:00 2001 From: Oleksandr Mysyura Date: Wed, 4 Jan 2023 11:50:13 +0200 Subject: [PATCH 071/228] New unit value 64kB Signed-off-by: Oleksandr Mysyura --- cmd/postgres_exporter/pg_setting.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/pg_setting.go b/cmd/postgres_exporter/pg_setting.go index 28a08a70b..8a45ec945 100644 --- a/cmd/postgres_exporter/pg_setting.go +++ b/cmd/postgres_exporter/pg_setting.go @@ -129,7 +129,7 @@ func (s *pgSetting) normaliseUnit() (val float64, unit string, err error) { return case "ms", "s", "min", "h", "d": unit = "seconds" - case "B", "kB", "MB", "GB", "TB", "4kB", "8kB", "16kB", "32kB", "16MB", "32MB", "64MB": + case "B", "kB", "MB", "GB", "TB", "4kB", "8kB", "16kB", "32kB", "64kB", "16MB", "32MB", "64MB": unit = "bytes" default: err = fmt.Errorf("Unknown unit for runtime variable: %q", s.unit) @@ -166,6 +166,8 @@ func (s *pgSetting) normaliseUnit() (val float64, unit string, err error) { val *= math.Pow(2, 14) case "32kB": val *= math.Pow(2, 15) + case "64kB": + val *= math.Pow(2, 16) case "16MB": val *= math.Pow(2, 24) case "32MB": From 29cf7eb61c7fc100b17f9402221260fad254cb41 Mon Sep 17 00:00:00 2001 From: prombot Date: Mon, 23 Jan 2023 17:50:28 +0000 Subject: [PATCH 072/228] Update common Prometheus files Signed-off-by: prombot --- .yamllint | 6 +----- Makefile.common | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.yamllint b/.yamllint index 3878a31d3..19552574b 100644 --- a/.yamllint +++ b/.yamllint @@ -21,8 +21,4 @@ rules: line-length: disable truthy: ignore: | - .github/workflows/codeql-analysis.yml - .github/workflows/funcbench.yml - .github/workflows/fuzzing.yml - .github/workflows/prombench.yml - .github/workflows/golangci-lint.yml + .github/workflows/*.yml diff --git a/Makefile.common b/Makefile.common index e358db69c..1985fcdeb 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.49.0 +GOLANGCI_LINT_VERSION ?= v1.50.1 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) From fc264d0ab025756d13ee467bdc7a23a304715155 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Tue, 24 Jan 2023 17:57:31 +0100 Subject: [PATCH 073/228] Update exporter-toolkit Update to the latest exporter-toolkit * Enables multi-listener and systemd socket activation. * Bump Go to 1.19. * Remove `PG_EXPORTER_WEB_LISTEN_ADDRESS` env var because this is now a repeatable flag. Signed-off-by: SuperQ --- .circleci/config.yml | 4 +- .promu.yml | 2 +- README.md | 3 - cmd/postgres_exporter/main.go | 10 +- go.mod | 17 +- go.sum | 288 ++++++++++++++++++++++++++++++++-- 6 files changed, 292 insertions(+), 32 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ae168f04e..3d7125a05 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,7 +8,7 @@ executors: # This must match .promu.yml. golang: docker: - - image: cimg/go:1.18 + - image: cimg/go:1.19 jobs: test: @@ -22,7 +22,7 @@ jobs: integration: docker: - - image: cimg/go:1.18 + - image: cimg/go:1.19 - image: << parameters.postgres_image >> environment: POSTGRES_DB: circle_test diff --git a/.promu.yml b/.promu.yml index d63d0444d..8f39e7865 100644 --- a/.promu.yml +++ b/.promu.yml @@ -1,6 +1,6 @@ go: # This must match .circle/config.yml. - version: 1.18 + version: 1.19 repository: path: github.com/prometheus-community/postgres_exporter build: diff --git a/README.md b/README.md index c7cb46212..2e1cf6e04 100644 --- a/README.md +++ b/README.md @@ -152,9 +152,6 @@ The following environment variables configure the exporter: * `DATA_SOURCE_PASS_FILE` The same as above but reads the password from a file. -* `PG_EXPORTER_WEB_LISTEN_ADDRESS` - Address to listen on for web interface and telemetry. Default is `:9187`. - * `PG_EXPORTER_WEB_TELEMETRY_PATH` Path under which to expose metrics. Default is `/metrics`. diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 8759f4372..6936226c8 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -27,7 +27,7 @@ import ( "github.com/prometheus/common/promlog/flag" "github.com/prometheus/common/version" "github.com/prometheus/exporter-toolkit/web" - webflag "github.com/prometheus/exporter-toolkit/web/kingpinflag" + "github.com/prometheus/exporter-toolkit/web/kingpinflag" "gopkg.in/alecthomas/kingpin.v2" ) @@ -37,8 +37,7 @@ var ( } configFile = kingpin.Flag("config.file", "Postgres exporter configuration file.").Default("postgres_exporter.yml").String() - listenAddress = kingpin.Flag("web.listen-address", "Address to listen on for web interface and telemetry.").Default(":9187").Envar("PG_EXPORTER_WEB_LISTEN_ADDRESS").String() - webConfig = webflag.AddFlags(kingpin.CommandLine) + webConfig = kingpinflag.AddFlags(kingpin.CommandLine, ":9187") metricPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").Envar("PG_EXPORTER_WEB_TELEMETRY_PATH").String() disableDefaultMetrics = kingpin.Flag("disable-default-metrics", "Do not include default metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_DEFAULT_METRICS").Bool() disableSettingsMetrics = kingpin.Flag("disable-settings-metrics", "Do not include pg_settings metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_SETTINGS_METRICS").Bool() @@ -146,9 +145,8 @@ func main() { http.HandleFunc("/probe", handleProbe(logger)) - level.Info(logger).Log("msg", "Listening on address", "address", *listenAddress) - srv := &http.Server{Addr: *listenAddress} - if err := web.ListenAndServe(srv, *webConfig, logger); err != nil { + srv := &http.Server{} + if err := web.ListenAndServe(srv, webConfig, logger); err != nil { level.Error(logger).Log("msg", "Error running HTTP server", "err", err) os.Exit(1) } diff --git a/go.mod b/go.mod index f8a0c26f0..4ce94a3ee 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/prometheus/client_golang v1.13.0 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.37.0 - github.com/prometheus/exporter-toolkit v0.7.1 + github.com/prometheus/exporter-toolkit v0.8.2 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 @@ -18,9 +18,10 @@ 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/coreos/go-systemd/v22 v22.4.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/jpillora/backoff v1.0.0 // indirect @@ -28,13 +29,13 @@ require ( github.com/kr/text v0.1.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/procfs v0.8.0 // indirect - golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect - golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect - golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect - golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect + golang.org/x/crypto v0.0.0-20221012134737-56aed061732a // indirect + golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect + golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect golang.org/x/text v0.3.7 // indirect - google.golang.org/appengine v1.6.6 // indirect + google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect ) diff --git a/go.sum b/go.sum index 631253203..00ed16fe6 100644 --- a/go.sum +++ b/go.sum @@ -13,14 +13,36 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -30,16 +52,20 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 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-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -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/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -47,6 +73,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -55,13 +83,30 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU= +github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -77,6 +122,7 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -89,6 +135,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -104,8 +152,10 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -115,13 +165,19 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -129,12 +185,29 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -169,7 +242,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -188,12 +260,11 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/exporter-toolkit v0.7.1 h1:c6RXaK8xBVercEeUQ4tRNL8UGWzDHfvj9dseo1FcK1Y= -github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g= +github.com/prometheus/exporter-toolkit v0.8.2 h1:sbJAfBXQFkG6sUkbwBun8MNdzW9+wd5YfPYofbmj0YM= +github.com/prometheus/exporter-toolkit v0.8.2/go.mod h1:00shzmJL7KxcsabLWcONwpyNEuWhREOnFqZW7vadFS0= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= @@ -201,32 +272,45 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg= +golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -249,6 +333,8 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -257,6 +343,9 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -285,19 +374,48 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -306,8 +424,12 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -339,15 +461,44 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -355,6 +506,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -401,10 +554,24 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -421,13 +588,37 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -451,12 +642,61 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -469,6 +709,26 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -481,6 +741,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= @@ -493,11 +755,13 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +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= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From b1e72a981bef0e1a3e33c1514374acdd3a5bf34a Mon Sep 17 00:00:00 2001 From: SuperQ Date: Tue, 24 Jan 2023 18:18:17 +0100 Subject: [PATCH 074/228] go fmt Signed-off-by: SuperQ --- cmd/postgres_exporter/postgres_exporter.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index af973d5d5..fea2e2b26 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -212,15 +212,15 @@ var builtinMetricMaps = map[string]intermediateMetricMap{ }, "pg_stat_replication": { map[string]ColumnMapping{ - "procpid": {DISCARD, "Process ID of a WAL sender process", nil, semver.MustParseRange("<9.2.0")}, - "pid": {DISCARD, "Process ID of a WAL sender process", nil, semver.MustParseRange(">=9.2.0")}, - "usesysid": {DISCARD, "OID of the user logged into this WAL sender process", nil, nil}, - "usename": {DISCARD, "Name of the user logged into this WAL sender process", nil, nil}, - "application_name": {LABEL, "Name of the application that is connected to this WAL sender", nil, nil}, - "client_addr": {LABEL, "IP address of the client connected to this WAL sender. If this field is null, it indicates that the client is connected via a Unix socket on the server machine.", nil, nil}, - "client_hostname": {DISCARD, "Host name of the connected client, as reported by a reverse DNS lookup of client_addr. This field will only be non-null for IP connections, and only when log_hostname is enabled.", nil, nil}, - "client_port": {DISCARD, "TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used", nil, nil}, - "backend_start": {DISCARD, "with time zone Time when this process was started, i.e., when the client connected to this WAL sender", nil, nil}, + "procpid": {DISCARD, "Process ID of a WAL sender process", nil, semver.MustParseRange("<9.2.0")}, + "pid": {DISCARD, "Process ID of a WAL sender process", nil, semver.MustParseRange(">=9.2.0")}, + "usesysid": {DISCARD, "OID of the user logged into this WAL sender process", nil, nil}, + "usename": {DISCARD, "Name of the user logged into this WAL sender process", nil, nil}, + "application_name": {LABEL, "Name of the application that is connected to this WAL sender", nil, nil}, + "client_addr": {LABEL, "IP address of the client connected to this WAL sender. If this field is null, it indicates that the client is connected via a Unix socket on the server machine.", nil, nil}, + "client_hostname": {DISCARD, "Host name of the connected client, as reported by a reverse DNS lookup of client_addr. This field will only be non-null for IP connections, and only when log_hostname is enabled.", nil, nil}, + "client_port": {DISCARD, "TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used", nil, nil}, + "backend_start": {DISCARD, "with time zone Time when this process was started, i.e., when the client connected to this WAL sender", nil, nil}, "backend_xmin": {DISCARD, "The current backend's xmin horizon.", nil, nil}, "state": {LABEL, "Current WAL sender state", nil, nil}, "sent_location": {DISCARD, "Last transaction log position sent on this connection", nil, semver.MustParseRange("<10.0.0")}, From 300750001c2957386ee3c3af3b35ef3fe79393b6 Mon Sep 17 00:00:00 2001 From: Zachary Caldarola Date: Tue, 24 Jan 2023 14:45:31 -0500 Subject: [PATCH 075/228] adding codified functionality for logical replication metrics Signed-off-by: Zachary Caldarola --- collector/pg_replication_slots.go | 72 +++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 collector/pg_replication_slots.go diff --git a/collector/pg_replication_slots.go b/collector/pg_replication_slots.go new file mode 100644 index 000000000..1da841e3c --- /dev/null +++ b/collector/pg_replication_slots.go @@ -0,0 +1,72 @@ +// Copyright 2022 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 collector + +import ( + "context" + "database/sql" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +func init() { + registerCollector("replication_slot", defaultEnabled, NewPGReplicationSlotCollector) +} + +type PGReplicationSlotCollector struct { + log log.Logger +} + +func NewPGReplicationSlotCollector(logger log.Logger) (Collector, error) { + return &PGReplicationSlotCollector{log: logger}, nil +} + +var pgReplicationSlot = map[string]*prometheus.Desc{ + "lsn_distance": prometheus.NewDesc( + "pg_replication_slot_lsn_distance", + "Disk space used by the database", + []string{"slot_name"}, nil, + ), +} + +func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { + rows, err := db.QueryContext(ctx, + `SELECT + slot_name, + (pg_current_wal_lsn() - confirmed_flush_lsn) AS lsn_distance + FROM + pg_replication_slots;`) + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var slot_name string + var size int64 + if err := rows.Scan(&slot_name, &size); err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric( + pgReplicationSlot["size_bytes"], + prometheus.GaugeValue, float64(size), slot_name, + ) + } + if err := rows.Err(); err != nil { + return err + } + return nil +} From e198f6fabe5feead720c2a5c21faaa68a72121f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Jan 2023 08:32:54 +0000 Subject: [PATCH 076/228] Bump github.com/prometheus/client_golang from 1.13.0 to 1.14.0 Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.13.0 to 1.14.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.13.0...v1.14.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 4ce94a3ee..4f8181155 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,8 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 github.com/lib/pq v1.10.7 - github.com/prometheus/client_golang v1.13.0 - github.com/prometheus/client_model v0.2.0 + github.com/prometheus/client_golang v1.14.0 + github.com/prometheus/client_model v0.3.0 github.com/prometheus/common v0.37.0 github.com/prometheus/exporter-toolkit v0.8.2 gopkg.in/alecthomas/kingpin.v2 v2.2.6 diff --git a/go.sum b/go.sum index 00ed16fe6..c0228730d 100644 --- a/go.sum +++ b/go.sum @@ -250,13 +250,15 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= From 61492f6931fa7e5863e63511099667573cc40f2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Jan 2023 13:16:35 +0000 Subject: [PATCH 077/228] Bump github.com/prometheus/common from 0.37.0 to 0.39.0 Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.37.0 to 0.39.0. - [Release notes](https://github.com/prometheus/common/releases) - [Commits](https://github.com/prometheus/common/compare/v0.37.0...v0.39.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 12 ++++++------ go.sum | 28 ++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 4f8181155..7d21dc4e2 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/lib/pq v1.10.7 github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_model v0.3.0 - github.com/prometheus/common v0.37.0 + github.com/prometheus/common v0.39.0 github.com/prometheus/exporter-toolkit v0.8.2 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c @@ -27,15 +27,15 @@ require ( github.com/jpillora/backoff v1.0.0 // indirect github.com/kr/pretty v0.2.1 // indirect github.com/kr/text v0.1.0 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/prometheus/procfs v0.8.0 // indirect golang.org/x/crypto v0.0.0-20221012134737-56aed061732a // indirect - golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect - golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect + golang.org/x/net v0.4.0 // indirect + golang.org/x/oauth2 v0.3.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/sys v0.3.0 // indirect + golang.org/x/text v0.5.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect ) diff --git a/go.sum b/go.sum index c0228730d..5a4377b6b 100644 --- a/go.sum +++ b/go.sum @@ -40,6 +40,7 @@ cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6m cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= @@ -230,8 +231,9 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -263,8 +265,9 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= +github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/exporter-toolkit v0.8.2 h1:sbJAfBXQFkG6sUkbwBun8MNdzW9+wd5YfPYofbmj0YM= github.com/prometheus/exporter-toolkit v0.8.2/go.mod h1:00shzmJL7KxcsabLWcONwpyNEuWhREOnFqZW7vadFS0= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -297,6 +300,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -311,6 +315,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg= golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -348,6 +353,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -394,8 +400,11 @@ golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -416,8 +425,9 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA= golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8= +golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -430,6 +440,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -499,10 +510,13 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -511,8 +525,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -567,6 +582,7 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 9b13780d142ba5b6abf1dca84504170137acb970 Mon Sep 17 00:00:00 2001 From: Zachary Caldarola Date: Wed, 25 Jan 2023 11:15:24 -0500 Subject: [PATCH 078/228] addressing comments Signed-off-by: Zachary Caldarola --- collector/pg_replication_slots.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/collector/pg_replication_slots.go b/collector/pg_replication_slots.go index 1da841e3c..c21d7f411 100644 --- a/collector/pg_replication_slots.go +++ b/collector/pg_replication_slots.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Prometheus Authors +// Copyright 2023 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 @@ -34,9 +34,14 @@ func NewPGReplicationSlotCollector(logger log.Logger) (Collector, error) { } var pgReplicationSlot = map[string]*prometheus.Desc{ - "lsn_distance": prometheus.NewDesc( - "pg_replication_slot_lsn_distance", - "Disk space used by the database", + "current_wal_lsn": prometheus.NewDesc( + "pg_replication_slot_current_wal_lsn", + "current wal lsn value", + []string{"slot_name"}, nil, + ), + "confirmed_flush_lsn": prometheus.NewDesc( + "pg_replication_slot_confirmed_flush_lsn", + "last lsn confirmed flushed to the replication slot", []string{"slot_name"}, nil, ), } @@ -45,7 +50,8 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha rows, err := db.QueryContext(ctx, `SELECT slot_name, - (pg_current_wal_lsn() - confirmed_flush_lsn) AS lsn_distance + pg_current_wal_lsn() AS current_wal_lsn, + confirmed_flush_lsn FROM pg_replication_slots;`) if err != nil { @@ -55,14 +61,19 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha for rows.Next() { var slot_name string - var size int64 - if err := rows.Scan(&slot_name, &size); err != nil { + var wal_lsn int64 + var flush_lsn int64 + if err := rows.Scan(&slot_name, &wal_lsn, &flush_lsn); err != nil { return err } ch <- prometheus.MustNewConstMetric( - pgReplicationSlot["size_bytes"], - prometheus.GaugeValue, float64(size), slot_name, + pgReplicationSlot["current_wal_lsn"], + prometheus.GaugeValue, float64(wal_lsn), slot_name, + ) + ch <- prometheus.MustNewConstMetric( + pgReplicationSlot["confirmed_flush_lsn"], + prometheus.GaugeValue, float64(flush_lsn), slot_name, ) } if err := rows.Err(); err != nil { From 600ad185cf47aa1180dbb073d55c22b6caf3587c Mon Sep 17 00:00:00 2001 From: Zachary Caldarola Date: Sat, 28 Jan 2023 17:05:45 -0500 Subject: [PATCH 079/228] more comments Signed-off-by: Zachary Caldarola --- ...lication_slots.go => replication_slots.go} | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) rename collector/{pg_replication_slots.go => replication_slots.go} (74%) diff --git a/collector/pg_replication_slots.go b/collector/replication_slots.go similarity index 74% rename from collector/pg_replication_slots.go rename to collector/replication_slots.go index c21d7f411..e1c2f0a8d 100644 --- a/collector/pg_replication_slots.go +++ b/collector/replication_slots.go @@ -44,16 +44,22 @@ var pgReplicationSlot = map[string]*prometheus.Desc{ "last lsn confirmed flushed to the replication slot", []string{"slot_name"}, nil, ), + "is_active": prometheus.NewDesc( + "pg_replication_slot_is_active", + "last lsn confirmed flushed to the replication slot", + []string{"slot_name"}, nil, + ), } func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { rows, err := db.QueryContext(ctx, `SELECT slot_name, - pg_current_wal_lsn() AS current_wal_lsn, - confirmed_flush_lsn - FROM - pg_replication_slots;`) + pg_current_wal_lsn() - '0/0' AS current_wal_lsn, + coalesce(confirmed_flush_lsn, '0/0') - '0/0', + active + FROM + pg_replication_slots;`) if err != nil { return err } @@ -63,7 +69,8 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha var slot_name string var wal_lsn int64 var flush_lsn int64 - if err := rows.Scan(&slot_name, &wal_lsn, &flush_lsn); err != nil { + var is_active int + if err := rows.Scan(&slot_name, &wal_lsn, &flush_lsn, &is_active); err != nil { return err } @@ -71,9 +78,15 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha pgReplicationSlot["current_wal_lsn"], prometheus.GaugeValue, float64(wal_lsn), slot_name, ) + if (is_active == 1) { + ch <- prometheus.MustNewConstMetric( + pgReplicationSlot["confirmed_flush_lsn"], + prometheus.GaugeValue, float64(flush_lsn), slot_name, + ) + } ch <- prometheus.MustNewConstMetric( - pgReplicationSlot["confirmed_flush_lsn"], - prometheus.GaugeValue, float64(flush_lsn), slot_name, + pgReplicationSlot["is_active"], + prometheus.GaugeValue, int(flush_lsn), slot_name, ) } if err := rows.Err(); err != nil { From 1ec69c9168c042314b8ef67360ba8e18f0e4fd84 Mon Sep 17 00:00:00 2001 From: Zachary Caldarola Date: Sat, 28 Jan 2023 17:37:41 -0500 Subject: [PATCH 080/228] fmt Signed-off-by: Zachary Caldarola --- collector/replication_slots.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collector/replication_slots.go b/collector/replication_slots.go index e1c2f0a8d..8705f69c1 100644 --- a/collector/replication_slots.go +++ b/collector/replication_slots.go @@ -78,7 +78,7 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha pgReplicationSlot["current_wal_lsn"], prometheus.GaugeValue, float64(wal_lsn), slot_name, ) - if (is_active == 1) { + if is_active == 1 { ch <- prometheus.MustNewConstMetric( pgReplicationSlot["confirmed_flush_lsn"], prometheus.GaugeValue, float64(flush_lsn), slot_name, From f3952f941b833f8626330d64ea885f3086b1f3a1 Mon Sep 17 00:00:00 2001 From: Zachary Caldarola Date: Sat, 28 Jan 2023 17:40:46 -0500 Subject: [PATCH 081/228] typing Signed-off-by: Zachary Caldarola --- collector/replication_slots.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collector/replication_slots.go b/collector/replication_slots.go index 8705f69c1..129b2efd5 100644 --- a/collector/replication_slots.go +++ b/collector/replication_slots.go @@ -86,7 +86,7 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha } ch <- prometheus.MustNewConstMetric( pgReplicationSlot["is_active"], - prometheus.GaugeValue, int(flush_lsn), slot_name, + prometheus.GaugeValue, float64(flush_lsn), slot_name, ) } if err := rows.Err(); err != nil { From 076eb2c3f54bf6d95ad59fcb63a96f5a29e31636 Mon Sep 17 00:00:00 2001 From: Zachary Caldarola Date: Sat, 28 Jan 2023 18:45:48 -0500 Subject: [PATCH 082/228] fmt Signed-off-by: Zachary Caldarola --- collector/replication_slots.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collector/replication_slots.go b/collector/replication_slots.go index 129b2efd5..224db3ccf 100644 --- a/collector/replication_slots.go +++ b/collector/replication_slots.go @@ -69,7 +69,7 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha var slot_name string var wal_lsn int64 var flush_lsn int64 - var is_active int + var is_active int64 if err := rows.Scan(&slot_name, &wal_lsn, &flush_lsn, &is_active); err != nil { return err } From e5891830e88ed7a5c7d50ef53ba4ee3b6831acb2 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 7 Feb 2023 16:55:20 +0200 Subject: [PATCH 083/228] send stdout/stderr to syslog Signed-off-by: Mike --- postgres_exporter.rc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/postgres_exporter.rc b/postgres_exporter.rc index d7c554689..b7a59a960 100644 --- a/postgres_exporter.rc +++ b/postgres_exporter.rc @@ -56,7 +56,8 @@ postgres_exporter_data_source_name="postgresql://${postgres_exporter_pg_user}:${ pidfile=/var/run/postgres_exporter.pid command="/usr/sbin/daemon" procname="/usr/local/bin/postgres_exporter" -command_args="-p ${pidfile} /usr/bin/env DATA_SOURCE_NAME="${postgres_exporter_data_source_name}" ${procname} \ +command_args="-f -p ${pidfile} -T ${name} \ + /usr/bin/env DATA_SOURCE_NAME="${postgres_exporter_data_source_name}" ${procname} \ --web.listen-address=${postgres_exporter_listen_address} \ ${postgres_exporter_args}" From 9cd48909d8e893b8d00beb6d0aa4fe4471afa9f6 Mon Sep 17 00:00:00 2001 From: prombot Date: Tue, 21 Feb 2023 17:50:14 +0000 Subject: [PATCH 084/228] Update common Prometheus files Signed-off-by: prombot --- Makefile.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.common b/Makefile.common index 1985fcdeb..6d8007c95 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.50.1 +GOLANGCI_LINT_VERSION ?= v1.51.2 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) From 799f3e15b22a62651ecfff4fba12f0c796a17322 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Mon, 3 Oct 2022 22:30:07 -0400 Subject: [PATCH 085/228] Fix exclude-databases for collector package The pg_database collector was not respecting the --exclude-databases flag and causing problems where databases were not accessible. This now respects the list of databases to exclude. - Adjusts the Collector create func to take a config struct instead of a logger. This allows more changes like this in the future. I figured we would need to do this at some point but I wasn't sure if we could hold off. - Split the database size collection to a separate query when database is not excluded. - Comment some probe code that was not useful/accurate Signed-off-by: Joe Adams --- cmd/postgres_exporter/main.go | 10 +++- cmd/postgres_exporter/postgres_exporter.go | 4 +- cmd/postgres_exporter/probe.go | 35 ++++++------- collector/collector.go | 16 ++++-- collector/pg_database.go | 60 +++++++++++++++++++--- collector/pg_stat_bgwriter.go | 3 +- collector/probe.go | 8 ++- 7 files changed, 97 insertions(+), 39 deletions(-) diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 6936226c8..642301065 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -14,8 +14,10 @@ package main import ( + "fmt" "net/http" "os" + "strings" "github.com/go-kit/log" "github.com/go-kit/log/level" @@ -101,13 +103,16 @@ func main() { os.Exit(1) } + excludedDatabases := strings.Split(*excludeDatabases, ",") + logger.Log("msg", "Excluded databases", "databases", fmt.Sprintf("%v", excludedDatabases)) + opts := []ExporterOpt{ DisableDefaultMetrics(*disableDefaultMetrics), DisableSettingsMetrics(*disableSettingsMetrics), AutoDiscoverDatabases(*autoDiscoverDatabases), WithUserQueriesPath(*queriesPath), WithConstantLabels(*constantLabelsList), - ExcludeDatabases(*excludeDatabases), + ExcludeDatabases(excludedDatabases), IncludeDatabases(*includeDatabases), } @@ -128,6 +133,7 @@ func main() { pe, err := collector.NewPostgresCollector( logger, + excludedDatabases, dsn, []string{}, ) @@ -143,7 +149,7 @@ func main() { w.Write(landingPage) // nolint: errcheck }) - http.HandleFunc("/probe", handleProbe(logger)) + http.HandleFunc("/probe", handleProbe(logger, excludedDatabases)) srv := &http.Server{} if err := web.ListenAndServe(srv, webConfig, logger); err != nil { diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index 0b56e768a..bc96bb0e6 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -484,9 +484,9 @@ func AutoDiscoverDatabases(b bool) ExporterOpt { } // ExcludeDatabases allows to filter out result from AutoDiscoverDatabases -func ExcludeDatabases(s string) ExporterOpt { +func ExcludeDatabases(s []string) ExporterOpt { return func(e *Exporter) { - e.excludeDatabases = strings.Split(s, ",") + e.excludeDatabases = s } } diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go index 167e827c2..6f0e8b8a3 100644 --- a/cmd/postgres_exporter/probe.go +++ b/cmd/postgres_exporter/probe.go @@ -16,7 +16,6 @@ package main import ( "fmt" "net/http" - "time" "github.com/go-kit/log" "github.com/go-kit/log/level" @@ -26,7 +25,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" ) -func handleProbe(logger log.Logger) http.HandlerFunc { +func handleProbe(logger log.Logger, excludeDatabases []string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() conf := c.GetConfig() @@ -62,21 +61,21 @@ func handleProbe(logger log.Logger) http.HandlerFunc { // TODO(@sysadmind): Timeout - probeSuccessGauge := prometheus.NewGauge(prometheus.GaugeOpts{ - Name: "probe_success", - Help: "Displays whether or not the probe was a success", - }) - probeDurationGauge := prometheus.NewGauge(prometheus.GaugeOpts{ - Name: "probe_duration_seconds", - Help: "Returns how long the probe took to complete in seconds", - }) + // probeSuccessGauge := prometheus.NewGauge(prometheus.GaugeOpts{ + // Name: "probe_success", + // Help: "Displays whether or not the probe was a success", + // }) + // probeDurationGauge := prometheus.NewGauge(prometheus.GaugeOpts{ + // Name: "probe_duration_seconds", + // Help: "Returns how long the probe took to complete in seconds", + // }) tl := log.With(logger, "target", target) - start := time.Now() + // start := time.Now() registry := prometheus.NewRegistry() - registry.MustRegister(probeSuccessGauge) - registry.MustRegister(probeDurationGauge) + // registry.MustRegister(probeSuccessGauge) + // registry.MustRegister(probeDurationGauge) opts := []ExporterOpt{ DisableDefaultMetrics(*disableDefaultMetrics), @@ -96,10 +95,10 @@ func handleProbe(logger log.Logger) http.HandlerFunc { registry.MustRegister(exporter) // Run the probe - pc, err := collector.NewProbeCollector(tl, registry, dsn) + pc, err := collector.NewProbeCollector(tl, excludeDatabases, registry, dsn) if err != nil { - probeSuccessGauge.Set(0) - probeDurationGauge.Set(time.Since(start).Seconds()) + // probeSuccessGauge.Set(0) + // probeDurationGauge.Set(time.Since(start).Seconds()) http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -115,10 +114,6 @@ func handleProbe(logger log.Logger) http.HandlerFunc { registry.MustRegister(pc) - duration := time.Since(start).Seconds() - probeDurationGauge.Set(duration) - probeSuccessGauge.Set(1) - // TODO check success, etc h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{}) h.ServeHTTP(w, r) diff --git a/collector/collector.go b/collector/collector.go index 6d1a4dd11..997fd62bf 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -28,7 +28,7 @@ import ( ) var ( - factories = make(map[string]func(logger log.Logger) (Collector, error)) + factories = make(map[string]func(collectorConfig) (Collector, error)) initiatedCollectorsMtx = sync.Mutex{} initiatedCollectors = make(map[string]Collector) collectorState = make(map[string]*bool) @@ -62,7 +62,12 @@ type Collector interface { Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error } -func registerCollector(name string, isDefaultEnabled bool, createFunc func(logger log.Logger) (Collector, error)) { +type collectorConfig struct { + logger log.Logger + excludeDatabases []string +} + +func registerCollector(name string, isDefaultEnabled bool, createFunc func(collectorConfig) (Collector, error)) { var helpDefaultState string if isDefaultEnabled { helpDefaultState = "enabled" @@ -93,7 +98,7 @@ type PostgresCollector struct { type Option func(*PostgresCollector) error // NewPostgresCollector creates a new PostgresCollector. -func NewPostgresCollector(logger log.Logger, dsn string, filters []string, options ...Option) (*PostgresCollector, error) { +func NewPostgresCollector(logger log.Logger, excludeDatabases []string, dsn string, filters []string, options ...Option) (*PostgresCollector, error) { p := &PostgresCollector{ logger: logger, } @@ -126,7 +131,10 @@ func NewPostgresCollector(logger log.Logger, dsn string, filters []string, optio if collector, ok := initiatedCollectors[key]; ok { collectors[key] = collector } else { - collector, err := factories[key](log.With(logger, "collector", key)) + collector, err := factories[key](collectorConfig{ + logger: log.With(logger, "collector", key), + excludeDatabases: excludeDatabases, + }) if err != nil { return nil, err } diff --git a/collector/pg_database.go b/collector/pg_database.go index 8fa4dab8e..1ed841ca6 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -26,11 +26,19 @@ func init() { } type PGDatabaseCollector struct { - log log.Logger + log log.Logger + excludedDatabases []string } -func NewPGDatabaseCollector(logger log.Logger) (Collector, error) { - return &PGDatabaseCollector{log: logger}, nil +func NewPGDatabaseCollector(config collectorConfig) (Collector, error) { + exclude := config.excludeDatabases + if exclude == nil { + exclude = []string{} + } + return &PGDatabaseCollector{ + log: config.logger, + excludedDatabases: exclude, + }, nil } var pgDatabase = map[string]*prometheus.Desc{ @@ -41,20 +49,49 @@ var pgDatabase = map[string]*prometheus.Desc{ ), } -func (PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { +// Update implements Collector and exposes database size. +// It is called by the Prometheus registry when collecting metrics. +// The list of databases is retrieved from pg_database and filtered +// by the excludeDatabase config parameter. The tradeoff here is that +// we have to query the list of databases and then query the size of +// each database individually. This is because we can't filter the +// list of databases in the query because the list of excluded +// databases is dynamic. +func (c PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { + // Query the list of databases rows, err := db.QueryContext(ctx, `SELECT pg_database.datname - ,pg_database_size(pg_database.datname) - FROM pg_database;`) + FROM pg_database; + `, + ) if err != nil { return err } defer rows.Close() + var databases []string + for rows.Next() { var datname string + if err := rows.Scan(&datname); err != nil { + return err + } + + // Ignore excluded databases + // Filtering is done here instead of in the query to avoid + // a complicated NOT IN query with a variable number of parameters + if sliceContains(c.excludedDatabases, datname) { + continue + } + + databases = append(databases, datname) + } + + // Query the size of the databases + for _, datname := range databases { var size int64 - if err := rows.Scan(&datname, &size); err != nil { + err = db.QueryRowContext(ctx, "SELECT pg_database_size($1)", datname).Scan(&size) + if err != nil { return err } @@ -68,3 +105,12 @@ func (PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- pro } return nil } + +func sliceContains(slice []string, s string) bool { + for _, item := range slice { + if item == s { + return true + } + } + return false +} diff --git a/collector/pg_stat_bgwriter.go b/collector/pg_stat_bgwriter.go index 69c75653f..5456423af 100644 --- a/collector/pg_stat_bgwriter.go +++ b/collector/pg_stat_bgwriter.go @@ -18,7 +18,6 @@ import ( "database/sql" "time" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -29,7 +28,7 @@ func init() { type PGStatBGWriterCollector struct { } -func NewPGStatBGWriterCollector(logger log.Logger) (Collector, error) { +func NewPGStatBGWriterCollector(collectorConfig) (Collector, error) { return &PGStatBGWriterCollector{}, nil } diff --git a/collector/probe.go b/collector/probe.go index c8bf8ee48..9044c40f9 100644 --- a/collector/probe.go +++ b/collector/probe.go @@ -30,7 +30,7 @@ type ProbeCollector struct { db *sql.DB } -func NewProbeCollector(logger log.Logger, registry *prometheus.Registry, dsn config.DSN) (*ProbeCollector, error) { +func NewProbeCollector(logger log.Logger, excludeDatabases []string, registry *prometheus.Registry, dsn config.DSN) (*ProbeCollector, error) { collectors := make(map[string]Collector) initiatedCollectorsMtx.Lock() defer initiatedCollectorsMtx.Unlock() @@ -45,7 +45,11 @@ func NewProbeCollector(logger log.Logger, registry *prometheus.Registry, dsn con if collector, ok := initiatedCollectors[key]; ok { collectors[key] = collector } else { - collector, err := factories[key](log.With(logger, "collector", key)) + collector, err := factories[key]( + collectorConfig{ + logger: log.With(logger, "collector", key), + excludeDatabases: excludeDatabases, + }) if err != nil { return nil, err } From 8d6ce0558c73b362625fa6eb5a273de58ecbedba Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Mon, 17 Oct 2022 19:23:51 -0400 Subject: [PATCH 086/228] Remove commented code Signed-off-by: Joe Adams --- cmd/postgres_exporter/probe.go | 14 +------------- collector/replication_slots.go | 4 ++-- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go index 6f0e8b8a3..2a7b29ec1 100644 --- a/cmd/postgres_exporter/probe.go +++ b/cmd/postgres_exporter/probe.go @@ -61,21 +61,9 @@ func handleProbe(logger log.Logger, excludeDatabases []string) http.HandlerFunc // TODO(@sysadmind): Timeout - // probeSuccessGauge := prometheus.NewGauge(prometheus.GaugeOpts{ - // Name: "probe_success", - // Help: "Displays whether or not the probe was a success", - // }) - // probeDurationGauge := prometheus.NewGauge(prometheus.GaugeOpts{ - // Name: "probe_duration_seconds", - // Help: "Returns how long the probe took to complete in seconds", - // }) - tl := log.With(logger, "target", target) - // start := time.Now() registry := prometheus.NewRegistry() - // registry.MustRegister(probeSuccessGauge) - // registry.MustRegister(probeDurationGauge) opts := []ExporterOpt{ DisableDefaultMetrics(*disableDefaultMetrics), @@ -83,7 +71,7 @@ func handleProbe(logger log.Logger, excludeDatabases []string) http.HandlerFunc AutoDiscoverDatabases(*autoDiscoverDatabases), WithUserQueriesPath(*queriesPath), WithConstantLabels(*constantLabelsList), - ExcludeDatabases(*excludeDatabases), + ExcludeDatabases(excludeDatabases), IncludeDatabases(*includeDatabases), } diff --git a/collector/replication_slots.go b/collector/replication_slots.go index 224db3ccf..ed37441cc 100644 --- a/collector/replication_slots.go +++ b/collector/replication_slots.go @@ -29,8 +29,8 @@ type PGReplicationSlotCollector struct { log log.Logger } -func NewPGReplicationSlotCollector(logger log.Logger) (Collector, error) { - return &PGReplicationSlotCollector{log: logger}, nil +func NewPGReplicationSlotCollector(config collectorConfig) (Collector, error) { + return &PGReplicationSlotCollector{log: config.logger}, nil } var pgReplicationSlot = map[string]*prometheus.Desc{ From 55263868e0bcddab8ae13e2897b9267e3a12a006 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Sun, 5 Mar 2023 15:30:18 -0500 Subject: [PATCH 087/228] Remove more dead code Signed-off-by: Joe Adams --- cmd/postgres_exporter/probe.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go index 2a7b29ec1..827314a7a 100644 --- a/cmd/postgres_exporter/probe.go +++ b/cmd/postgres_exporter/probe.go @@ -85,8 +85,6 @@ func handleProbe(logger log.Logger, excludeDatabases []string) http.HandlerFunc // Run the probe pc, err := collector.NewProbeCollector(tl, excludeDatabases, registry, dsn) if err != nil { - // probeSuccessGauge.Set(0) - // probeDurationGauge.Set(time.Since(start).Seconds()) http.Error(w, err.Error(), http.StatusInternalServerError) return } From 0e654d8f8376eb18523e8c4f673f7bbdb6844309 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Sun, 5 Mar 2023 21:40:54 +0100 Subject: [PATCH 088/228] Update build * Update Go to 1.20. * Update golanci-lint. * Bump modules. * Update CI orb. * Fix up use of deprecated ioutil. Signed-off-by: SuperQ --- .circleci/config.yml | 6 +- .github/workflows/golangci-lint.yml | 8 +- .promu.yml | 2 +- cmd/postgres_exporter/datasource.go | 7 +- cmd/postgres_exporter/postgres_exporter.go | 4 +- .../postgres_exporter_test.go | 3 +- go.mod | 12 +- go.sum | 723 +----------------- 8 files changed, 30 insertions(+), 735 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 65b561f2a..508120e67 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,13 +2,13 @@ version: 2.1 orbs: - prometheus: prometheus/prometheus@0.16.0 + prometheus: prometheus/prometheus@0.17.1 executors: # This must match .promu.yml. golang: docker: - - image: cimg/go:1.19 + - image: cimg/go:1.20 jobs: test: @@ -22,7 +22,7 @@ jobs: integration: docker: - - image: cimg/go:1.19 + - image: cimg/go:1.20 - image: << parameters.postgres_image >> environment: POSTGRES_DB: circle_test diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 6034bcbf8..100cf9329 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -18,13 +18,13 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - name: install Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x - name: Install snmp_exporter/generator dependencies run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@v3.2.0 + uses: golangci/golangci-lint-action@v3.4.0 with: - version: v1.45.2 + version: v1.51.2 diff --git a/.promu.yml b/.promu.yml index 8f39e7865..55c73712e 100644 --- a/.promu.yml +++ b/.promu.yml @@ -1,6 +1,6 @@ go: # This must match .circle/config.yml. - version: 1.19 + version: 1.20 repository: path: github.com/prometheus-community/postgres_exporter build: diff --git a/cmd/postgres_exporter/datasource.go b/cmd/postgres_exporter/datasource.go index 97f7ecd8b..feaae6b61 100644 --- a/cmd/postgres_exporter/datasource.go +++ b/cmd/postgres_exporter/datasource.go @@ -15,7 +15,6 @@ package main import ( "fmt" - "io/ioutil" "net/url" "os" "regexp" @@ -130,7 +129,7 @@ func getDataSources() ([]string, error) { dataSourceUserFile := os.Getenv("DATA_SOURCE_USER_FILE") if len(dataSourceUserFile) != 0 { - fileContents, err := ioutil.ReadFile(dataSourceUserFile) + fileContents, err := os.ReadFile(dataSourceUserFile) if err != nil { return nil, fmt.Errorf("failed loading data source user file %s: %s", dataSourceUserFile, err.Error()) } @@ -141,7 +140,7 @@ func getDataSources() ([]string, error) { dataSourcePassFile := os.Getenv("DATA_SOURCE_PASS_FILE") if len(dataSourcePassFile) != 0 { - fileContents, err := ioutil.ReadFile(dataSourcePassFile) + fileContents, err := os.ReadFile(dataSourcePassFile) if err != nil { return nil, fmt.Errorf("failed loading data source pass file %s: %s", dataSourcePassFile, err.Error()) } @@ -153,7 +152,7 @@ func getDataSources() ([]string, error) { ui := url.UserPassword(user, pass).String() dataSrouceURIFile := os.Getenv("DATA_SOURCE_URI_FILE") if len(dataSrouceURIFile) != 0 { - fileContents, err := ioutil.ReadFile(dataSrouceURIFile) + fileContents, err := os.ReadFile(dataSrouceURIFile) if err != nil { return nil, fmt.Errorf("failed loading data source URI file %s: %s", dataSrouceURIFile, err.Error()) } diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index bc96bb0e6..e1d1e4445 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -18,8 +18,8 @@ import ( "database/sql" "errors" "fmt" - "io/ioutil" "math" + "os" "regexp" "strings" "time" @@ -663,7 +663,7 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, server *Server) e.userQueriesError.Reset() // Calculate the hashsum of the useQueries - userQueriesData, err := ioutil.ReadFile(e.userQueriesPath) + userQueriesData, err := os.ReadFile(e.userQueriesPath) if err != nil { level.Error(logger).Log("msg", "Failed to reload user queries", "path", e.userQueriesPath, "err", err) e.userQueriesError.WithLabelValues(e.userQueriesPath, "").Set(1) diff --git a/cmd/postgres_exporter/postgres_exporter_test.go b/cmd/postgres_exporter/postgres_exporter_test.go index 468aa39b9..0f36febf4 100644 --- a/cmd/postgres_exporter/postgres_exporter_test.go +++ b/cmd/postgres_exporter/postgres_exporter_test.go @@ -17,7 +17,6 @@ package main import ( - "io/ioutil" "math" "os" "reflect" @@ -409,7 +408,7 @@ func (s *FunctionalSuite) TestBooleanConversionToValueAndString(c *C) { } func (s *FunctionalSuite) TestParseUserQueries(c *C) { - userQueriesData, err := ioutil.ReadFile("./tests/user_queries_ok.yaml") + userQueriesData, err := os.ReadFile("./tests/user_queries_ok.yaml") if err == nil { metricMaps, newQueryOverrides, err := parseUserQueries(userQueriesData) c.Assert(err, Equals, nil) diff --git a/go.mod b/go.mod index 7d21dc4e2..d6a5cc4cc 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/prometheus-community/postgres_exporter -go 1.17 +go 1.19 require ( github.com/blang/semver/v4 v4.0.0 @@ -30,12 +30,12 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/prometheus/procfs v0.8.0 // indirect - golang.org/x/crypto v0.0.0-20221012134737-56aed061732a // indirect - golang.org/x/net v0.4.0 // indirect - golang.org/x/oauth2 v0.3.0 // indirect + golang.org/x/crypto v0.7.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/oauth2 v0.6.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect ) diff --git a/go.sum b/go.sum index 5a4377b6b..3896acc0c 100644 --- a/go.sum +++ b/go.sum @@ -1,229 +1,32 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 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-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -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/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU= github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -231,564 +34,58 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/exporter-toolkit v0.8.2 h1:sbJAfBXQFkG6sUkbwBun8MNdzW9+wd5YfPYofbmj0YM= github.com/prometheus/exporter-toolkit v0.8.2/go.mod h1:00shzmJL7KxcsabLWcONwpyNEuWhREOnFqZW7vadFS0= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg= -golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8= -golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -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= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From e7f58a42e8040936d7e28f0a99c6823dba7ef6f7 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Mon, 6 Mar 2023 09:34:22 +0100 Subject: [PATCH 089/228] Reduce cardinality of pg_stat_statements Make the example queries.yaml `pg_stat_statements` query safer. * Select the top 10% of queries by total query time. * Only expose the top 100 queries by total query time. * Keep only the most useful metrics. * Comment out the example by default. Fixes: https://github.com/prometheus-community/postgres_exporter/issues/549 Signed-off-by: SuperQ --- queries.yaml | 123 ++++++++++++++++++++++----------------------------- 1 file changed, 52 insertions(+), 71 deletions(-) diff --git a/queries.yaml b/queries.yaml index 6f2008cbe..1e54f326d 100644 --- a/queries.yaml +++ b/queries.yaml @@ -146,77 +146,58 @@ pg_statio_user_tables: usage: "COUNTER" description: "Number of buffer hits in this table's TOAST table indexes (if any)" -# WARNING: This set of metrics can be very expensive on a busy server as every unique query executed will create an additional time series -pg_stat_statements: - query: "SELECT t2.rolname, t3.datname, queryid, calls, total_time / 1000 as total_time_seconds, min_time / 1000 as min_time_seconds, max_time / 1000 as max_time_seconds, mean_time / 1000 as mean_time_seconds, stddev_time / 1000 as stddev_time_seconds, rows, shared_blks_hit, shared_blks_read, shared_blks_dirtied, shared_blks_written, local_blks_hit, local_blks_read, local_blks_dirtied, local_blks_written, temp_blks_read, temp_blks_written, blk_read_time / 1000 as blk_read_time_seconds, blk_write_time / 1000 as blk_write_time_seconds FROM pg_stat_statements t1 JOIN pg_roles t2 ON (t1.userid=t2.oid) JOIN pg_database t3 ON (t1.dbid=t3.oid) WHERE t2.rolname != 'rdsadmin'" - master: true - metrics: - - rolname: - usage: "LABEL" - description: "Name of user" - - datname: - usage: "LABEL" - description: "Name of database" - - queryid: - usage: "LABEL" - description: "Query ID" - - calls: - usage: "COUNTER" - description: "Number of times executed" - - total_time_seconds: - usage: "COUNTER" - description: "Total time spent in the statement, in milliseconds" - - min_time_seconds: - usage: "GAUGE" - description: "Minimum time spent in the statement, in milliseconds" - - max_time_seconds: - usage: "GAUGE" - description: "Maximum time spent in the statement, in milliseconds" - - mean_time_seconds: - usage: "GAUGE" - description: "Mean time spent in the statement, in milliseconds" - - stddev_time_seconds: - usage: "GAUGE" - description: "Population standard deviation of time spent in the statement, in milliseconds" - - rows: - usage: "COUNTER" - description: "Total number of rows retrieved or affected by the statement" - - shared_blks_hit: - usage: "COUNTER" - description: "Total number of shared block cache hits by the statement" - - shared_blks_read: - usage: "COUNTER" - description: "Total number of shared blocks read by the statement" - - shared_blks_dirtied: - usage: "COUNTER" - description: "Total number of shared blocks dirtied by the statement" - - shared_blks_written: - usage: "COUNTER" - description: "Total number of shared blocks written by the statement" - - local_blks_hit: - usage: "COUNTER" - description: "Total number of local block cache hits by the statement" - - local_blks_read: - usage: "COUNTER" - description: "Total number of local blocks read by the statement" - - local_blks_dirtied: - usage: "COUNTER" - description: "Total number of local blocks dirtied by the statement" - - local_blks_written: - usage: "COUNTER" - description: "Total number of local blocks written by the statement" - - temp_blks_read: - usage: "COUNTER" - description: "Total number of temp blocks read by the statement" - - temp_blks_written: - usage: "COUNTER" - description: "Total number of temp blocks written by the statement" - - blk_read_time_seconds: - usage: "COUNTER" - description: "Total time the statement spent reading blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)" - - blk_write_time_seconds: - usage: "COUNTER" - description: "Total time the statement spent writing blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)" +# +# WARNING: +# This set of metrics can be very expensive on a busy server as every +# unique query executed will create an additional time series +# +# pg_stat_statements: +# query: | +# SELECT +# pg_get_userbyid(userid) as user, +# pg_database.datname, +# pg_stat_statements.queryid, +# pg_stat_statements.calls as calls_total, +# pg_stat_statements.total_time / 1000.0 as seconds_total, +# pg_stat_statements.rows as rows_total, +# pg_stat_statements.blk_read_time / 1000.0 as block_read_seconds_total, +# pg_stat_statements.blk_write_time / 1000.0 as block_write_seconds_total +# FROM pg_stat_statements +# JOIN pg_database +# ON pg_database.oid = pg_stat_statements.dbid +# WHERE +# total_time > ( +# SELECT percentile_cont(0.1) +# WITHIN GROUP (ORDER BY total_time) +# FROM pg_stat_statements +# ) +# ORDER BY seconds_total DESC +# LIMIT 100 +# metrics: +# - user: +# usage: "LABEL" +# description: "The user who executed the statement" +# - datname: +# usage: "LABEL" +# description: "The database in which the statement was executed" +# - queryid: +# usage: "LABEL" +# description: "Internal hash code, computed from the statement's parse tree" +# - calls_total: +# usage: "COUNTER" +# description: "Number of times executed" +# - seconds_total: +# usage: "COUNTER" +# description: "Total time spent in the statement, in seconds" +# - rows_total: +# usage: "COUNTER" +# description: "Total number of rows retrieved or affected by the statement" +# - block_read_seconds_total: +# usage: "COUNTER" +# description: "Total time the statement spent reading blocks, in seconds" +# - block_write_seconds_total: +# usage: "COUNTER" +# description: "Total time the statement spent writing blocks, in seconds" pg_process_idle: query: | From 7e7366c9d03cd6d8d42f77b03643712b015614ae Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Mon, 20 Mar 2023 20:05:39 -0400 Subject: [PATCH 090/228] Update changelog and version for v0.12.0 release Signed-off-by: Joe Adams --- CHANGELOG.md | 6 +++++- VERSION | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38d7e4d90..c89c71859 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## master / unreleased -## 0.12.0-rc.0 / 2022-08-26 +## 0.12.0 / 2023-03-21 BREAKING CHANGES: @@ -10,7 +10,11 @@ PostgreSQL servers from a single exporter by passing the target via URL params. See the Multi-Target Support section of the README. * [CHANGE] Add multi-target support #618 +* [CHANGE] Add usename and application_name to pg_stat_activity metrics #673 +* [FEATURE] Add replication metrics from pg_replication_slots #747 * [BUGFIX] Add dsn type for handling datasources #678 +* [BUGFIX] Add 64kB unit for postgres 15 #740 +* [BUGFIX] Add 4kB unit for postgres compiled with small blocks #699 ## 0.11.1 / 2022-08-01 diff --git a/VERSION b/VERSION index 68f8b7694..ac454c6a1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.12.0-rc.0 +0.12.0 From de1c3cc5e77d831c0070a926b038a2b454ee7988 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Tue, 21 Mar 2023 08:21:49 +0100 Subject: [PATCH 091/228] Update exporter-toolkit Updates the exporter-toolkit to the latest version * Adds new landing page feature. * Allow metrics path to be on `/`. Signed-off-by: SuperQ --- cmd/postgres_exporter/main.go | 41 ++++++++++++++++++++--------------- collector/collector.go | 2 +- go.mod | 17 ++++++++------- go.sum | 38 ++++++++++++++++++-------------- 4 files changed, 55 insertions(+), 43 deletions(-) diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 642301065..cad77b96a 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -19,6 +19,7 @@ import ( "os" "strings" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/postgres_exporter/collector" @@ -30,7 +31,6 @@ import ( "github.com/prometheus/common/version" "github.com/prometheus/exporter-toolkit/web" "github.com/prometheus/exporter-toolkit/web/kingpinflag" - "gopkg.in/alecthomas/kingpin.v2" ) var ( @@ -40,7 +40,7 @@ var ( configFile = kingpin.Flag("config.file", "Postgres exporter configuration file.").Default("postgres_exporter.yml").String() webConfig = kingpinflag.AddFlags(kingpin.CommandLine, ":9187") - metricPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").Envar("PG_EXPORTER_WEB_TELEMETRY_PATH").String() + metricsPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").Envar("PG_EXPORTER_WEB_TELEMETRY_PATH").String() disableDefaultMetrics = kingpin.Flag("disable-default-metrics", "Do not include default metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_DEFAULT_METRICS").Bool() disableSettingsMetrics = kingpin.Flag("disable-settings-metrics", "Do not include pg_settings metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_SETTINGS_METRICS").Bool() autoDiscoverDatabases = kingpin.Flag("auto-discover-databases", "Whether to discover the databases on a server dynamically.").Default("false").Envar("PG_EXPORTER_AUTO_DISCOVER_DATABASES").Bool() @@ -76,17 +76,6 @@ func main() { kingpin.Parse() logger = promlog.New(promlogConfig) - // landingPage contains the HTML served at '/'. - // TODO: Make this nicer and more informative. - var landingPage = []byte(` - Postgres exporter - -

Postgres exporter

-

Metrics

- - - `) - if *onlyDumpMaps { dumpMaps() return @@ -143,11 +132,27 @@ func main() { prometheus.MustRegister(pe) } - http.Handle(*metricPath, promhttp.Handler()) - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/html; charset=UTF-8") // nolint: errcheck - w.Write(landingPage) // nolint: errcheck - }) + http.Handle(*metricsPath, promhttp.Handler()) + + if *metricsPath != "/" && *metricsPath != "" { + landingConfig := web.LandingConfig{ + Name: "Postgres Exporter", + Description: "Prometheus PostgreSQL server Exporter", + Version: version.Info(), + Links: []web.LandingLinks{ + { + Address: *metricsPath, + Text: "Metrics", + }, + }, + } + landingPage, err := web.NewLandingPage(landingConfig) + if err != nil { + level.Error(logger).Log("err", err) + os.Exit(1) + } + http.Handle("/", landingPage) + } http.HandleFunc("/probe", handleProbe(logger, excludedDatabases)) diff --git a/collector/collector.go b/collector/collector.go index 997fd62bf..e8e418d12 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -21,10 +21,10 @@ import ( "sync" "time" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" - "gopkg.in/alecthomas/kingpin.v2" ) var ( diff --git a/go.mod b/go.mod index d6a5cc4cc..c46bd99b9 100644 --- a/go.mod +++ b/go.mod @@ -3,33 +3,34 @@ module github.com/prometheus-community/postgres_exporter go 1.19 require ( + github.com/alecthomas/kingpin/v2 v2.3.2 github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 github.com/lib/pq v1.10.7 github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_model v0.3.0 - github.com/prometheus/common v0.39.0 - github.com/prometheus/exporter-toolkit v0.8.2 - gopkg.in/alecthomas/kingpin.v2 v2.2.6 + github.com/prometheus/common v0.42.0 + github.com/prometheus/exporter-toolkit v0.9.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // 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/coreos/go-systemd/v22 v22.4.0 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/jpillora/backoff v1.0.0 // indirect - github.com/kr/pretty v0.2.1 // indirect - github.com/kr/text v0.1.0 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/xhit/go-str2duration/v2 v2.1.0 // indirect golang.org/x/crypto v0.7.0 // indirect golang.org/x/net v0.8.0 // indirect golang.org/x/oauth2 v0.6.0 // indirect diff --git a/go.sum b/go.sum index 3896acc0c..99f2d1721 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -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/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU= +github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= 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= @@ -8,8 +8,9 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU= -github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= @@ -24,35 +25,42 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= -github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= -github.com/prometheus/exporter-toolkit v0.8.2 h1:sbJAfBXQFkG6sUkbwBun8MNdzW9+wd5YfPYofbmj0YM= -github.com/prometheus/exporter-toolkit v0.8.2/go.mod h1:00shzmJL7KxcsabLWcONwpyNEuWhREOnFqZW7vadFS0= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/exporter-toolkit v0.9.1 h1:cNkC01riqiOS+kh3zdnNwRsbe/Blh0WwK3ij5rPJ9Sw= +github.com/prometheus/exporter-toolkit v0.9.1/go.mod h1:iFlTmFISCix0vyuyBmm0UqOUCTao9+RsAsKJP3YM9ec= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= @@ -79,8 +87,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From d8617df696d2449809d191e43a6056892dd99a0b Mon Sep 17 00:00:00 2001 From: prombot Date: Tue, 21 Mar 2023 17:51:31 +0000 Subject: [PATCH 092/228] Update common Prometheus files Signed-off-by: prombot --- Makefile.common | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Makefile.common b/Makefile.common index 6d8007c95..b111d2562 100644 --- a/Makefile.common +++ b/Makefile.common @@ -91,6 +91,8 @@ BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS)) PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS)) TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS)) +SANITIZED_DOCKER_IMAGE_TAG := $(subst +,-,$(DOCKER_IMAGE_TAG)) + ifeq ($(GOHOSTARCH),amd64) ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows)) # Only supported on amd64 @@ -205,7 +207,7 @@ common-tarball: promu .PHONY: common-docker $(BUILD_DOCKER_ARCHS) common-docker: $(BUILD_DOCKER_ARCHS) $(BUILD_DOCKER_ARCHS): common-docker-%: - docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \ + docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" \ -f $(DOCKERFILE_PATH) \ --build-arg ARCH="$*" \ --build-arg OS="linux" \ @@ -214,19 +216,19 @@ $(BUILD_DOCKER_ARCHS): common-docker-%: .PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS) common-docker-publish: $(PUBLISH_DOCKER_ARCHS) $(PUBLISH_DOCKER_ARCHS): common-docker-publish-%: - docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" + docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" DOCKER_MAJOR_VERSION_TAG = $(firstword $(subst ., ,$(shell cat VERSION))) .PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS) common-docker-tag-latest: $(TAG_DOCKER_ARCHS) $(TAG_DOCKER_ARCHS): common-docker-tag-latest-%: - docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest" - docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)" + docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest" + docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)" .PHONY: common-docker-manifest common-docker-manifest: - DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG)) - DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" + DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(SANITIZED_DOCKER_IMAGE_TAG)) + DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)" .PHONY: promu promu: $(PROMU) From 1e3b177e34da2bf5bdae7a8003807fc18132e172 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 22 Mar 2023 20:54:00 -0400 Subject: [PATCH 093/228] Fix column type for pg_replication_slots Change the data type of `active` from int64 to bool. The documentation confirms that this is a boolean field. https://www.postgresql.org/docs/current/view-pg-replication-slots.html fixes #769 Signed-off-by: Joe Adams --- collector/replication_slots.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/collector/replication_slots.go b/collector/replication_slots.go index ed37441cc..a9cad77df 100644 --- a/collector/replication_slots.go +++ b/collector/replication_slots.go @@ -69,7 +69,7 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha var slot_name string var wal_lsn int64 var flush_lsn int64 - var is_active int64 + var is_active bool if err := rows.Scan(&slot_name, &wal_lsn, &flush_lsn, &is_active); err != nil { return err } @@ -78,7 +78,7 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha pgReplicationSlot["current_wal_lsn"], prometheus.GaugeValue, float64(wal_lsn), slot_name, ) - if is_active == 1 { + if is_active { ch <- prometheus.MustNewConstMetric( pgReplicationSlot["confirmed_flush_lsn"], prometheus.GaugeValue, float64(flush_lsn), slot_name, From 6e2f8c332b4879a09ebeb88fb522b344a628c96e Mon Sep 17 00:00:00 2001 From: SuperQ Date: Tue, 28 Mar 2023 23:18:18 +0200 Subject: [PATCH 094/228] Update versions listed in the README Update the supported versions based on what we actually test in CI. Signed-off-by: SuperQ --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 31bc7b4e2..d53287798 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Prometheus exporter for PostgreSQL server metrics. -CI Tested PostgreSQL versions: `9.4`, `9.5`, `9.6`, `10`, `11`, `12`, `13`, `14`, `15` +CI Tested PostgreSQL versions: `10`, `11`, `12`, `13`, `14`, `15` ## Quick Start This package is available for Docker: From a32ef400534fbb4c90d4e90487b6e99edac3ed20 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 29 Mar 2023 20:13:51 -0400 Subject: [PATCH 095/228] Update README cli flags These have not been kept up to date. Signed-off-by: Joe Adams --- README.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d53287798..b54b4b63c 100644 --- a/README.md +++ b/README.md @@ -77,9 +77,22 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra * `collector.bgwriter` Enable the pg_stat_bgwriter collector. Default is `enabled` +* `collector.replication_slot` + Enable the replication_slot collector. Default is `enabled` + +* `config.file` + Set the config file path. Default is `postgres_exporter.yml` + +* `web.systemd-socket` + Use systemd socket activation listeners instead of port listeners (Linux only). Default is `false` + * `web.listen-address` Address to listen on for web interface and telemetry. Default is `:9187`. +* `web.config.file` + Configuration file to use TLS and/or basic authentication. The format of the + file is described [in the exporter-toolkit repository](https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md). + * `web.telemetry-path` Path under which to expose metrics. Default is `/metrics`. @@ -118,10 +131,6 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra * `log.format` Set the log format: one of `logfmt`, `json`. -* `web.config.file` - Configuration file to use TLS and/or basic authentication. The format of the - file is described [in the exporter-toolkit repository](https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md). - ### Environment Variables The following environment variables configure the exporter: From ac05e0bdce56896858044db755284a7b5c8f0eae Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 29 Mar 2023 20:15:41 -0400 Subject: [PATCH 096/228] Adjust log level for collector startup Since we support both multi-target and typical direct scrapes, either of these can fail and it is no longer an error. Signed-off-by: Joe Adams --- cmd/postgres_exporter/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index cad77b96a..efa96738b 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -83,7 +83,7 @@ func main() { if err := c.ReloadConfig(*configFile, logger); err != nil { // This is not fatal, but it means that auth must be provided for every dsn. - level.Error(logger).Log("msg", "Error loading config", "err", err) + level.Warn(logger).Log("msg", "Error loading config", "err", err) } dsns, err := getDataSources() @@ -127,7 +127,7 @@ func main() { []string{}, ) if err != nil { - level.Error(logger).Log("msg", "Failed to create PostgresCollector", "err", err.Error()) + level.Warn(logger).Log("msg", "Failed to create PostgresCollector", "err", err.Error()) } else { prometheus.MustRegister(pe) } From 20b1b75e64a46dc236a633c03158be736077b470 Mon Sep 17 00:00:00 2001 From: Khaled Khalifa <33331600+khkhalifa@users.noreply.github.com> Date: Sun, 16 Apr 2023 11:29:12 +0000 Subject: [PATCH 097/228] Fix pg_setting different help values Signed-off-by: GitHub --- cmd/postgres_exporter/pg_setting.go | 2 +- cmd/postgres_exporter/pg_setting_test.go | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cmd/postgres_exporter/pg_setting.go b/cmd/postgres_exporter/pg_setting.go index 8a45ec945..30b60ca1c 100644 --- a/cmd/postgres_exporter/pg_setting.go +++ b/cmd/postgres_exporter/pg_setting.go @@ -70,7 +70,7 @@ func (s *pgSetting) metric(labels prometheus.Labels) prometheus.Metric { err error name = strings.Replace(s.name, ".", "_", -1) unit = s.unit // nolint: ineffassign - shortDesc = s.shortDesc + shortDesc = fmt.Sprintf("Server Parameter: %s", s.name) subsystem = "settings" val float64 ) diff --git a/cmd/postgres_exporter/pg_setting_test.go b/cmd/postgres_exporter/pg_setting_test.go index 8f8f9c058..1b1168c7e 100644 --- a/cmd/postgres_exporter/pg_setting_test.go +++ b/cmd/postgres_exporter/pg_setting_test.go @@ -40,7 +40,7 @@ var fixtures = []fixture{ unit: "seconds", err: "", }, - d: `Desc{fqName: "pg_settings_seconds_fixture_metric_seconds", help: "Foo foo foo [Units converted to seconds.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_seconds_fixture_metric_seconds", help: "Server Parameter: seconds_fixture_metric [Units converted to seconds.]", constLabels: {}, variableLabels: []}`, v: 5, }, { @@ -56,7 +56,7 @@ var fixtures = []fixture{ unit: "seconds", err: "", }, - d: `Desc{fqName: "pg_settings_milliseconds_fixture_metric_seconds", help: "Foo foo foo [Units converted to seconds.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_milliseconds_fixture_metric_seconds", help: "Server Parameter: milliseconds_fixture_metric [Units converted to seconds.]", constLabels: {}, variableLabels: []}`, v: 5, }, { @@ -72,7 +72,7 @@ var fixtures = []fixture{ unit: "bytes", err: "", }, - d: `Desc{fqName: "pg_settings_eight_kb_fixture_metric_bytes", help: "Foo foo foo [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_eight_kb_fixture_metric_bytes", help: "Server Parameter: eight_kb_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, v: 139264, }, { @@ -88,7 +88,7 @@ var fixtures = []fixture{ unit: "bytes", err: "", }, - d: `Desc{fqName: "pg_settings_16_kb_real_fixture_metric_bytes", help: "Foo foo foo [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_16_kb_real_fixture_metric_bytes", help: "Server Parameter: 16_kb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, v: 49152, }, { @@ -104,7 +104,7 @@ var fixtures = []fixture{ unit: "bytes", err: "", }, - d: `Desc{fqName: "pg_settings_16_mb_real_fixture_metric_bytes", help: "Foo foo foo [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_16_mb_real_fixture_metric_bytes", help: "Server Parameter: 16_mb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, v: 5.0331648e+07, }, { @@ -120,7 +120,7 @@ var fixtures = []fixture{ unit: "bytes", err: "", }, - d: `Desc{fqName: "pg_settings_32_mb_real_fixture_metric_bytes", help: "Foo foo foo [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_32_mb_real_fixture_metric_bytes", help: "Server Parameter: 32_mb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, v: 1.00663296e+08, }, { @@ -136,7 +136,7 @@ var fixtures = []fixture{ unit: "bytes", err: "", }, - d: `Desc{fqName: "pg_settings_64_mb_real_fixture_metric_bytes", help: "Foo foo foo [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_64_mb_real_fixture_metric_bytes", help: "Server Parameter: 64_mb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, v: 2.01326592e+08, }, { @@ -152,7 +152,7 @@ var fixtures = []fixture{ unit: "", err: "", }, - d: `Desc{fqName: "pg_settings_bool_on_fixture_metric", help: "Foo foo foo", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_bool_on_fixture_metric", help: "Server Parameter: bool_on_fixture_metric", constLabels: {}, variableLabels: []}`, v: 1, }, { @@ -168,7 +168,7 @@ var fixtures = []fixture{ unit: "", err: "", }, - d: `Desc{fqName: "pg_settings_bool_off_fixture_metric", help: "Foo foo foo", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_bool_off_fixture_metric", help: "Server Parameter: bool_off_fixture_metric", constLabels: {}, variableLabels: []}`, v: 0, }, { @@ -184,7 +184,7 @@ var fixtures = []fixture{ unit: "seconds", err: "", }, - d: `Desc{fqName: "pg_settings_special_minus_one_value_seconds", help: "foo foo foo [Units converted to seconds.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_special_minus_one_value_seconds", help: "Server Parameter: special_minus_one_value [Units converted to seconds.]", constLabels: {}, variableLabels: []}`, v: -1, }, { @@ -200,7 +200,7 @@ var fixtures = []fixture{ unit: "", err: "", }, - d: `Desc{fqName: "pg_settings_rds_rds_superuser_reserved_connections", help: "Sets the number of connection slots reserved for rds_superusers.", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_rds_rds_superuser_reserved_connections", help: "Server Parameter: rds.rds_superuser_reserved_connections", constLabels: {}, variableLabels: []}`, v: 2, }, { From 0c04fc1d1e95645ca927b91d5c88211ccc602ab8 Mon Sep 17 00:00:00 2001 From: Jack Wink <57678801+mothershipper@users.noreply.github.com> Date: Wed, 12 Apr 2023 12:59:01 -0700 Subject: [PATCH 098/228] Supports alternate postgres:// prefix in URLs Adds support for the alternate postgres:// prefix in URLs. It's maybe not the cleanest approach, but works. Hoping I can either get some pointers on a more appropriate patch, or that we could use this in the interim to unblock this use-case. Signed-off-by: Jack Wink <57678801+mothershipper@users.noreply.github.com> --- cmd/postgres_exporter/datasource.go | 2 +- config/dsn.go | 2 +- config/dsn_test.go | 13 +++++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cmd/postgres_exporter/datasource.go b/cmd/postgres_exporter/datasource.go index feaae6b61..0b8cef04a 100644 --- a/cmd/postgres_exporter/datasource.go +++ b/cmd/postgres_exporter/datasource.go @@ -35,7 +35,7 @@ func (e *Exporter) discoverDatabaseDSNs() []string { var dsnURI *url.URL var dsnConnstring string - if strings.HasPrefix(dsn, "postgresql://") { + if strings.HasPrefix(dsn, "postgresql://") || strings.HasPrefix(dsn, "postgres://") { var err error dsnURI, err = url.Parse(dsn) if err != nil { diff --git a/config/dsn.go b/config/dsn.go index 78d798d5f..168d00d62 100644 --- a/config/dsn.go +++ b/config/dsn.go @@ -65,7 +65,7 @@ func (d DSN) GetConnectionString() string { // dsnFromString parses a connection string into a dsn. It will attempt to parse the string as // a URL and as a set of key=value pairs. If both attempts fail, dsnFromString will return an error. func dsnFromString(in string) (DSN, error) { - if strings.HasPrefix(in, "postgresql://") { + if strings.HasPrefix(in, "postgresql://") || strings.HasPrefix(in, "postgres://") { return dsnFromURL(in) } diff --git a/config/dsn_test.go b/config/dsn_test.go index 637a3568e..68340cd09 100644 --- a/config/dsn_test.go +++ b/config/dsn_test.go @@ -186,6 +186,19 @@ func Test_dsnFromString(t *testing.T) { }, wantErr: false, }, + { + name: "Alternative URL prefix", + input: "postgres://user:s3cret@host.example.com:5432/tsdb?user=postgres", + want: DSN{ + scheme: "postgres", + host: "host.example.com:5432", + path: "/tsdb", + query: url.Values{}, + username: "user", + password: "s3cret", + }, + wantErr: false, + }, { name: "URL with user and password in query string", input: "postgresql://host.example.com:5432/tsdb?user=postgres&password=s3cr3t", From ef2bf612991e69e76eda021a5823ebe1cd63aaab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 17:58:52 +0000 Subject: [PATCH 099/228] Bump github.com/lib/pq from 1.10.7 to 1.10.9 Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.7 to 1.10.9. - [Release notes](https://github.com/lib/pq/releases) - [Commits](https://github.com/lib/pq/compare/v1.10.7...v1.10.9) --- updated-dependencies: - dependency-name: github.com/lib/pq dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c46bd99b9..4d6214c7a 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/alecthomas/kingpin/v2 v2.3.2 github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 - github.com/lib/pq v1.10.7 + github.com/lib/pq v1.10.9 github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_model v0.3.0 github.com/prometheus/common v0.42.0 diff --git a/go.sum b/go.sum index 99f2d1721..4669d9acc 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= From 425c4938ef019df6cf334431488d8ea255d9b9bf Mon Sep 17 00:00:00 2001 From: SuperQ Date: Thu, 1 Jun 2023 10:04:35 +0200 Subject: [PATCH 100/228] Refactor collector descriptors Use individual collector metric descriptor vars to help avoid miss-mapped or unused metrics. Signed-off-by: SuperQ --- collector/pg_database.go | 14 +++---- collector/pg_stat_bgwriter.go | 70 +++++++++++++++++----------------- collector/replication_slots.go | 22 +++++------ 3 files changed, 52 insertions(+), 54 deletions(-) diff --git a/collector/pg_database.go b/collector/pg_database.go index 1ed841ca6..0d21385bf 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -41,13 +41,11 @@ func NewPGDatabaseCollector(config collectorConfig) (Collector, error) { }, nil } -var pgDatabase = map[string]*prometheus.Desc{ - "size_bytes": prometheus.NewDesc( - "pg_database_size_bytes", - "Disk space used by the database", - []string{"datname"}, nil, - ), -} +var pgDatabaseSizeDesc = prometheus.NewDesc( + "pg_database_size_bytes", + "Disk space used by the database", + []string{"datname"}, nil, +) // Update implements Collector and exposes database size. // It is called by the Prometheus registry when collecting metrics. @@ -96,7 +94,7 @@ func (c PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- p } ch <- prometheus.MustNewConstMetric( - pgDatabase["size_bytes"], + pgDatabaseSizeDesc, prometheus.GaugeValue, float64(size), datname, ) } diff --git a/collector/pg_stat_bgwriter.go b/collector/pg_stat_bgwriter.go index 5456423af..46e0baf4b 100644 --- a/collector/pg_stat_bgwriter.go +++ b/collector/pg_stat_bgwriter.go @@ -34,74 +34,74 @@ func NewPGStatBGWriterCollector(collectorConfig) (Collector, error) { const bgWriterSubsystem = "stat_bgwriter" -var statBGWriter = map[string]*prometheus.Desc{ - "checkpoints_timed": prometheus.NewDesc( +var ( + statBGWriterCheckpointsTimedDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_timed_total"), "Number of scheduled checkpoints that have been performed", []string{}, prometheus.Labels{}, - ), - "checkpoints_req": prometheus.NewDesc( + ) + statBGWriterCheckpointsReqDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_req_total"), "Number of requested checkpoints that have been performed", []string{}, prometheus.Labels{}, - ), - "checkpoint_write_time": prometheus.NewDesc( + ) + statBGWriterCheckpointsReqTimeDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoint_write_time_total"), "Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in milliseconds", []string{}, prometheus.Labels{}, - ), - "checkpoint_sync_time": prometheus.NewDesc( + ) + statBGWriterCheckpointsSyncTimeDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoint_sync_time_total"), "Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in milliseconds", []string{}, prometheus.Labels{}, - ), - "buffers_checkpoint": prometheus.NewDesc( + ) + statBGWriterBuffersCheckpointDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_checkpoint_total"), "Number of buffers written during checkpoints", []string{}, prometheus.Labels{}, - ), - "buffers_clean": prometheus.NewDesc( + ) + statBGWriterBuffersCleanDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_clean_total"), "Number of buffers written by the background writer", []string{}, prometheus.Labels{}, - ), - "maxwritten_clean": prometheus.NewDesc( + ) + statBGWriterMaxwrittenCleanDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "maxwritten_clean_total"), "Number of times the background writer stopped a cleaning scan because it had written too many buffers", []string{}, prometheus.Labels{}, - ), - "buffers_backend": prometheus.NewDesc( + ) + statBGWriterBuffersBackendDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_backend_total"), "Number of buffers written directly by a backend", []string{}, prometheus.Labels{}, - ), - "buffers_backend_fsync": prometheus.NewDesc( + ) + statBGWriterBuffersBackendFsyncDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_backend_fsync_total"), "Number of times a backend had to execute its own fsync call (normally the background writer handles those even when the backend does its own write)", []string{}, prometheus.Labels{}, - ), - "buffers_alloc": prometheus.NewDesc( + ) + statBGWriterBuffersAllocDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "buffers_alloc_total"), "Number of buffers allocated", []string{}, prometheus.Labels{}, - ), - "stats_reset": prometheus.NewDesc( + ) + statBGWriterStatsResetDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "stats_reset_total"), "Time at which these statistics were last reset", []string{}, prometheus.Labels{}, - ), -} + ) +) func (PGStatBGWriterCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { row := db.QueryRowContext(ctx, @@ -137,57 +137,57 @@ func (PGStatBGWriterCollector) Update(ctx context.Context, db *sql.DB, ch chan<- } ch <- prometheus.MustNewConstMetric( - statBGWriter["checkpoints_timed"], + statBGWriterCheckpointsTimedDesc, prometheus.CounterValue, float64(cpt), ) ch <- prometheus.MustNewConstMetric( - statBGWriter["checkpoints_req"], + statBGWriterCheckpointsReqDesc, prometheus.CounterValue, float64(cpr), ) ch <- prometheus.MustNewConstMetric( - statBGWriter["checkpoint_write_time"], + statBGWriterCheckpointsReqTimeDesc, prometheus.CounterValue, float64(cpwt), ) ch <- prometheus.MustNewConstMetric( - statBGWriter["checkpoint_sync_time"], + statBGWriterCheckpointsSyncTimeDesc, prometheus.CounterValue, float64(cpst), ) ch <- prometheus.MustNewConstMetric( - statBGWriter["buffers_checkpoint"], + statBGWriterBuffersCheckpointDesc, prometheus.CounterValue, float64(bcp), ) ch <- prometheus.MustNewConstMetric( - statBGWriter["buffers_clean"], + statBGWriterBuffersCleanDesc, prometheus.CounterValue, float64(bc), ) ch <- prometheus.MustNewConstMetric( - statBGWriter["maxwritten_clean"], + statBGWriterMaxwrittenCleanDesc, prometheus.CounterValue, float64(mwc), ) ch <- prometheus.MustNewConstMetric( - statBGWriter["buffers_backend"], + statBGWriterBuffersBackendDesc, prometheus.CounterValue, float64(bb), ) ch <- prometheus.MustNewConstMetric( - statBGWriter["buffers_backend_fsync"], + statBGWriterBuffersBackendFsyncDesc, prometheus.CounterValue, float64(bbf), ) ch <- prometheus.MustNewConstMetric( - statBGWriter["buffers_alloc"], + statBGWriterBuffersAllocDesc, prometheus.CounterValue, float64(ba), ) ch <- prometheus.MustNewConstMetric( - statBGWriter["stats_reset"], + statBGWriterStatsResetDesc, prometheus.CounterValue, float64(sr.Unix()), ) diff --git a/collector/replication_slots.go b/collector/replication_slots.go index a9cad77df..3b3572726 100644 --- a/collector/replication_slots.go +++ b/collector/replication_slots.go @@ -33,23 +33,23 @@ func NewPGReplicationSlotCollector(config collectorConfig) (Collector, error) { return &PGReplicationSlotCollector{log: config.logger}, nil } -var pgReplicationSlot = map[string]*prometheus.Desc{ - "current_wal_lsn": prometheus.NewDesc( +var ( + pgReplicationSlotCurrentWalDesc = prometheus.NewDesc( "pg_replication_slot_current_wal_lsn", "current wal lsn value", []string{"slot_name"}, nil, - ), - "confirmed_flush_lsn": prometheus.NewDesc( + ) + pgReplicationSlotCurrentFlushDesc = prometheus.NewDesc( "pg_replication_slot_confirmed_flush_lsn", "last lsn confirmed flushed to the replication slot", []string{"slot_name"}, nil, - ), - "is_active": prometheus.NewDesc( + ) + pgReplicationSlotIsActiveDesc = prometheus.NewDesc( "pg_replication_slot_is_active", "last lsn confirmed flushed to the replication slot", []string{"slot_name"}, nil, - ), -} + ) +) func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { rows, err := db.QueryContext(ctx, @@ -75,17 +75,17 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha } ch <- prometheus.MustNewConstMetric( - pgReplicationSlot["current_wal_lsn"], + pgReplicationSlotCurrentWalDesc, prometheus.GaugeValue, float64(wal_lsn), slot_name, ) if is_active { ch <- prometheus.MustNewConstMetric( - pgReplicationSlot["confirmed_flush_lsn"], + pgReplicationSlotCurrentFlushDesc, prometheus.GaugeValue, float64(flush_lsn), slot_name, ) } ch <- prometheus.MustNewConstMetric( - pgReplicationSlot["is_active"], + pgReplicationSlotIsActiveDesc, prometheus.GaugeValue, float64(flush_lsn), slot_name, ) } From 4da97f70e02def84f02f476f5d4fa3815b6d8a97 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 17:58:58 +0000 Subject: [PATCH 101/228] Bump github.com/prometheus/common from 0.42.0 to 0.44.0 Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.42.0 to 0.44.0. - [Release notes](https://github.com/prometheus/common/releases) - [Commits](https://github.com/prometheus/common/compare/v0.42.0...v0.44.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 22 +++++++++++----------- go.sum | 44 ++++++++++++++++++++++---------------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index 4d6214c7a..d144f0bc7 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,9 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 github.com/lib/pq v1.10.9 - github.com/prometheus/client_golang v1.14.0 - github.com/prometheus/client_model v0.3.0 - github.com/prometheus/common v0.42.0 + github.com/prometheus/client_golang v1.15.1 + github.com/prometheus/client_model v0.4.0 + github.com/prometheus/common v0.44.0 github.com/prometheus/exporter-toolkit v0.9.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 @@ -19,24 +19,24 @@ require ( require ( 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/cespare/xxhash/v2 v2.2.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/prometheus/procfs v0.9.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect golang.org/x/crypto v0.7.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/oauth2 v0.6.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.28.1 // indirect + google.golang.org/protobuf v1.30.0 // indirect ) diff --git a/go.sum b/go.sum index 4669d9acc..40fb5cf10 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,8 @@ 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/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -20,10 +20,9 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -44,18 +43,19 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/exporter-toolkit v0.9.1 h1:cNkC01riqiOS+kh3zdnNwRsbe/Blh0WwK3ij5rPJ9Sw= github.com/prometheus/exporter-toolkit v0.9.1/go.mod h1:iFlTmFISCix0vyuyBmm0UqOUCTao9+RsAsKJP3YM9ec= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= @@ -65,28 +65,28 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From fab8e625a81f0d59ef300ed9de34f241dc99c886 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Sat, 3 Jun 2023 09:28:17 +0200 Subject: [PATCH 102/228] Update linting * Move errcheck exclude list to config file. * Enable revive linter * Fix up revive linting issues. Signed-off-by: SuperQ --- .golangci.yml | 8 +++++++- cmd/postgres_exporter/main.go | 2 +- collector/replication_slots.go | 18 +++++++++--------- config/config.go | 6 +++--- config/config_test.go | 4 ++-- scripts/errcheck_excludes.txt | 2 -- 6 files changed, 22 insertions(+), 18 deletions(-) delete mode 100644 scripts/errcheck_excludes.txt diff --git a/.golangci.yml b/.golangci.yml index 096572c13..7a03966aa 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,4 +1,8 @@ --- +linters: + enable: + - revive + issues: exclude-rules: - path: _test.go @@ -7,4 +11,6 @@ issues: linters-settings: errcheck: - exclude: scripts/errcheck_excludes.txt + exclude-functions: + # Never check for logger errors. + - (github.com/go-kit/log.Logger).Log diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index efa96738b..04dd6e7c4 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -34,7 +34,7 @@ import ( ) var ( - c = config.ConfigHandler{ + c = config.Handler{ Config: &config.Config{}, } diff --git a/collector/replication_slots.go b/collector/replication_slots.go index 3b3572726..1349487bd 100644 --- a/collector/replication_slots.go +++ b/collector/replication_slots.go @@ -66,27 +66,27 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha defer rows.Close() for rows.Next() { - var slot_name string - var wal_lsn int64 - var flush_lsn int64 - var is_active bool - if err := rows.Scan(&slot_name, &wal_lsn, &flush_lsn, &is_active); err != nil { + var slotName string + var walLSN int64 + var flusLSN int64 + var isActive bool + if err := rows.Scan(&slotName, &walLSN, &flusLSN, &isActive); err != nil { return err } ch <- prometheus.MustNewConstMetric( pgReplicationSlotCurrentWalDesc, - prometheus.GaugeValue, float64(wal_lsn), slot_name, + prometheus.GaugeValue, float64(walLSN), slotName, ) - if is_active { + if isActive { ch <- prometheus.MustNewConstMetric( pgReplicationSlotCurrentFlushDesc, - prometheus.GaugeValue, float64(flush_lsn), slot_name, + prometheus.GaugeValue, float64(flusLSN), slotName, ) } ch <- prometheus.MustNewConstMetric( pgReplicationSlotIsActiveDesc, - prometheus.GaugeValue, float64(flush_lsn), slot_name, + prometheus.GaugeValue, float64(flusLSN), slotName, ) } if err := rows.Err(); err != nil { diff --git a/config/config.go b/config/config.go index 9e514f413..f67969725 100644 --- a/config/config.go +++ b/config/config.go @@ -54,18 +54,18 @@ type UserPass struct { Password string `yaml:"password"` } -type ConfigHandler struct { +type Handler struct { sync.RWMutex Config *Config } -func (ch *ConfigHandler) GetConfig() *Config { +func (ch *Handler) GetConfig() *Config { ch.RLock() defer ch.RUnlock() return ch.Config } -func (ch *ConfigHandler) ReloadConfig(f string, logger log.Logger) error { +func (ch *Handler) ReloadConfig(f string, logger log.Logger) error { config := &Config{} var err error defer func() { diff --git a/config/config_test.go b/config/config_test.go index 63b932adb..d5d23d3ba 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -18,7 +18,7 @@ import ( ) func TestLoadConfig(t *testing.T) { - ch := &ConfigHandler{ + ch := &Handler{ Config: &Config{}, } @@ -29,7 +29,7 @@ func TestLoadConfig(t *testing.T) { } func TestLoadBadConfigs(t *testing.T) { - ch := &ConfigHandler{ + ch := &Handler{ Config: &Config{}, } diff --git a/scripts/errcheck_excludes.txt b/scripts/errcheck_excludes.txt deleted file mode 100644 index 58c2051ac..000000000 --- a/scripts/errcheck_excludes.txt +++ /dev/null @@ -1,2 +0,0 @@ -// Never check for logger errors. -(github.com/go-kit/log.Logger).Log From 1eb4c991f4fe2a194645145cce757e069a845d4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 3 Jun 2023 11:22:41 +0000 Subject: [PATCH 103/228] Bump github.com/prometheus/exporter-toolkit from 0.9.1 to 0.10.0 Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.9.1 to 0.10.0. - [Release notes](https://github.com/prometheus/exporter-toolkit/releases) - [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md) - [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.9.1...v0.10.0) --- updated-dependencies: - dependency-name: github.com/prometheus/exporter-toolkit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index d144f0bc7..59db8685e 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/prometheus/client_golang v1.15.1 github.com/prometheus/client_model v0.4.0 github.com/prometheus/common v0.44.0 - github.com/prometheus/exporter-toolkit v0.9.1 + github.com/prometheus/exporter-toolkit v0.10.0 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 @@ -31,7 +31,7 @@ require ( github.com/prometheus/procfs v0.9.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.7.0 // indirect + golang.org/x/crypto v0.8.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sync v0.1.0 // indirect diff --git a/go.sum b/go.sum index 40fb5cf10..7b7f09319 100644 --- a/go.sum +++ b/go.sum @@ -49,8 +49,8 @@ github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUo github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/exporter-toolkit v0.9.1 h1:cNkC01riqiOS+kh3zdnNwRsbe/Blh0WwK3ij5rPJ9Sw= -github.com/prometheus/exporter-toolkit v0.9.1/go.mod h1:iFlTmFISCix0vyuyBmm0UqOUCTao9+RsAsKJP3YM9ec= +github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= +github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -62,8 +62,8 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= From fe960c6b54d8b308d0c0af5a85dfb925cb65e1ed Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Thu, 8 Jun 2023 14:28:04 -0700 Subject: [PATCH 104/228] Move queries from queries.yaml to collectors (#801) Signed-off-by: Ben Kochie --- collector/collector.go | 4 +- collector/collector_test.go | 56 ++++ collector/pg_database.go | 19 +- collector/pg_database_test.go | 59 +++++ collector/pg_postmaster.go | 58 ++++ collector/pg_postmaster_test.go | 57 ++++ collector/pg_process_idle.go | 106 ++++++++ collector/pg_replication.go | 77 ++++++ collector/pg_replication_test.go | 61 +++++ collector/pg_stat_bgwriter.go | 28 +- collector/pg_stat_bgwriter_test.go | 88 ++++++ collector/pg_stat_statements.go | 152 +++++++++++ collector/pg_stat_statements_test.go | 64 +++++ collector/pg_stat_user_tables.go | 339 ++++++++++++++++++++++++ collector/pg_stat_user_tables_test.go | 138 ++++++++++ collector/pg_statio_user_tables.go | 182 +++++++++++++ collector/pg_statio_user_tables_test.go | 88 ++++++ collector/replication_slots.go | 31 ++- collector/replication_slots_test.go | 101 +++++++ go.mod | 5 + go.sum | 10 + queries.yaml | 246 +---------------- 22 files changed, 1690 insertions(+), 279 deletions(-) create mode 100644 collector/collector_test.go create mode 100644 collector/pg_database_test.go create mode 100644 collector/pg_postmaster.go create mode 100644 collector/pg_postmaster_test.go create mode 100644 collector/pg_process_idle.go create mode 100644 collector/pg_replication.go create mode 100644 collector/pg_replication_test.go create mode 100644 collector/pg_stat_bgwriter_test.go create mode 100644 collector/pg_stat_statements.go create mode 100644 collector/pg_stat_statements_test.go create mode 100644 collector/pg_stat_user_tables.go create mode 100644 collector/pg_stat_user_tables_test.go create mode 100644 collector/pg_statio_user_tables.go create mode 100644 collector/pg_statio_user_tables_test.go create mode 100644 collector/replication_slots_test.go diff --git a/collector/collector.go b/collector/collector.go index e8e418d12..d50e1e72a 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -39,8 +39,8 @@ const ( // Namespace for all metrics. namespace = "pg" - defaultEnabled = true - // defaultDisabled = false + defaultEnabled = true + defaultDisabled = false ) var ( diff --git a/collector/collector_test.go b/collector/collector_test.go new file mode 100644 index 000000000..061de8895 --- /dev/null +++ b/collector/collector_test.go @@ -0,0 +1,56 @@ +// Copyright 2023 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 collector + +import ( + "strings" + + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" +) + +type labelMap map[string]string + +type MetricResult struct { + labels labelMap + value float64 + metricType dto.MetricType +} + +func readMetric(m prometheus.Metric) MetricResult { + pb := &dto.Metric{} + m.Write(pb) + labels := make(labelMap, len(pb.Label)) + for _, v := range pb.Label { + labels[v.GetName()] = v.GetValue() + } + if pb.Gauge != nil { + return MetricResult{labels: labels, value: pb.GetGauge().GetValue(), metricType: dto.MetricType_GAUGE} + } + if pb.Counter != nil { + return MetricResult{labels: labels, value: pb.GetCounter().GetValue(), metricType: dto.MetricType_COUNTER} + } + if pb.Untyped != nil { + return MetricResult{labels: labels, value: pb.GetUntyped().GetValue(), metricType: dto.MetricType_UNTYPED} + } + panic("Unsupported metric type") +} + +func sanitizeQuery(q string) string { + q = strings.Join(strings.Fields(q), " ") + q = strings.Replace(q, "(", "\\(", -1) + q = strings.Replace(q, ")", "\\)", -1) + q = strings.Replace(q, "*", "\\*", -1) + q = strings.Replace(q, "$", "\\$", -1) + return q +} diff --git a/collector/pg_database.go b/collector/pg_database.go index 0d21385bf..8a027e2db 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -41,10 +41,15 @@ func NewPGDatabaseCollector(config collectorConfig) (Collector, error) { }, nil } -var pgDatabaseSizeDesc = prometheus.NewDesc( - "pg_database_size_bytes", - "Disk space used by the database", - []string{"datname"}, nil, +var ( + pgDatabaseSizeDesc = prometheus.NewDesc( + "pg_database_size_bytes", + "Disk space used by the database", + []string{"datname"}, nil, + ) + + pgDatabaseQuery = "SELECT pg_database.datname FROM pg_database;" + pgDatabaseSizeQuery = "SELECT pg_database_size($1)" ) // Update implements Collector and exposes database size. @@ -58,9 +63,7 @@ var pgDatabaseSizeDesc = prometheus.NewDesc( func (c PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { // Query the list of databases rows, err := db.QueryContext(ctx, - `SELECT pg_database.datname - FROM pg_database; - `, + pgDatabaseQuery, ) if err != nil { return err @@ -88,7 +91,7 @@ func (c PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- p // Query the size of the databases for _, datname := range databases { var size int64 - err = db.QueryRowContext(ctx, "SELECT pg_database_size($1)", datname).Scan(&size) + err = db.QueryRowContext(ctx, pgDatabaseSizeQuery, datname).Scan(&size) if err != nil { return err } diff --git a/collector/pg_database_test.go b/collector/pg_database_test.go new file mode 100644 index 000000000..bb108bb86 --- /dev/null +++ b/collector/pg_database_test.go @@ -0,0 +1,59 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGDatabaseCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + mock.ExpectQuery(sanitizeQuery(pgDatabaseQuery)).WillReturnRows(sqlmock.NewRows([]string{"datname"}). + AddRow("postgres")) + + mock.ExpectQuery(sanitizeQuery(pgDatabaseSizeQuery)).WithArgs("postgres").WillReturnRows(sqlmock.NewRows([]string{"pg_database_size"}). + AddRow(1024)) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGDatabaseCollector{} + if err := c.Update(context.Background(), db, ch); err != nil { + t.Errorf("Error calling PGDatabaseCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datname": "postgres"}, value: 1024, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_postmaster.go b/collector/pg_postmaster.go new file mode 100644 index 000000000..b7d844e18 --- /dev/null +++ b/collector/pg_postmaster.go @@ -0,0 +1,58 @@ +// Copyright 2023 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 collector + +import ( + "context" + "database/sql" + + "github.com/prometheus/client_golang/prometheus" +) + +func init() { + registerCollector("postmaster", defaultEnabled, NewPGPostmasterCollector) +} + +type PGPostmasterCollector struct { +} + +func NewPGPostmasterCollector(collectorConfig) (Collector, error) { + return &PGPostmasterCollector{}, nil +} + +var ( + pgPostMasterStartTimeSeconds = prometheus.NewDesc( + "pg_postmaster_start_time_seconds", + "Time at which postmaster started", + []string{}, nil, + ) + + pgPostmasterQuery = "SELECT pg_postmaster_start_time from pg_postmaster_start_time();" +) + +func (c *PGPostmasterCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { + row := db.QueryRowContext(ctx, + pgPostmasterQuery) + + var startTimeSeconds float64 + err := row.Scan(&startTimeSeconds) + if err != nil { + return err + } + ch <- prometheus.MustNewConstMetric( + pgPostMasterStartTimeSeconds, + prometheus.GaugeValue, startTimeSeconds, + ) + return nil +} diff --git a/collector/pg_postmaster_test.go b/collector/pg_postmaster_test.go new file mode 100644 index 000000000..9b93a5c91 --- /dev/null +++ b/collector/pg_postmaster_test.go @@ -0,0 +1,57 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPgPostmasterCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + mock.ExpectQuery(sanitizeQuery(pgPostmasterQuery)).WillReturnRows(sqlmock.NewRows([]string{"pg_postmaster_start_time"}). + AddRow(1685739904)) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGPostmasterCollector{} + + if err := c.Update(context.Background(), db, ch); err != nil { + t.Errorf("Error calling PGPostmasterCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{}, value: 1685739904, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_process_idle.go b/collector/pg_process_idle.go new file mode 100644 index 000000000..b8c1a6cb7 --- /dev/null +++ b/collector/pg_process_idle.go @@ -0,0 +1,106 @@ +// Copyright 2023 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 collector + +import ( + "context" + "database/sql" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +func init() { + registerCollector("statements", defaultEnabled, NewPGProcessIdleCollector) +} + +type PGProcessIdleCollector struct { + log log.Logger +} + +const processIdleSubsystem = "process_idle" + +func NewPGProcessIdleCollector(config collectorConfig) (Collector, error) { + return &PGProcessIdleCollector{log: config.logger}, nil +} + +var pgProcessIdleSeconds = prometheus.NewDesc( + prometheus.BuildFQName(namespace, processIdleSubsystem, "seconds"), + "Idle time of server processes", + []string{"application_name"}, + prometheus.Labels{}, +) + +func (PGProcessIdleCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { + row := db.QueryRowContext(ctx, + `WITH + metrics AS ( + SELECT + application_name, + SUM(EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - state_change))::bigint)::float AS process_idle_seconds_sum, + COUNT(*) AS process_idle_seconds_count + FROM pg_stat_activity + WHERE state = 'idle' + GROUP BY application_name + ), + buckets AS ( + SELECT + application_name, + le, + SUM( + CASE WHEN EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - state_change)) <= le + THEN 1 + ELSE 0 + END + )::bigint AS bucket + FROM + pg_stat_activity, + UNNEST(ARRAY[1, 2, 5, 15, 30, 60, 90, 120, 300]) AS le + GROUP BY application_name, le + ORDER BY application_name, le + ) + SELECT + application_name, + process_idle_seconds_sum as seconds_sum, + process_idle_seconds_count as seconds_count, + ARRAY_AGG(le) AS seconds, + ARRAY_AGG(bucket) AS seconds_bucket + FROM metrics JOIN buckets USING (application_name) + GROUP BY 1, 2, 3;`) + + var applicationName string + var secondsSum int64 + var secondsCount uint64 + var seconds []int64 + var secondsBucket []uint64 + + err := row.Scan(&applicationName, &secondsSum, &secondsCount, &seconds, &secondsBucket) + + var buckets = make(map[float64]uint64, len(seconds)) + for i, second := range seconds { + if i >= len(secondsBucket) { + break + } + buckets[float64(second)] = secondsBucket[i] + } + if err != nil { + return err + } + ch <- prometheus.MustNewConstHistogram( + pgProcessIdleSeconds, + secondsCount, float64(secondsSum), buckets, + applicationName, + ) + return nil +} diff --git a/collector/pg_replication.go b/collector/pg_replication.go new file mode 100644 index 000000000..10e4de521 --- /dev/null +++ b/collector/pg_replication.go @@ -0,0 +1,77 @@ +// Copyright 2023 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 collector + +import ( + "context" + "database/sql" + + "github.com/prometheus/client_golang/prometheus" +) + +func init() { + registerCollector("replication", defaultEnabled, NewPGReplicationCollector) +} + +type PGReplicationCollector struct { +} + +func NewPGReplicationCollector(collectorConfig) (Collector, error) { + return &PGPostmasterCollector{}, nil +} + +var ( + pgReplicationLag = prometheus.NewDesc( + "pg_replication_lag", + "Replication lag behind master in seconds", + []string{}, nil, + ) + pgReplicationIsReplica = prometheus.NewDesc( + "pg_replication_is_replica", + "Indicates if the server is a replica", + []string{}, nil, + ) + + pgReplicationQuery = `SELECT + CASE + WHEN NOT pg_is_in_recovery() THEN 0 + ELSE GREATEST (0, EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))) + END AS lag, + CASE + WHEN pg_is_in_recovery() THEN 1 + ELSE 0 + END as is_replica` +) + +func (c *PGReplicationCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { + row := db.QueryRowContext(ctx, + pgReplicationQuery, + ) + + var lag float64 + var isReplica int64 + err := row.Scan(&lag, &isReplica) + if err != nil { + return err + } + ch <- prometheus.MustNewConstMetric( + pgReplicationLag, + prometheus.GaugeValue, lag, + ) + ch <- prometheus.MustNewConstMetric( + pgReplicationIsReplica, + prometheus.GaugeValue, float64(isReplica), + ) + return nil +} diff --git a/collector/pg_replication_test.go b/collector/pg_replication_test.go new file mode 100644 index 000000000..4d240cdf3 --- /dev/null +++ b/collector/pg_replication_test.go @@ -0,0 +1,61 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPgReplicationCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + columns := []string{"lag", "is_replica"} + rows := sqlmock.NewRows(columns). + AddRow(1000, 1) + mock.ExpectQuery(sanitizeQuery(pgReplicationQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGReplicationCollector{} + + if err := c.Update(context.Background(), db, ch); err != nil { + t.Errorf("Error calling PGReplicationCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{}, value: 1000, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{}, value: 1, metricType: dto.MetricType_GAUGE}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_stat_bgwriter.go b/collector/pg_stat_bgwriter.go index 46e0baf4b..6efe87d52 100644 --- a/collector/pg_stat_bgwriter.go +++ b/collector/pg_stat_bgwriter.go @@ -101,23 +101,25 @@ var ( []string{}, prometheus.Labels{}, ) + + statBGWriterQuery = `SELECT + checkpoints_timed + ,checkpoints_req + ,checkpoint_write_time + ,checkpoint_sync_time + ,buffers_checkpoint + ,buffers_clean + ,maxwritten_clean + ,buffers_backend + ,buffers_backend_fsync + ,buffers_alloc + ,stats_reset + FROM pg_stat_bgwriter;` ) func (PGStatBGWriterCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { row := db.QueryRowContext(ctx, - `SELECT - checkpoints_timed - ,checkpoints_req - ,checkpoint_write_time - ,checkpoint_sync_time - ,buffers_checkpoint - ,buffers_clean - ,maxwritten_clean - ,buffers_backend - ,buffers_backend_fsync - ,buffers_alloc - ,stats_reset - FROM pg_stat_bgwriter;`) + statBGWriterQuery) var cpt int var cpr int diff --git a/collector/pg_stat_bgwriter_test.go b/collector/pg_stat_bgwriter_test.go new file mode 100644 index 000000000..54f625c9e --- /dev/null +++ b/collector/pg_stat_bgwriter_test.go @@ -0,0 +1,88 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGStatBGWriterCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + columns := []string{ + "checkpoints_timed", + "checkpoints_req", + "checkpoint_write_time", + "checkpoint_sync_time", + "buffers_checkpoint", + "buffers_clean", + "maxwritten_clean", + "buffers_backend", + "buffers_backend_fsync", + "buffers_alloc", + "stats_reset"} + + srT, err := time.Parse("2006-01-02 15:04:05.00000-07", "2023-05-25 17:10:42.81132-07") + if err != nil { + t.Fatalf("Error parsing time: %s", err) + } + + rows := sqlmock.NewRows(columns). + AddRow(354, 4945, 289097744, 1242257, 3275602074, 89320867, 450139, 2034563757, 0, 2725688749, srT) + mock.ExpectQuery(sanitizeQuery(statBGWriterQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatBGWriterCollector{} + + if err := c.Update(context.Background(), db, ch); err != nil { + t.Errorf("Error calling PGStatBGWriterCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 354}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 4945}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 289097744}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 1242257}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 3275602074}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 89320867}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 450139}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 2034563757}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 2725688749}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 1685059842}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_stat_statements.go b/collector/pg_stat_statements.go new file mode 100644 index 000000000..78485f619 --- /dev/null +++ b/collector/pg_stat_statements.go @@ -0,0 +1,152 @@ +// Copyright 2023 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 collector + +import ( + "context" + "database/sql" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +func init() { + // WARNING: + // Disabled by default because this set of metrics can be quite expensive on a busy server + // Every unique query will cause a new timeseries to be created + registerCollector("statements", defaultDisabled, NewPGStatStatementsCollector) +} + +type PGStatStatementsCollector struct { + log log.Logger +} + +const statStatementsSubsystem = "stat_statements" + +func NewPGStatStatementsCollector(config collectorConfig) (Collector, error) { + return &PGStatStatementsCollector{log: config.logger}, nil +} + +var ( + statSTatementsCallsTotal = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statStatementsSubsystem, "calls_total"), + "Number of times executed", + []string{"user", "datname", "queryid"}, + prometheus.Labels{}, + ) + statStatementsSecondsTotal = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statStatementsSubsystem, "seconds_total"), + "Total time spent in the statement, in seconds", + []string{"user", "datname", "queryid"}, + prometheus.Labels{}, + ) + statStatementsRowsTotal = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statStatementsSubsystem, "rows_total"), + "Total number of rows retrieved or affected by the statement", + []string{"user", "datname", "queryid"}, + prometheus.Labels{}, + ) + statStatementsBlockReadSecondsTotal = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statStatementsSubsystem, "block_read_seconds_total"), + "Total time the statement spent reading blocks, in seconds", + []string{"user", "datname", "queryid"}, + prometheus.Labels{}, + ) + statStatementsBlockWriteSecondsTotal = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statStatementsSubsystem, "block_write_seconds_total"), + "Total time the statement spent writing blocks, in seconds", + []string{"user", "datname", "queryid"}, + prometheus.Labels{}, + ) + + pgStatStatementsQuery = `SELECT + pg_get_userbyid(userid) as user, + pg_database.datname, + pg_stat_statements.queryid, + pg_stat_statements.calls as calls_total, + pg_stat_statements.total_time / 1000.0 as seconds_total, + pg_stat_statements.rows as rows_total, + pg_stat_statements.blk_read_time / 1000.0 as block_read_seconds_total, + pg_stat_statements.blk_write_time / 1000.0 as block_write_seconds_total + FROM pg_stat_statements + JOIN pg_database + ON pg_database.oid = pg_stat_statements.dbid + WHERE + total_time > ( + SELECT percentile_cont(0.1) + WITHIN GROUP (ORDER BY total_time) + FROM pg_stat_statements + ) + ORDER BY seconds_total DESC + LIMIT 100;` +) + +func (PGStatStatementsCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { + rows, err := db.QueryContext(ctx, + pgStatStatementsQuery) + + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var user string + var datname string + var queryid string + var callsTotal int64 + var secondsTotal float64 + var rowsTotal int64 + var blockReadSecondsTotal float64 + var blockWriteSecondsTotal float64 + + if err := rows.Scan(&user, &datname, &queryid, &callsTotal, &secondsTotal, &rowsTotal, &blockReadSecondsTotal, &blockWriteSecondsTotal); err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric( + statSTatementsCallsTotal, + prometheus.CounterValue, + float64(callsTotal), + user, datname, queryid, + ) + ch <- prometheus.MustNewConstMetric( + statStatementsSecondsTotal, + prometheus.CounterValue, + secondsTotal, + user, datname, queryid, + ) + ch <- prometheus.MustNewConstMetric( + statStatementsRowsTotal, + prometheus.CounterValue, + float64(rowsTotal), + user, datname, queryid, + ) + ch <- prometheus.MustNewConstMetric( + statStatementsBlockReadSecondsTotal, + prometheus.CounterValue, + blockReadSecondsTotal, + user, datname, queryid, + ) + ch <- prometheus.MustNewConstMetric( + statStatementsBlockWriteSecondsTotal, + prometheus.CounterValue, + blockWriteSecondsTotal, + user, datname, queryid, + ) + } + if err := rows.Err(); err != nil { + return err + } + return nil +} diff --git a/collector/pg_stat_statements_test.go b/collector/pg_stat_statements_test.go new file mode 100644 index 000000000..a5c5cab57 --- /dev/null +++ b/collector/pg_stat_statements_test.go @@ -0,0 +1,64 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGStateStatementsCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} + rows := sqlmock.NewRows(columns). + AddRow("postgres", "postgres", 1500, 5, 0.4, 100, 0.1, 0.2) + mock.ExpectQuery(sanitizeQuery(pgStatStatementsQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatStatementsCollector{} + + if err := c.Update(context.Background(), db, ch); err != nil { + t.Errorf("Error calling PGStatStatementsCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 5}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.4}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 100}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.1}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.2}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_stat_user_tables.go b/collector/pg_stat_user_tables.go new file mode 100644 index 000000000..1f267a7ee --- /dev/null +++ b/collector/pg_stat_user_tables.go @@ -0,0 +1,339 @@ +// Copyright 2023 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 collector + +import ( + "context" + "database/sql" + "time" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +func init() { + registerCollector("user_tables", defaultEnabled, NewPGStatUserTablesCollector) +} + +type PGStatUserTablesCollector struct { + log log.Logger +} + +const userTableSubsystem = "stat_user_tables" + +func NewPGStatUserTablesCollector(config collectorConfig) (Collector, error) { + return &PGStatUserTablesCollector{log: config.logger}, nil +} + +var ( + statUserTablesSeqScan = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "seq_scan"), + "Number of sequential scans initiated on this table", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesSeqTupRead = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "seq_tup_read"), + "Number of live rows fetched by sequential scans", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesIdxScan = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "idx_scan"), + "Number of index scans initiated on this table", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesIdxTupFetch = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "idx_tup_fetch"), + "Number of live rows fetched by index scans", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesNTupIns = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "n_tup_ins"), + "Number of rows inserted", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesNTupUpd = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "n_tup_upd"), + "Number of rows updated", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesNTupDel = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "n_tup_del"), + "Number of rows deleted", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesNTupHotUpd = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "n_tup_hot_upd"), + "Number of rows HOT updated (i.e., with no separate index update required)", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesNLiveTup = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "n_live_tup"), + "Estimated number of live rows", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesNDeadTup = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "n_dead_tup"), + "Estimated number of dead rows", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesNModSinceAnalyze = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "n_mod_since_analyze"), + "Estimated number of rows changed since last analyze", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesLastVacuum = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "last_vacuum"), + "Last time at which this table was manually vacuumed (not counting VACUUM FULL)", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesLastAutovacuum = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "last_autovacuum"), + "Last time at which this table was vacuumed by the autovacuum daemon", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesLastAnalyze = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "last_analyze"), + "Last time at which this table was manually analyzed", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesLastAutoanalyze = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "last_autoanalyze"), + "Last time at which this table was analyzed by the autovacuum daemon", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesVacuumCount = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "vacuum_count"), + "Number of times this table has been manually vacuumed (not counting VACUUM FULL)", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesAutovacuumCount = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "autovacuum_count"), + "Number of times this table has been vacuumed by the autovacuum daemon", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesAnalyzeCount = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "analyze_count"), + "Number of times this table has been manually analyzed", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTablesAutoanalyzeCount = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "autoanalyze_count"), + "Number of times this table has been analyzed by the autovacuum daemon", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + + statUserTablesQuery = `SELECT + current_database() datname, + schemaname, + relname, + seq_scan, + seq_tup_read, + idx_scan, + idx_tup_fetch, + n_tup_ins, + n_tup_upd, + n_tup_del, + n_tup_hot_upd, + n_live_tup, + n_dead_tup, + n_mod_since_analyze, + COALESCE(last_vacuum, '1970-01-01Z') as last_vacuum, + COALESCE(last_autovacuum, '1970-01-01Z') as last_autovacuum, + COALESCE(last_analyze, '1970-01-01Z') as last_analyze, + COALESCE(last_autoanalyze, '1970-01-01Z') as last_autoanalyze, + vacuum_count, + autovacuum_count, + analyze_count, + autoanalyze_count + FROM + pg_stat_user_tables` +) + +func (c *PGStatUserTablesCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { + rows, err := db.QueryContext(ctx, + statUserTablesQuery) + + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var datname string + var schemaname string + var relname string + var seqScan int64 + var seqTupRead int64 + var idxScan int64 + var idxTupFetch int64 + var nTupIns int64 + var nTupUpd int64 + var nTupDel int64 + var nTupHotUpd int64 + var nLiveTup int64 + var nDeadTup int64 + var nModSinceAnalyze int64 + var lastVacuum time.Time + var lastAutovacuum time.Time + var lastAnalyze time.Time + var lastAutoanalyze time.Time + var vacuumCount int64 + var autovacuumCount int64 + var analyzeCount int64 + var autoanalyzeCount int64 + + if err := rows.Scan(&datname, &schemaname, &relname, &seqScan, &seqTupRead, &idxScan, &idxTupFetch, &nTupIns, &nTupUpd, &nTupDel, &nTupHotUpd, &nLiveTup, &nDeadTup, &nModSinceAnalyze, &lastVacuum, &lastAutovacuum, &lastAnalyze, &lastAutoanalyze, &vacuumCount, &autovacuumCount, &analyzeCount, &autoanalyzeCount); err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric( + statUserTablesSeqScan, + prometheus.CounterValue, + float64(seqScan), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesSeqTupRead, + prometheus.CounterValue, + float64(seqTupRead), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesIdxScan, + prometheus.CounterValue, + float64(idxScan), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesIdxTupFetch, + prometheus.CounterValue, + float64(idxTupFetch), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesNTupIns, + prometheus.CounterValue, + float64(nTupIns), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesNTupUpd, + prometheus.CounterValue, + float64(nTupUpd), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesNTupDel, + prometheus.CounterValue, + float64(nTupDel), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesNTupHotUpd, + prometheus.CounterValue, + float64(nTupHotUpd), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesNLiveTup, + prometheus.GaugeValue, + float64(nLiveTup), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesNDeadTup, + prometheus.GaugeValue, + float64(nDeadTup), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesNModSinceAnalyze, + prometheus.GaugeValue, + float64(nModSinceAnalyze), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesLastVacuum, + prometheus.GaugeValue, + float64(lastVacuum.Unix()), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesLastAutovacuum, + prometheus.GaugeValue, + float64(lastAutovacuum.Unix()), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesLastAnalyze, + prometheus.GaugeValue, + float64(lastAnalyze.Unix()), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesLastAutoanalyze, + prometheus.GaugeValue, + float64(lastAutoanalyze.Unix()), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesVacuumCount, + prometheus.CounterValue, + float64(vacuumCount), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesAutovacuumCount, + prometheus.CounterValue, + float64(autovacuumCount), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesAnalyzeCount, + prometheus.CounterValue, + float64(analyzeCount), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statUserTablesAutoanalyzeCount, + prometheus.CounterValue, + float64(autoanalyzeCount), + datname, schemaname, relname, + ) + } + + if err := rows.Err(); err != nil { + return err + } + return nil +} diff --git a/collector/pg_stat_user_tables_test.go b/collector/pg_stat_user_tables_test.go new file mode 100644 index 000000000..29b5d15f1 --- /dev/null +++ b/collector/pg_stat_user_tables_test.go @@ -0,0 +1,138 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGStatUserTablesCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + lastVacuumTime, err := time.Parse("2006-01-02Z", "2023-06-02Z") + if err != nil { + t.Fatalf("Error parsing vacuum time: %s", err) + } + lastAutoVacuumTime, err := time.Parse("2006-01-02Z", "2023-06-03Z") + if err != nil { + t.Fatalf("Error parsing vacuum time: %s", err) + } + lastAnalyzeTime, err := time.Parse("2006-01-02Z", "2023-06-04Z") + if err != nil { + t.Fatalf("Error parsing vacuum time: %s", err) + } + lastAutoAnalyzeTime, err := time.Parse("2006-01-02Z", "2023-06-05Z") + if err != nil { + t.Fatalf("Error parsing vacuum time: %s", err) + } + + columns := []string{ + "datname", + "schemaname", + "relname", + "seq_scan", + "seq_tup_read", + "idx_scan", + "idx_tup_fetch", + "n_tup_ins", + "n_tup_upd", + "n_tup_del", + "n_tup_hot_upd", + "n_live_tup", + "n_dead_tup", + "n_mod_since_analyze", + "last_vacuum", + "last_autovacuum", + "last_analyze", + "last_autoanalyze", + "vacuum_count", + "autovacuum_count", + "analyze_count", + "autoanalyze_count"} + rows := sqlmock.NewRows(columns). + AddRow("postgres", + "public", + "a_table", + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 0, + lastVacuumTime, + lastAutoVacuumTime, + lastAnalyzeTime, + lastAutoAnalyzeTime, + 11, + 12, + 13, + 14) + mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows) + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatUserTablesCollector{} + + if err := c.Update(context.Background(), db, ch); err != nil { + t.Errorf("Error calling PGStatUserTablesCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 1}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 2}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 3}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 4}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 5}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 6}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 7}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 8}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 9}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 10}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685664000}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685750400}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685836800}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 1685923200}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 11}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 12}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 13}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 14}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_statio_user_tables.go b/collector/pg_statio_user_tables.go new file mode 100644 index 000000000..e84631df5 --- /dev/null +++ b/collector/pg_statio_user_tables.go @@ -0,0 +1,182 @@ +// Copyright 2023 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 collector + +import ( + "context" + "database/sql" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +func init() { + registerCollector("statio_user_tables", defaultEnabled, NewPGStatIOUserTablesCollector) +} + +type PGStatIOUserTablesCollector struct { + log log.Logger +} + +const statioUserTableSubsystem = "statio_user_tables" + +func NewPGStatIOUserTablesCollector(config collectorConfig) (Collector, error) { + return &PGStatIOUserTablesCollector{log: config.logger}, nil +} + +var ( + statioUserTablesHeapBlksRead = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statioUserTableSubsystem, "heap_blocks_read"), + "Number of disk blocks read from this table", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statioUserTablesHeapBlksHit = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statioUserTableSubsystem, "heap_blocks_hit"), + "Number of buffer hits in this table", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statioUserTablesIdxBlksRead = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statioUserTableSubsystem, "idx_blocks_read"), + "Number of disk blocks read from all indexes on this table", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statioUserTablesIdxBlksHit = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statioUserTableSubsystem, "idx_blocks_hit"), + "Number of buffer hits in all indexes on this table", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statioUserTablesToastBlksRead = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statioUserTableSubsystem, "toast_blocks_read"), + "Number of disk blocks read from this table's TOAST table (if any)", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statioUserTablesToastBlksHit = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statioUserTableSubsystem, "toast_blocks_hit"), + "Number of buffer hits in this table's TOAST table (if any)", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statioUserTablesTidxBlksRead = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statioUserTableSubsystem, "tidx_blocks_read"), + "Number of disk blocks read from this table's TOAST table indexes (if any)", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statioUserTablesTidxBlksHit = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statioUserTableSubsystem, "tidx_blocks_hit"), + "Number of buffer hits in this table's TOAST table indexes (if any)", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + + statioUserTablesQuery = `SELECT + current_database() datname, + schemaname, + relname, + heap_blks_read, + heap_blks_hit, + idx_blks_read, + idx_blks_hit, + toast_blks_read, + toast_blks_hit, + tidx_blks_read, + tidx_blks_hit + FROM pg_statio_user_tables` +) + +func (PGStatIOUserTablesCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { + rows, err := db.QueryContext(ctx, + statioUserTablesQuery) + + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var datname string + var schemaname string + var relname string + var heapBlksRead int64 + var heapBlksHit int64 + var idxBlksRead int64 + var idxBlksHit int64 + var toastBlksRead int64 + var toastBlksHit int64 + var tidxBlksRead int64 + var tidxBlksHit int64 + + if err := rows.Scan(&datname, &schemaname, &relname, &heapBlksRead, &heapBlksHit, &idxBlksRead, &idxBlksHit, &toastBlksRead, &toastBlksHit, &tidxBlksRead, &tidxBlksHit); err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric( + statioUserTablesHeapBlksRead, + prometheus.CounterValue, + float64(heapBlksRead), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statioUserTablesHeapBlksHit, + prometheus.CounterValue, + float64(heapBlksHit), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statioUserTablesIdxBlksRead, + prometheus.CounterValue, + float64(idxBlksRead), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statioUserTablesIdxBlksHit, + prometheus.CounterValue, + float64(idxBlksHit), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statioUserTablesToastBlksRead, + prometheus.CounterValue, + float64(toastBlksRead), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statioUserTablesToastBlksHit, + prometheus.CounterValue, + float64(toastBlksHit), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statioUserTablesTidxBlksRead, + prometheus.CounterValue, + float64(tidxBlksRead), + datname, schemaname, relname, + ) + ch <- prometheus.MustNewConstMetric( + statioUserTablesTidxBlksHit, + prometheus.CounterValue, + float64(tidxBlksHit), + datname, schemaname, relname, + ) + } + if err := rows.Err(); err != nil { + return err + } + return nil +} diff --git a/collector/pg_statio_user_tables_test.go b/collector/pg_statio_user_tables_test.go new file mode 100644 index 000000000..0a7174d80 --- /dev/null +++ b/collector/pg_statio_user_tables_test.go @@ -0,0 +1,88 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGStatIOUserTablesCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + columns := []string{ + "datname", + "schemaname", + "relname", + "heap_blks_read", + "heap_blks_hit", + "idx_blks_read", + "idx_blks_hit", + "toast_blks_read", + "toast_blks_hit", + "tidx_blks_read", + "tidx_blks_hit", + } + rows := sqlmock.NewRows(columns). + AddRow("postgres", + "public", + "a_table", + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8) + mock.ExpectQuery(sanitizeQuery(statioUserTablesQuery)).WillReturnRows(rows) + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatIOUserTablesCollector{} + + if err := c.Update(context.Background(), db, ch); err != nil { + t.Errorf("Error calling PGStatIOUserTablesCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 1}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 2}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 3}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 4}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 5}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 6}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 7}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 8}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/replication_slots.go b/collector/replication_slots.go index 1349487bd..0aaf39cdc 100644 --- a/collector/replication_slots.go +++ b/collector/replication_slots.go @@ -46,20 +46,22 @@ var ( ) pgReplicationSlotIsActiveDesc = prometheus.NewDesc( "pg_replication_slot_is_active", - "last lsn confirmed flushed to the replication slot", + "whether the replication slot is active or not", []string{"slot_name"}, nil, ) + + pgReplicationSlotQuery = `SELECT + slot_name, + pg_current_wal_lsn() - '0/0' AS current_wal_lsn, + coalesce(confirmed_flush_lsn, '0/0') - '0/0', + active + FROM + pg_replication_slots;` ) func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { rows, err := db.QueryContext(ctx, - `SELECT - slot_name, - pg_current_wal_lsn() - '0/0' AS current_wal_lsn, - coalesce(confirmed_flush_lsn, '0/0') - '0/0', - active - FROM - pg_replication_slots;`) + pgReplicationSlotQuery) if err != nil { return err } @@ -68,12 +70,17 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha for rows.Next() { var slotName string var walLSN int64 - var flusLSN int64 + var flushLSN int64 var isActive bool - if err := rows.Scan(&slotName, &walLSN, &flusLSN, &isActive); err != nil { + if err := rows.Scan(&slotName, &walLSN, &flushLSN, &isActive); err != nil { return err } + isActiveValue := 0 + if isActive { + isActiveValue = 1 + } + ch <- prometheus.MustNewConstMetric( pgReplicationSlotCurrentWalDesc, prometheus.GaugeValue, float64(walLSN), slotName, @@ -81,12 +88,12 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch cha if isActive { ch <- prometheus.MustNewConstMetric( pgReplicationSlotCurrentFlushDesc, - prometheus.GaugeValue, float64(flusLSN), slotName, + prometheus.GaugeValue, float64(flushLSN), slotName, ) } ch <- prometheus.MustNewConstMetric( pgReplicationSlotIsActiveDesc, - prometheus.GaugeValue, float64(flusLSN), slotName, + prometheus.GaugeValue, float64(isActiveValue), slotName, ) } if err := rows.Err(); err != nil { diff --git a/collector/replication_slots_test.go b/collector/replication_slots_test.go new file mode 100644 index 000000000..53bafafad --- /dev/null +++ b/collector/replication_slots_test.go @@ -0,0 +1,101 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPgReplicationSlotCollectorActive(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + columns := []string{"slot_name", "current_wal_lsn", "confirmed_flush_lsn", "active"} + rows := sqlmock.NewRows(columns). + AddRow("test_slot", 5, 3, true) + mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGReplicationSlotCollector{} + + if err := c.Update(context.Background(), db, ch); err != nil { + t.Errorf("Error calling PGPostmasterCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"slot_name": "test_slot"}, value: 5, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot"}, value: 3, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot"}, value: 1, metricType: dto.MetricType_GAUGE}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} + +func TestPgReplicationSlotCollectorInActive(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + columns := []string{"slot_name", "current_wal_lsn", "confirmed_flush_lsn", "active"} + rows := sqlmock.NewRows(columns). + AddRow("test_slot", 6, 12, false) + mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGReplicationSlotCollector{} + + if err := c.Update(context.Background(), db, ch); err != nil { + t.Errorf("Error calling PGReplicationSlotCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"slot_name": "test_slot"}, value: 6, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot"}, value: 0, metricType: dto.MetricType_GAUGE}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } + +} diff --git a/go.mod b/go.mod index 59db8685e..6444a66e4 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/prometheus-community/postgres_exporter go 1.19 require ( + github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/alecthomas/kingpin/v2 v2.3.2 github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 @@ -11,6 +12,7 @@ require ( github.com/prometheus/client_model v0.4.0 github.com/prometheus/common v0.44.0 github.com/prometheus/exporter-toolkit v0.10.0 + github.com/smartystreets/goconvey v1.8.0 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 @@ -23,13 +25,16 @@ require ( github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/jpillora/backoff v1.0.0 // indirect + github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/smartystreets/assertions v1.13.1 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect golang.org/x/crypto v0.8.0 // indirect golang.org/x/net v0.10.0 // indirect diff --git a/go.sum b/go.sum index 7b7f09319..12673c116 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU= github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= @@ -25,8 +27,12 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -56,6 +62,10 @@ github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0ZxudX+ThRdWfU= +github.com/smartystreets/assertions v1.13.1/go.mod h1:cXr/IwVfSo/RbCSPhoAPv73p3hlSdrBH/b3SdnW/LMY= +github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w= +github.com/smartystreets/goconvey v1.8.0/go.mod h1:EdX8jtrTIj26jmjCOVNMVSIYAtgexqXKHOXW2Dx9JLg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= diff --git a/queries.yaml b/queries.yaml index 1e54f326d..189ce0866 100644 --- a/queries.yaml +++ b/queries.yaml @@ -1,244 +1,2 @@ -pg_replication: - query: "SELECT CASE WHEN NOT pg_is_in_recovery() THEN 0 ELSE GREATEST (0, EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))) END AS lag" - master: true - metrics: - - lag: - usage: "GAUGE" - description: "Replication lag behind master in seconds" - -pg_postmaster: - query: "SELECT pg_postmaster_start_time as start_time_seconds from pg_postmaster_start_time()" - master: true - metrics: - - start_time_seconds: - usage: "GAUGE" - description: "Time at which postmaster started" - -pg_stat_user_tables: - query: | - SELECT - current_database() datname, - schemaname, - relname, - seq_scan, - seq_tup_read, - idx_scan, - idx_tup_fetch, - n_tup_ins, - n_tup_upd, - n_tup_del, - n_tup_hot_upd, - n_live_tup, - n_dead_tup, - n_mod_since_analyze, - COALESCE(last_vacuum, '1970-01-01Z') as last_vacuum, - COALESCE(last_autovacuum, '1970-01-01Z') as last_autovacuum, - COALESCE(last_analyze, '1970-01-01Z') as last_analyze, - COALESCE(last_autoanalyze, '1970-01-01Z') as last_autoanalyze, - vacuum_count, - autovacuum_count, - analyze_count, - autoanalyze_count - FROM - pg_stat_user_tables - metrics: - - datname: - usage: "LABEL" - description: "Name of current database" - - schemaname: - usage: "LABEL" - description: "Name of the schema that this table is in" - - relname: - usage: "LABEL" - description: "Name of this table" - - seq_scan: - usage: "COUNTER" - description: "Number of sequential scans initiated on this table" - - seq_tup_read: - usage: "COUNTER" - description: "Number of live rows fetched by sequential scans" - - idx_scan: - usage: "COUNTER" - description: "Number of index scans initiated on this table" - - idx_tup_fetch: - usage: "COUNTER" - description: "Number of live rows fetched by index scans" - - n_tup_ins: - usage: "COUNTER" - description: "Number of rows inserted" - - n_tup_upd: - usage: "COUNTER" - description: "Number of rows updated" - - n_tup_del: - usage: "COUNTER" - description: "Number of rows deleted" - - n_tup_hot_upd: - usage: "COUNTER" - description: "Number of rows HOT updated (i.e., with no separate index update required)" - - n_live_tup: - usage: "GAUGE" - description: "Estimated number of live rows" - - n_dead_tup: - usage: "GAUGE" - description: "Estimated number of dead rows" - - n_mod_since_analyze: - usage: "GAUGE" - description: "Estimated number of rows changed since last analyze" - - last_vacuum: - usage: "GAUGE" - description: "Last time at which this table was manually vacuumed (not counting VACUUM FULL)" - - last_autovacuum: - usage: "GAUGE" - description: "Last time at which this table was vacuumed by the autovacuum daemon" - - last_analyze: - usage: "GAUGE" - description: "Last time at which this table was manually analyzed" - - last_autoanalyze: - usage: "GAUGE" - description: "Last time at which this table was analyzed by the autovacuum daemon" - - vacuum_count: - usage: "COUNTER" - description: "Number of times this table has been manually vacuumed (not counting VACUUM FULL)" - - autovacuum_count: - usage: "COUNTER" - description: "Number of times this table has been vacuumed by the autovacuum daemon" - - analyze_count: - usage: "COUNTER" - description: "Number of times this table has been manually analyzed" - - autoanalyze_count: - usage: "COUNTER" - description: "Number of times this table has been analyzed by the autovacuum daemon" - -pg_statio_user_tables: - query: "SELECT current_database() datname, schemaname, relname, heap_blks_read, heap_blks_hit, idx_blks_read, idx_blks_hit, toast_blks_read, toast_blks_hit, tidx_blks_read, tidx_blks_hit FROM pg_statio_user_tables" - metrics: - - datname: - usage: "LABEL" - description: "Name of current database" - - schemaname: - usage: "LABEL" - description: "Name of the schema that this table is in" - - relname: - usage: "LABEL" - description: "Name of this table" - - heap_blks_read: - usage: "COUNTER" - description: "Number of disk blocks read from this table" - - heap_blks_hit: - usage: "COUNTER" - description: "Number of buffer hits in this table" - - idx_blks_read: - usage: "COUNTER" - description: "Number of disk blocks read from all indexes on this table" - - idx_blks_hit: - usage: "COUNTER" - description: "Number of buffer hits in all indexes on this table" - - toast_blks_read: - usage: "COUNTER" - description: "Number of disk blocks read from this table's TOAST table (if any)" - - toast_blks_hit: - usage: "COUNTER" - description: "Number of buffer hits in this table's TOAST table (if any)" - - tidx_blks_read: - usage: "COUNTER" - description: "Number of disk blocks read from this table's TOAST table indexes (if any)" - - tidx_blks_hit: - usage: "COUNTER" - description: "Number of buffer hits in this table's TOAST table indexes (if any)" - -# -# WARNING: -# This set of metrics can be very expensive on a busy server as every -# unique query executed will create an additional time series -# -# pg_stat_statements: -# query: | -# SELECT -# pg_get_userbyid(userid) as user, -# pg_database.datname, -# pg_stat_statements.queryid, -# pg_stat_statements.calls as calls_total, -# pg_stat_statements.total_time / 1000.0 as seconds_total, -# pg_stat_statements.rows as rows_total, -# pg_stat_statements.blk_read_time / 1000.0 as block_read_seconds_total, -# pg_stat_statements.blk_write_time / 1000.0 as block_write_seconds_total -# FROM pg_stat_statements -# JOIN pg_database -# ON pg_database.oid = pg_stat_statements.dbid -# WHERE -# total_time > ( -# SELECT percentile_cont(0.1) -# WITHIN GROUP (ORDER BY total_time) -# FROM pg_stat_statements -# ) -# ORDER BY seconds_total DESC -# LIMIT 100 -# metrics: -# - user: -# usage: "LABEL" -# description: "The user who executed the statement" -# - datname: -# usage: "LABEL" -# description: "The database in which the statement was executed" -# - queryid: -# usage: "LABEL" -# description: "Internal hash code, computed from the statement's parse tree" -# - calls_total: -# usage: "COUNTER" -# description: "Number of times executed" -# - seconds_total: -# usage: "COUNTER" -# description: "Total time spent in the statement, in seconds" -# - rows_total: -# usage: "COUNTER" -# description: "Total number of rows retrieved or affected by the statement" -# - block_read_seconds_total: -# usage: "COUNTER" -# description: "Total time the statement spent reading blocks, in seconds" -# - block_write_seconds_total: -# usage: "COUNTER" -# description: "Total time the statement spent writing blocks, in seconds" - -pg_process_idle: - query: | - WITH - metrics AS ( - SELECT - application_name, - SUM(EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - state_change))::bigint)::float AS process_idle_seconds_sum, - COUNT(*) AS process_idle_seconds_count - FROM pg_stat_activity - WHERE state = 'idle' - GROUP BY application_name - ), - buckets AS ( - SELECT - application_name, - le, - SUM( - CASE WHEN EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - state_change)) <= le - THEN 1 - ELSE 0 - END - )::bigint AS bucket - FROM - pg_stat_activity, - UNNEST(ARRAY[1, 2, 5, 15, 30, 60, 90, 120, 300]) AS le - GROUP BY application_name, le - ORDER BY application_name, le - ) - SELECT - application_name, - process_idle_seconds_sum as seconds_sum, - process_idle_seconds_count as seconds_count, - ARRAY_AGG(le) AS seconds, - ARRAY_AGG(bucket) AS seconds_bucket - FROM metrics JOIN buckets USING (application_name) - GROUP BY 1, 2, 3 - metrics: - - application_name: - usage: "LABEL" - description: "Application Name" - - seconds: - usage: "HISTOGRAM" - description: "Idle time of server processes" +# Adding queries to this file is deprecated +# Example queries have been transformed into collectors. \ No newline at end of file From fe486012c9149e0d5b41da4b3ac60ff0cabd8d64 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Mon, 12 Jun 2023 19:48:28 -0400 Subject: [PATCH 105/228] Fix pg_stat_database collector The signature for creating a collector changed and CI didn't retrigger. Move metrics out of map and into individual vars. Signed-off-by: Joe Adams --- collector/pg_stat_database.go | 118 +++++++++++++++++----------------- 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/collector/pg_stat_database.go b/collector/pg_stat_database.go index 387094e08..705ac0ce0 100644 --- a/collector/pg_stat_database.go +++ b/collector/pg_stat_database.go @@ -17,7 +17,6 @@ import ( "context" "database/sql" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -27,14 +26,14 @@ func init() { type PGStatDatabaseCollector struct{} -func NewPGStatDatabaseCollector(logger log.Logger) (Collector, error) { +func NewPGStatDatabaseCollector(config collectorConfig) (Collector, error) { return &PGStatDatabaseCollector{}, nil } const statDatabaseSubsystem = "stat_database" -var statDatabase = map[string]*prometheus.Desc{ - "numbackends": prometheus.NewDesc( +var ( + statDatabaseNumbackends = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -43,8 +42,8 @@ var statDatabase = map[string]*prometheus.Desc{ "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.", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "xact_commit": prometheus.NewDesc( + ) + statDatabaseXactCommit = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -53,8 +52,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of transactions in this database that have been committed", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "xact_rollback": prometheus.NewDesc( + ) + statDatabaseXactRollback = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -63,8 +62,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of transactions in this database that have been rolled back", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "blks_read": prometheus.NewDesc( + ) + statDatabaseBlksRead = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -73,8 +72,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of disk blocks read in this database", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "blks_hit": prometheus.NewDesc( + ) + statDatabaseBlksHit = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -83,8 +82,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of times disk blocks were found already in the buffer cache, so that a read was not necessary (this only includes hits in the PostgreSQL buffer cache, not the operating system's file system cache)", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "tup_returned": prometheus.NewDesc( + ) + statDatabaseTupReturned = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -93,8 +92,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of rows returned by queries in this database", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "tup_fetched": prometheus.NewDesc( + ) + statDatabaseTupFetched = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -103,8 +102,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of rows fetched by queries in this database", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "tup_inserted": prometheus.NewDesc( + ) + statDatabaseTupInserted = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -113,8 +112,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of rows inserted by queries in this database", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "tup_updated": prometheus.NewDesc( + ) + statDatabaseTupUpdated = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -123,8 +122,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of rows updated by queries in this database", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "tup_deleted": prometheus.NewDesc( + ) + statDatabaseTupDeleted = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -133,8 +132,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of rows deleted by queries in this database", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "conflicts": prometheus.NewDesc( + ) + statDatabaseConflicts = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -143,8 +142,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of queries canceled due to conflicts with recovery in this database. (Conflicts occur only on standby servers; see pg_stat_database_conflicts for details.)", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "temp_files": prometheus.NewDesc( + ) + statDatabaseTempFiles = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -153,8 +152,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of temporary files created by queries in this database. All temporary files are counted, regardless of why the temporary file was created (e.g., sorting or hashing), and regardless of the log_temp_files setting.", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "temp_bytes": prometheus.NewDesc( + ) + statDatabaseTempBytes = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -163,8 +162,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Total amount of data written to temporary files by queries in this database. All temporary files are counted, regardless of why the temporary file was created, and regardless of the log_temp_files setting.", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "deadlocks": prometheus.NewDesc( + ) + statDatabaseDeadlocks = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -173,8 +172,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Number of deadlocks detected in this database", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "blk_read_time": prometheus.NewDesc( + ) + statDatabaseBlkReadTime = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -183,8 +182,8 @@ var statDatabase = map[string]*prometheus.Desc{ "Time spent reading data file blocks by backends in this database, in milliseconds", []string{"datid", "datname"}, prometheus.Labels{}, - ), - "blk_write_time": prometheus.NewDesc( + ) + statDatabaseBlkWriteTime = prometheus.NewDesc( prometheus.BuildFQName( namespace, statDatabaseSubsystem, @@ -193,18 +192,17 @@ var statDatabase = map[string]*prometheus.Desc{ "Time spent writing data file blocks by backends in this database, in milliseconds", []string{"datid", "datname"}, prometheus.Labels{}, + ) + statDatabaseStatsReset = prometheus.NewDesc(prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "stats_reset", ), - "stats_reset": prometheus.NewDesc( - prometheus.BuildFQName( - namespace, - statDatabaseSubsystem, - "stats_reset", - ), "Time at which these statistics were last reset", []string{"datid", "datname"}, prometheus.Labels{}, - ), -} + ) +) func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { rows, err := db.QueryContext(ctx, @@ -283,7 +281,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- } ch <- prometheus.MustNewConstMetric( - statDatabase["numbackends"], + statDatabaseNumbackends, prometheus.GaugeValue, numBackends, datid, @@ -291,7 +289,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["xact_commit"], + statDatabaseXactCommit, prometheus.CounterValue, xactCommit, datid, @@ -299,7 +297,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["xact_rollback"], + statDatabaseXactRollback, prometheus.CounterValue, xactRollback, datid, @@ -307,7 +305,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["blks_read"], + statDatabaseBlksRead, prometheus.CounterValue, blksRead, datid, @@ -315,7 +313,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["blks_hit"], + statDatabaseBlksHit, prometheus.CounterValue, blksHit, datid, @@ -323,7 +321,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["tup_returned"], + statDatabaseTupReturned, prometheus.CounterValue, tupReturned, datid, @@ -331,7 +329,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["tup_fetched"], + statDatabaseTupFetched, prometheus.CounterValue, tupFetched, datid, @@ -339,7 +337,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["tup_inserted"], + statDatabaseTupInserted, prometheus.CounterValue, tupInserted, datid, @@ -347,7 +345,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["tup_updated"], + statDatabaseTupUpdated, prometheus.CounterValue, tupUpdated, datid, @@ -355,7 +353,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["tup_deleted"], + statDatabaseTupDeleted, prometheus.CounterValue, tupDeleted, datid, @@ -363,7 +361,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["conflicts"], + statDatabaseConflicts, prometheus.CounterValue, conflicts, datid, @@ -371,7 +369,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["temp_files"], + statDatabaseTempFiles, prometheus.CounterValue, tempFiles, datid, @@ -379,7 +377,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["temp_bytes"], + statDatabaseTempBytes, prometheus.CounterValue, tempBytes, datid, @@ -387,7 +385,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["deadlocks"], + statDatabaseDeadlocks, prometheus.CounterValue, deadlocks, datid, @@ -395,7 +393,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["blk_read_time"], + statDatabaseBlkReadTime, prometheus.CounterValue, blkReadTime, datid, @@ -403,7 +401,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) ch <- prometheus.MustNewConstMetric( - statDatabase["blk_write_time"], + statDatabaseBlkWriteTime, prometheus.CounterValue, blkWriteTime, datid, @@ -412,7 +410,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- if statsReset.Valid { ch <- prometheus.MustNewConstMetric( - statDatabase["stats_reset"], + statDatabaseStatsReset, prometheus.CounterValue, float64(statsReset.Time.Unix()), datid, @@ -420,7 +418,7 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- ) } else { ch <- prometheus.MustNewConstMetric( - statDatabase["stats_reset"], + statDatabaseStatsReset, prometheus.CounterValue, 0, datid, From 99828de70a7cd46d7a4a5fb7b6e23165b5178198 Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Tue, 13 Jun 2023 17:28:11 +0200 Subject: [PATCH 106/228] Fix up collector registration (#812) Use const definitions to make collector registration consistent. * Use collector subsystem name consistently. * Fix up replication metric name unit. Signed-off-by: SuperQ --- collector/pg_database.go | 10 +++++++-- collector/pg_postmaster.go | 10 +++++++-- collector/pg_process_idle.go | 6 ++--- collector/pg_replication.go | 16 +++++++++++--- ...cation_slots.go => pg_replication_slot.go} | 22 +++++++++++++++---- ...ts_test.go => pg_replication_slot_test.go} | 0 collector/pg_stat_bgwriter.go | 6 ++--- collector/pg_stat_database.go | 6 ++--- collector/pg_stat_statements.go | 6 ++--- collector/pg_stat_user_tables.go | 6 ++--- collector/pg_statio_user_tables.go | 6 ++--- 11 files changed, 65 insertions(+), 29 deletions(-) rename collector/{replication_slots.go => pg_replication_slot.go} (84%) rename collector/{replication_slots_test.go => pg_replication_slot_test.go} (100%) diff --git a/collector/pg_database.go b/collector/pg_database.go index 8a027e2db..661f84cd8 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -21,8 +21,10 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const databaseSubsystem = "database" + func init() { - registerCollector("database", defaultEnabled, NewPGDatabaseCollector) + registerCollector(databaseSubsystem, defaultEnabled, NewPGDatabaseCollector) } type PGDatabaseCollector struct { @@ -43,7 +45,11 @@ func NewPGDatabaseCollector(config collectorConfig) (Collector, error) { var ( pgDatabaseSizeDesc = prometheus.NewDesc( - "pg_database_size_bytes", + prometheus.BuildFQName( + namespace, + databaseSubsystem, + "size_bytes", + ), "Disk space used by the database", []string{"datname"}, nil, ) diff --git a/collector/pg_postmaster.go b/collector/pg_postmaster.go index b7d844e18..4a0cec6d4 100644 --- a/collector/pg_postmaster.go +++ b/collector/pg_postmaster.go @@ -20,8 +20,10 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const postmasterSubsystem = "postmaster" + func init() { - registerCollector("postmaster", defaultEnabled, NewPGPostmasterCollector) + registerCollector(postmasterSubsystem, defaultEnabled, NewPGPostmasterCollector) } type PGPostmasterCollector struct { @@ -33,7 +35,11 @@ func NewPGPostmasterCollector(collectorConfig) (Collector, error) { var ( pgPostMasterStartTimeSeconds = prometheus.NewDesc( - "pg_postmaster_start_time_seconds", + prometheus.BuildFQName( + namespace, + postmasterSubsystem, + "start_time_seconds", + ), "Time at which postmaster started", []string{}, nil, ) diff --git a/collector/pg_process_idle.go b/collector/pg_process_idle.go index b8c1a6cb7..8ee65a436 100644 --- a/collector/pg_process_idle.go +++ b/collector/pg_process_idle.go @@ -21,16 +21,16 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const processIdleSubsystem = "process_idle" + func init() { - registerCollector("statements", defaultEnabled, NewPGProcessIdleCollector) + registerCollector(processIdleSubsystem, defaultEnabled, NewPGProcessIdleCollector) } type PGProcessIdleCollector struct { log log.Logger } -const processIdleSubsystem = "process_idle" - func NewPGProcessIdleCollector(config collectorConfig) (Collector, error) { return &PGProcessIdleCollector{log: config.logger}, nil } diff --git a/collector/pg_replication.go b/collector/pg_replication.go index 10e4de521..1a8a3569f 100644 --- a/collector/pg_replication.go +++ b/collector/pg_replication.go @@ -20,8 +20,10 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const replicationSubsystem = "replication" + func init() { - registerCollector("replication", defaultEnabled, NewPGReplicationCollector) + registerCollector(replicationSubsystem, defaultEnabled, NewPGReplicationCollector) } type PGReplicationCollector struct { @@ -33,12 +35,20 @@ func NewPGReplicationCollector(collectorConfig) (Collector, error) { var ( pgReplicationLag = prometheus.NewDesc( - "pg_replication_lag", + prometheus.BuildFQName( + namespace, + replicationSubsystem, + "lag_seconds", + ), "Replication lag behind master in seconds", []string{}, nil, ) pgReplicationIsReplica = prometheus.NewDesc( - "pg_replication_is_replica", + prometheus.BuildFQName( + namespace, + replicationSubsystem, + "is_replica", + ), "Indicates if the server is a replica", []string{}, nil, ) diff --git a/collector/replication_slots.go b/collector/pg_replication_slot.go similarity index 84% rename from collector/replication_slots.go rename to collector/pg_replication_slot.go index 0aaf39cdc..8f105ff49 100644 --- a/collector/replication_slots.go +++ b/collector/pg_replication_slot.go @@ -21,8 +21,10 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const replicationSlotSubsystem = "replication_slot" + func init() { - registerCollector("replication_slot", defaultEnabled, NewPGReplicationSlotCollector) + registerCollector(replicationSlotSubsystem, defaultEnabled, NewPGReplicationSlotCollector) } type PGReplicationSlotCollector struct { @@ -35,17 +37,29 @@ func NewPGReplicationSlotCollector(config collectorConfig) (Collector, error) { var ( pgReplicationSlotCurrentWalDesc = prometheus.NewDesc( - "pg_replication_slot_current_wal_lsn", + prometheus.BuildFQName( + namespace, + replicationSlotSubsystem, + "slot_current_wal_lsn", + ), "current wal lsn value", []string{"slot_name"}, nil, ) pgReplicationSlotCurrentFlushDesc = prometheus.NewDesc( - "pg_replication_slot_confirmed_flush_lsn", + prometheus.BuildFQName( + namespace, + replicationSlotSubsystem, + "slot_confirmed_flush_lsn", + ), "last lsn confirmed flushed to the replication slot", []string{"slot_name"}, nil, ) pgReplicationSlotIsActiveDesc = prometheus.NewDesc( - "pg_replication_slot_is_active", + prometheus.BuildFQName( + namespace, + replicationSlotSubsystem, + "slot_is_active", + ), "whether the replication slot is active or not", []string{"slot_name"}, nil, ) diff --git a/collector/replication_slots_test.go b/collector/pg_replication_slot_test.go similarity index 100% rename from collector/replication_slots_test.go rename to collector/pg_replication_slot_test.go diff --git a/collector/pg_stat_bgwriter.go b/collector/pg_stat_bgwriter.go index 6efe87d52..5daf606c9 100644 --- a/collector/pg_stat_bgwriter.go +++ b/collector/pg_stat_bgwriter.go @@ -21,8 +21,10 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const bgWriterSubsystem = "stat_bgwriter" + func init() { - registerCollector("bgwriter", defaultEnabled, NewPGStatBGWriterCollector) + registerCollector(bgWriterSubsystem, defaultEnabled, NewPGStatBGWriterCollector) } type PGStatBGWriterCollector struct { @@ -32,8 +34,6 @@ func NewPGStatBGWriterCollector(collectorConfig) (Collector, error) { return &PGStatBGWriterCollector{}, nil } -const bgWriterSubsystem = "stat_bgwriter" - var ( statBGWriterCheckpointsTimedDesc = prometheus.NewDesc( prometheus.BuildFQName(namespace, bgWriterSubsystem, "checkpoints_timed_total"), diff --git a/collector/pg_stat_database.go b/collector/pg_stat_database.go index 705ac0ce0..346ed9ea9 100644 --- a/collector/pg_stat_database.go +++ b/collector/pg_stat_database.go @@ -20,8 +20,10 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const statDatabaseSubsystem = "stat_database" + func init() { - registerCollector("stat_database", defaultEnabled, NewPGStatDatabaseCollector) + registerCollector(statDatabaseSubsystem, defaultEnabled, NewPGStatDatabaseCollector) } type PGStatDatabaseCollector struct{} @@ -30,8 +32,6 @@ func NewPGStatDatabaseCollector(config collectorConfig) (Collector, error) { return &PGStatDatabaseCollector{}, nil } -const statDatabaseSubsystem = "stat_database" - var ( statDatabaseNumbackends = prometheus.NewDesc( prometheus.BuildFQName( diff --git a/collector/pg_stat_statements.go b/collector/pg_stat_statements.go index 78485f619..23e1f1567 100644 --- a/collector/pg_stat_statements.go +++ b/collector/pg_stat_statements.go @@ -21,19 +21,19 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const statStatementsSubsystem = "stat_statements" + func init() { // WARNING: // Disabled by default because this set of metrics can be quite expensive on a busy server // Every unique query will cause a new timeseries to be created - registerCollector("statements", defaultDisabled, NewPGStatStatementsCollector) + registerCollector(statStatementsSubsystem, defaultDisabled, NewPGStatStatementsCollector) } type PGStatStatementsCollector struct { log log.Logger } -const statStatementsSubsystem = "stat_statements" - func NewPGStatStatementsCollector(config collectorConfig) (Collector, error) { return &PGStatStatementsCollector{log: config.logger}, nil } diff --git a/collector/pg_stat_user_tables.go b/collector/pg_stat_user_tables.go index 1f267a7ee..05aced91f 100644 --- a/collector/pg_stat_user_tables.go +++ b/collector/pg_stat_user_tables.go @@ -22,16 +22,16 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const userTableSubsystem = "stat_user_tables" + func init() { - registerCollector("user_tables", defaultEnabled, NewPGStatUserTablesCollector) + registerCollector(userTableSubsystem, defaultEnabled, NewPGStatUserTablesCollector) } type PGStatUserTablesCollector struct { log log.Logger } -const userTableSubsystem = "stat_user_tables" - func NewPGStatUserTablesCollector(config collectorConfig) (Collector, error) { return &PGStatUserTablesCollector{log: config.logger}, nil } diff --git a/collector/pg_statio_user_tables.go b/collector/pg_statio_user_tables.go index e84631df5..043433d86 100644 --- a/collector/pg_statio_user_tables.go +++ b/collector/pg_statio_user_tables.go @@ -21,16 +21,16 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const statioUserTableSubsystem = "statio_user_tables" + func init() { - registerCollector("statio_user_tables", defaultEnabled, NewPGStatIOUserTablesCollector) + registerCollector(statioUserTableSubsystem, defaultEnabled, NewPGStatIOUserTablesCollector) } type PGStatIOUserTablesCollector struct { log log.Logger } -const statioUserTableSubsystem = "statio_user_tables" - func NewPGStatIOUserTablesCollector(config collectorConfig) (Collector, error) { return &PGStatIOUserTablesCollector{log: config.logger}, nil } From 3fc8b3ab19d56591e51f7adbbd3fe4854f761290 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Mon, 12 Jun 2023 19:59:36 -0400 Subject: [PATCH 107/228] Update release info for v0.12.1 Signed-off-by: Joe Adams --- CHANGELOG.md | 3 +++ VERSION | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c89c71859..4d5d60f92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## master / unreleased +## 0.12.1 / 2023-06-12 +* [BUGFIX] Fix column type for pg_replication_slots #777 + ## 0.12.0 / 2023-03-21 BREAKING CHANGES: diff --git a/VERSION b/VERSION index ac454c6a1..34a83616b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.12.0 +0.12.1 From 7dcf1dc7b631c38b889f843aa4e5601a119fcfe3 Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Tue, 13 Jun 2023 17:39:39 +0200 Subject: [PATCH 108/228] Deprecate extend queries feature (#811) Mark the extend queries feature as deprecated in favor of recommending the sql_exporter. Signed-off-by: SuperQ --- README.md | 6 ++++-- cmd/postgres_exporter/main.go | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b54b4b63c..9f5222c15 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra * `auto-discover-databases` Whether to discover the databases on a server dynamically. Default is `false`. -* `extend.query-path` +* `extend.query-path` (DEPRECATED) Path to a YAML file containing custom queries to run. Check out [`queries.yaml`](queries.yaml) for examples of the format. @@ -222,7 +222,9 @@ for l in StringIO(x): Adjust the value of the resultant prometheus value type appropriately. This helps build rich self-documenting metrics for the exporter. -### Adding new metrics via a config file +### Adding new metrics via a config file (DEPRECATED) + +This feature is deprecated in favor of built-in collector functions. For generic SQL database monitoring see the [sql_exporter](https://github.com/burningalchemist/sql_exporter). The -extend.query-path command-line argument specifies a YAML file containing additional queries to run. Some examples are provided in [queries.yaml](queries.yaml). diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 04dd6e7c4..cab3fcab4 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -44,7 +44,7 @@ var ( disableDefaultMetrics = kingpin.Flag("disable-default-metrics", "Do not include default metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_DEFAULT_METRICS").Bool() disableSettingsMetrics = kingpin.Flag("disable-settings-metrics", "Do not include pg_settings metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_SETTINGS_METRICS").Bool() autoDiscoverDatabases = kingpin.Flag("auto-discover-databases", "Whether to discover the databases on a server dynamically.").Default("false").Envar("PG_EXPORTER_AUTO_DISCOVER_DATABASES").Bool() - queriesPath = kingpin.Flag("extend.query-path", "Path to custom queries to run.").Default("").Envar("PG_EXPORTER_EXTEND_QUERY_PATH").String() + queriesPath = kingpin.Flag("extend.query-path", "Path to custom queries to run. (DEPRECATED)").Default("").Envar("PG_EXPORTER_EXTEND_QUERY_PATH").String() onlyDumpMaps = kingpin.Flag("dumpmaps", "Do not run, simply dump the maps.").Bool() constantLabelsList = kingpin.Flag("constantLabels", "A list of label=value separated by comma(,).").Default("").Envar("PG_EXPORTER_CONSTANT_LABELS").String() excludeDatabases = kingpin.Flag("exclude-databases", "A list of databases to remove when autoDiscoverDatabases is enabled").Default("").Envar("PG_EXPORTER_EXCLUDE_DATABASES").String() @@ -95,6 +95,10 @@ func main() { excludedDatabases := strings.Split(*excludeDatabases, ",") logger.Log("msg", "Excluded databases", "databases", fmt.Sprintf("%v", excludedDatabases)) + if *queriesPath != "" { + level.Warn(logger).Log("msg", "The extend queries.yaml config is DEPRECATD", "file", *queriesPath) + } + opts := []ExporterOpt{ DisableDefaultMetrics(*disableDefaultMetrics), DisableSettingsMetrics(*disableSettingsMetrics), From 3dd0aa691011d73dbd831c7f38cc7e5272066588 Mon Sep 17 00:00:00 2001 From: prombot Date: Sun, 18 Jun 2023 17:50:53 +0000 Subject: [PATCH 109/228] Update common Prometheus files Signed-off-by: prombot --- Makefile.common | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.common b/Makefile.common index b111d2562..e372d3473 100644 --- a/Makefile.common +++ b/Makefile.common @@ -49,7 +49,7 @@ endif GOTEST := $(GO) test GOTEST_DIR := ifneq ($(CIRCLE_JOB),) -ifneq ($(shell which gotestsum),) +ifneq ($(shell command -v gotestsum > /dev/null),) GOTEST_DIR := test-results GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml -- endif @@ -178,7 +178,7 @@ endif .PHONY: common-yamllint common-yamllint: @echo ">> running yamllint on all YAML files in the repository" -ifeq (, $(shell which yamllint)) +ifeq (, $(shell command -v yamllint > /dev/null)) @echo "yamllint not installed so skipping" else yamllint . From c71d395bf605e6e2203058033645f109330fdd1d Mon Sep 17 00:00:00 2001 From: SuperQ Date: Mon, 19 Jun 2023 13:05:57 +0200 Subject: [PATCH 110/228] Deprecate additional database features Now that we have deprecated extended queries we can deprecate related database features. * Deprecate flags/functions around auto discover databases. * Deprecate flags/functions for additional constant labels. Signed-off-by: SuperQ --- README.md | 18 +++++++++--------- cmd/postgres_exporter/main.go | 16 ++++++++++++---- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 9f5222c15..471e304d2 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra * `disable-settings-metrics` Use the flag if you don't want to scrape `pg_settings`. Default is `false`. -* `auto-discover-databases` +* `auto-discover-databases` (DEPRECATED) Whether to discover the databases on a server dynamically. Default is `false`. * `extend.query-path` (DEPRECATED) @@ -113,16 +113,16 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra Do not run - print the internal representation of the metric maps. Useful when debugging a custom queries file. -* `constantLabels` +* `constantLabels` (DEPRECATED) Labels to set in all metrics. A list of `label=value` pairs, separated by commas. * `version` Show application version. -* `exclude-databases` +* `exclude-databases` (DEPRECATED) A list of databases to remove when autoDiscoverDatabases is enabled. -* `include-databases` +* `include-databases` (DEPRECATED) A list of databases to only include when autoDiscoverDatabases is enabled. * `log.level` @@ -170,20 +170,20 @@ The following environment variables configure the exporter: * `PG_EXPORTER_DISABLE_SETTINGS_METRICS` Use the flag if you don't want to scrape `pg_settings`. Value can be `true` or `false`. Default is `false`. -* `PG_EXPORTER_AUTO_DISCOVER_DATABASES` +* `PG_EXPORTER_AUTO_DISCOVER_DATABASES` (DEPRECATED) Whether to discover the databases on a server dynamically. Value can be `true` or `false`. Default is `false`. * `PG_EXPORTER_EXTEND_QUERY_PATH` Path to a YAML file containing custom queries to run. Check out [`queries.yaml`](queries.yaml) for examples of the format. -* `PG_EXPORTER_CONSTANT_LABELS` +* `PG_EXPORTER_CONSTANT_LABELS` (DEPRECATED) Labels to set in all metrics. A list of `label=value` pairs, separated by commas. -* `PG_EXPORTER_EXCLUDE_DATABASES` +* `PG_EXPORTER_EXCLUDE_DATABASES` (DEPRECATED) A comma-separated list of databases to remove when autoDiscoverDatabases is enabled. Default is empty string. -* `PG_EXPORTER_INCLUDE_DATABASES` +* `PG_EXPORTER_INCLUDE_DATABASES` (DEPRECATED) A comma-separated list of databases to only include when autoDiscoverDatabases is enabled. Default is empty string, means allow all. @@ -235,7 +235,7 @@ or variants of postgres (e.g. Greenplum), you can disable the default metrics wi flag. This removes all built-in metrics, and uses only metrics defined by queries in the `queries.yaml` file you supply (so you must supply one, otherwise the exporter will return nothing but internal statuses and not your database). -### Automatically discover databases +### Automatically discover databases (DEPRECATED) To scrape metrics from all databases on a database server, the database DSN's can be dynamically discovered via the `--auto-discover-databases` flag. When true, `SELECT datname FROM pg_database WHERE datallowconn = true AND datistemplate = false and datname != current_database()` is run for all configured DSN's. From the result a new set of DSN's is created for which the metrics are scraped. diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index cab3fcab4..64554d370 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -43,12 +43,12 @@ var ( metricsPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").Envar("PG_EXPORTER_WEB_TELEMETRY_PATH").String() disableDefaultMetrics = kingpin.Flag("disable-default-metrics", "Do not include default metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_DEFAULT_METRICS").Bool() disableSettingsMetrics = kingpin.Flag("disable-settings-metrics", "Do not include pg_settings metrics.").Default("false").Envar("PG_EXPORTER_DISABLE_SETTINGS_METRICS").Bool() - autoDiscoverDatabases = kingpin.Flag("auto-discover-databases", "Whether to discover the databases on a server dynamically.").Default("false").Envar("PG_EXPORTER_AUTO_DISCOVER_DATABASES").Bool() + autoDiscoverDatabases = kingpin.Flag("auto-discover-databases", "Whether to discover the databases on a server dynamically. (DEPRECATED)").Default("false").Envar("PG_EXPORTER_AUTO_DISCOVER_DATABASES").Bool() queriesPath = kingpin.Flag("extend.query-path", "Path to custom queries to run. (DEPRECATED)").Default("").Envar("PG_EXPORTER_EXTEND_QUERY_PATH").String() onlyDumpMaps = kingpin.Flag("dumpmaps", "Do not run, simply dump the maps.").Bool() - constantLabelsList = kingpin.Flag("constantLabels", "A list of label=value separated by comma(,).").Default("").Envar("PG_EXPORTER_CONSTANT_LABELS").String() - excludeDatabases = kingpin.Flag("exclude-databases", "A list of databases to remove when autoDiscoverDatabases is enabled").Default("").Envar("PG_EXPORTER_EXCLUDE_DATABASES").String() - includeDatabases = kingpin.Flag("include-databases", "A list of databases to include when autoDiscoverDatabases is enabled").Default("").Envar("PG_EXPORTER_INCLUDE_DATABASES").String() + constantLabelsList = kingpin.Flag("constantLabels", "A list of label=value separated by comma(,). (DEPRECATED)").Default("").Envar("PG_EXPORTER_CONSTANT_LABELS").String() + excludeDatabases = kingpin.Flag("exclude-databases", "A list of databases to remove when autoDiscoverDatabases is enabled (DEPRECATED)").Default("").Envar("PG_EXPORTER_EXCLUDE_DATABASES").String() + includeDatabases = kingpin.Flag("include-databases", "A list of databases to include when autoDiscoverDatabases is enabled (DEPRECATED)").Default("").Envar("PG_EXPORTER_INCLUDE_DATABASES").String() metricPrefix = 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() logger = log.NewNopLogger() ) @@ -99,6 +99,14 @@ func main() { level.Warn(logger).Log("msg", "The extend queries.yaml config is DEPRECATD", "file", *queriesPath) } + if *autoDiscoverDatabases || *excludeDatabases != "" || *includeDatabases != "" { + level.Warn(logger).Log("msg", "Scraping additional databases via auto discovery is DEPRECATD") + } + + if *constantLabelsList != "" { + level.Warn(logger).Log("msg", "Constant lables on all metrics is DEPRECATD") + } + opts := []ExporterOpt{ DisableDefaultMetrics(*disableDefaultMetrics), DisableSettingsMetrics(*disableSettingsMetrics), From db08eee988e8e59095d780b620d4c9b8e8cc8ba8 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Wed, 21 Jun 2023 15:33:23 +0200 Subject: [PATCH 111/228] Release v0.13.0 BREAKING CHANGES: Please note, the following features are deprecated and may be removed in a future release: - `auto-discover-databases` - `extend.query-path` - `constantLabels` - `exclude-databases` - `include-databases` This exporter is meant to monitor PostgresSQL servers, not the user data/databases. If you need a generic SQL report exporter https://github.com/burningalchemist/sql_exporter is recommended. * [CHANGE] Adjust log level for collector startup #784 * [CHANGE] Move queries from queries.yaml to collectors #801 * [CHANGE] Deprecate extend queries feature #811 * [CHANGE] Deprecate additional database features #815 * [CHANGE] Convert pg_stat_database to new collector #685 * [ENHANCEMENT] Supports alternate postgres:// prefix in URLs #787 * [BUGFIX] Fix pg_setting different help values #771 * [BUGFIX] Fix column type for pg_replication_slots #777 * [BUGFIX] Fix pg_stat_database collector #809 Signed-off-by: SuperQ --- CHANGELOG.md | 25 ++++++++++++++++++++++++- README.md | 34 ++++++++++++++++++++++++++++------ VERSION | 2 +- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d5d60f92..7a13c53eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,27 @@ -## master / unreleased +## 0.13.0 / 2023-06-21 + +BREAKING CHANGES: + +Please note, the following features are deprecated and may be removed in a future release: +- `auto-discover-databases` +- `extend.query-path` +- `constantLabels` +- `exclude-databases` +- `include-databases` + +This exporter is meant to monitor PostgresSQL servers, not the user data/databases. If +you need a generic SQL report exporter https://github.com/burningalchemist/sql_exporter +is recommended. + +* [CHANGE] Adjust log level for collector startup #784 +* [CHANGE] Move queries from queries.yaml to collectors #801 +* [CHANGE] Deprecate extend queries feature #811 +* [CHANGE] Deprecate additional database features #815 +* [CHANGE] Convert pg_stat_database to new collector #685 +* [ENHANCEMENT] Supports alternate postgres:// prefix in URLs #787 +* [BUGFIX] Fix pg_setting different help values #771 +* [BUGFIX] Fix column type for pg_replication_slots #777 +* [BUGFIX] Fix pg_stat_database collector #809 ## 0.12.1 / 2023-06-12 * [BUGFIX] Fix column type for pg_replication_slots #777 diff --git a/README.md b/README.md index 471e304d2..912ea0c5d 100644 --- a/README.md +++ b/README.md @@ -71,14 +71,36 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra * `help` Show context-sensitive help (also try --help-long and --help-man). -* `collector.database` - Enable the pg_database collector. Default is `enabled` -* `collector.bgwriter` - Enable the pg_stat_bgwriter collector. Default is `enabled` +* `[no-]collector.database` + Enable the database collector (default: enabled). -* `collector.replication_slot` - Enable the replication_slot collector. Default is `enabled` +* `[no-]collector.postmaster` + Enable the `postmaster` collector (default: enabled). + +* `[no-]collector.process_idle` + Enable the `process_idle` collector (default: enabled). + +* `[no-]collector.replication` + Enable the `replication` collector (default: enabled). + +* `[no-]collector.replication_slot` + Enable the `replication_slot` collector (default: enabled). + +* `[no-]collector.stat_bgwriter` + Enable the `stat_bgwriter` collector (default: enabled). + +* `[no-]collector.stat_database` + Enable the `stat_database` collector (default: enabled). + +* `[no-]collector.statio_user_tables` + Enable the `statio_user_tables` collector (default: enabled). + +* `[no-]collector.stat_statements` + Enable the `stat_statements` collector (default: disabled). + +* `[no-]collector.stat_user_tables` + Enable the `stat_user_tables` collector (default: enabled). * `config.file` Set the config file path. Default is `postgres_exporter.yml` diff --git a/VERSION b/VERSION index 34a83616b..54d1a4f2a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.12.1 +0.13.0 From ab33346cbdb19df89d1c0ca8b7691379089eb4f1 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 29 Mar 2023 21:25:27 -0400 Subject: [PATCH 112/228] Add the instance struct to handle connections The intent is to use the instance struct to hold the connection to the database as well as metadata about the instance. Currently this metadata only includes the version of postgres for the instance which can be used in the collectors to decide what query to run. In the future this could hold more metadata but for now it keeps the Collector interface arguments to a reasonable number. Signed-off-by: Joe Adams --- collector/collector.go | 18 ++---- collector/instance.go | 85 +++++++++++++++++++++++++ collector/pg_database.go | 4 +- collector/pg_database_test.go | 4 +- collector/pg_postmaster.go | 4 +- collector/pg_postmaster_test.go | 4 +- collector/pg_process_idle.go | 4 +- collector/pg_replication_slot.go | 4 +- collector/pg_replication_slot_test.go | 8 ++- collector/pg_stat_bgwriter.go | 4 +- collector/pg_stat_bgwriter_test.go | 4 +- collector/pg_stat_database.go | 3 +- collector/pg_stat_statements.go | 4 +- collector/pg_stat_statements_test.go | 4 +- collector/pg_stat_user_tables.go | 4 +- collector/pg_stat_user_tables_test.go | 4 +- collector/pg_statio_user_tables.go | 4 +- collector/pg_statio_user_tables_test.go | 4 +- collector/probe.go | 13 ++-- 19 files changed, 139 insertions(+), 44 deletions(-) create mode 100644 collector/instance.go diff --git a/collector/collector.go b/collector/collector.go index d50e1e72a..c1bf2af9a 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -15,7 +15,6 @@ package collector import ( "context" - "database/sql" "errors" "fmt" "sync" @@ -59,7 +58,7 @@ var ( ) type Collector interface { - Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error + Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error } type collectorConfig struct { @@ -92,7 +91,7 @@ type PostgresCollector struct { Collectors map[string]Collector logger log.Logger - db *sql.DB + instance *instance } type Option func(*PostgresCollector) error @@ -149,14 +148,11 @@ func NewPostgresCollector(logger log.Logger, excludeDatabases []string, dsn stri return nil, errors.New("empty dsn") } - db, err := sql.Open("postgres", dsn) + instance, err := newInstance(dsn) if err != nil { return nil, err } - db.SetMaxOpenConns(1) - db.SetMaxIdleConns(1) - - p.db = db + p.instance = instance return p, nil } @@ -174,16 +170,16 @@ func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) { wg.Add(len(p.Collectors)) for name, c := range p.Collectors { go func(name string, c Collector) { - execute(ctx, name, c, p.db, ch, p.logger) + execute(ctx, name, c, p.instance, ch, p.logger) wg.Done() }(name, c) } wg.Wait() } -func execute(ctx context.Context, name string, c Collector, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) { +func execute(ctx context.Context, name string, c Collector, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) { begin := time.Now() - err := c.Update(ctx, db, ch) + err := c.Update(ctx, instance, ch) duration := time.Since(begin) var success float64 diff --git a/collector/instance.go b/collector/instance.go new file mode 100644 index 000000000..9b2bbf47f --- /dev/null +++ b/collector/instance.go @@ -0,0 +1,85 @@ +// Copyright 2023 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 collector + +import ( + "database/sql" + "fmt" + "regexp" + + "github.com/blang/semver/v4" +) + +type instance struct { + db *sql.DB + version semver.Version +} + +func newInstance(dsn string) (*instance, error) { + i := &instance{} + db, err := sql.Open("postgres", dsn) + if err != nil { + return nil, err + } + db.SetMaxOpenConns(1) + db.SetMaxIdleConns(1) + i.db = db + + version, err := queryVersion(db) + if err != nil { + db.Close() + return nil, err + } + + i.version = version + + return i, nil +} + +func (i *instance) getDB() *sql.DB { + return i.db +} + +func (i *instance) Close() error { + return i.db.Close() +} + +// Regex used to get the "short-version" from the postgres version field. +// The result of SELECT version() is something like "PostgreSQL 9.6.2 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 6.2.1 20160830, 64-bit" +var versionRegex = regexp.MustCompile(`^\w+ ((\d+)(\.\d+)?(\.\d+)?)`) +var serverVersionRegex = regexp.MustCompile(`^((\d+)(\.\d+)?(\.\d+)?)`) + +func queryVersion(db *sql.DB) (semver.Version, error) { + var version string + err := db.QueryRow("SELECT version();").Scan(&version) + if err != nil { + return semver.Version{}, err + } + submatches := versionRegex.FindStringSubmatch(version) + if len(submatches) > 1 { + return semver.ParseTolerant(submatches[1]) + } + + // We could also try to parse the version from the server_version field. + // This is of the format 13.3 (Debian 13.3-1.pgdg100+1) + err = db.QueryRow("SHOW server_version;").Scan(&version) + if err != nil { + return semver.Version{}, err + } + submatches = serverVersionRegex.FindStringSubmatch(version) + if len(submatches) > 1 { + return semver.ParseTolerant(submatches[1]) + } + return semver.Version{}, fmt.Errorf("could not parse version from %q", version) +} diff --git a/collector/pg_database.go b/collector/pg_database.go index 661f84cd8..a4ea50d0d 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -15,7 +15,6 @@ package collector import ( "context" - "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" @@ -66,7 +65,8 @@ var ( // each database individually. This is because we can't filter the // list of databases in the query because the list of excluded // databases is dynamic. -func (c PGDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { +func (c PGDatabaseCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() // Query the list of databases rows, err := db.QueryContext(ctx, pgDatabaseQuery, diff --git a/collector/pg_database_test.go b/collector/pg_database_test.go index bb108bb86..058a6d252 100644 --- a/collector/pg_database_test.go +++ b/collector/pg_database_test.go @@ -29,6 +29,8 @@ func TestPGDatabaseCollector(t *testing.T) { } defer db.Close() + inst := &instance{db: db} + mock.ExpectQuery(sanitizeQuery(pgDatabaseQuery)).WillReturnRows(sqlmock.NewRows([]string{"datname"}). AddRow("postgres")) @@ -39,7 +41,7 @@ func TestPGDatabaseCollector(t *testing.T) { go func() { defer close(ch) c := PGDatabaseCollector{} - if err := c.Update(context.Background(), db, ch); err != nil { + if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGDatabaseCollector.Update: %s", err) } }() diff --git a/collector/pg_postmaster.go b/collector/pg_postmaster.go index 4a0cec6d4..eae82d567 100644 --- a/collector/pg_postmaster.go +++ b/collector/pg_postmaster.go @@ -15,7 +15,6 @@ package collector import ( "context" - "database/sql" "github.com/prometheus/client_golang/prometheus" ) @@ -47,7 +46,8 @@ var ( pgPostmasterQuery = "SELECT pg_postmaster_start_time from pg_postmaster_start_time();" ) -func (c *PGPostmasterCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { +func (c *PGPostmasterCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() row := db.QueryRowContext(ctx, pgPostmasterQuery) diff --git a/collector/pg_postmaster_test.go b/collector/pg_postmaster_test.go index 9b93a5c91..c40fe03ad 100644 --- a/collector/pg_postmaster_test.go +++ b/collector/pg_postmaster_test.go @@ -29,6 +29,8 @@ func TestPgPostmasterCollector(t *testing.T) { } defer db.Close() + inst := &instance{db: db} + mock.ExpectQuery(sanitizeQuery(pgPostmasterQuery)).WillReturnRows(sqlmock.NewRows([]string{"pg_postmaster_start_time"}). AddRow(1685739904)) @@ -37,7 +39,7 @@ func TestPgPostmasterCollector(t *testing.T) { defer close(ch) c := PGPostmasterCollector{} - if err := c.Update(context.Background(), db, ch); err != nil { + if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGPostmasterCollector.Update: %s", err) } }() diff --git a/collector/pg_process_idle.go b/collector/pg_process_idle.go index 8ee65a436..06244975b 100644 --- a/collector/pg_process_idle.go +++ b/collector/pg_process_idle.go @@ -15,7 +15,6 @@ package collector import ( "context" - "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" @@ -42,7 +41,8 @@ var pgProcessIdleSeconds = prometheus.NewDesc( prometheus.Labels{}, ) -func (PGProcessIdleCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { +func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() row := db.QueryRowContext(ctx, `WITH metrics AS ( diff --git a/collector/pg_replication_slot.go b/collector/pg_replication_slot.go index 8f105ff49..4278923f8 100644 --- a/collector/pg_replication_slot.go +++ b/collector/pg_replication_slot.go @@ -15,7 +15,6 @@ package collector import ( "context" - "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" @@ -73,7 +72,8 @@ var ( pg_replication_slots;` ) -func (PGReplicationSlotCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { +func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() rows, err := db.QueryContext(ctx, pgReplicationSlotQuery) if err != nil { diff --git a/collector/pg_replication_slot_test.go b/collector/pg_replication_slot_test.go index 53bafafad..cb25b755a 100644 --- a/collector/pg_replication_slot_test.go +++ b/collector/pg_replication_slot_test.go @@ -29,6 +29,8 @@ func TestPgReplicationSlotCollectorActive(t *testing.T) { } defer db.Close() + inst := &instance{db: db} + columns := []string{"slot_name", "current_wal_lsn", "confirmed_flush_lsn", "active"} rows := sqlmock.NewRows(columns). AddRow("test_slot", 5, 3, true) @@ -39,7 +41,7 @@ func TestPgReplicationSlotCollectorActive(t *testing.T) { defer close(ch) c := PGReplicationSlotCollector{} - if err := c.Update(context.Background(), db, ch); err != nil { + if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGPostmasterCollector.Update: %s", err) } }() @@ -68,6 +70,8 @@ func TestPgReplicationSlotCollectorInActive(t *testing.T) { } defer db.Close() + inst := &instance{db: db} + columns := []string{"slot_name", "current_wal_lsn", "confirmed_flush_lsn", "active"} rows := sqlmock.NewRows(columns). AddRow("test_slot", 6, 12, false) @@ -78,7 +82,7 @@ func TestPgReplicationSlotCollectorInActive(t *testing.T) { defer close(ch) c := PGReplicationSlotCollector{} - if err := c.Update(context.Background(), db, ch); err != nil { + if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGReplicationSlotCollector.Update: %s", err) } }() diff --git a/collector/pg_stat_bgwriter.go b/collector/pg_stat_bgwriter.go index 5daf606c9..2bdef8d40 100644 --- a/collector/pg_stat_bgwriter.go +++ b/collector/pg_stat_bgwriter.go @@ -15,7 +15,6 @@ package collector import ( "context" - "database/sql" "time" "github.com/prometheus/client_golang/prometheus" @@ -117,7 +116,8 @@ var ( FROM pg_stat_bgwriter;` ) -func (PGStatBGWriterCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { +func (PGStatBGWriterCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() row := db.QueryRowContext(ctx, statBGWriterQuery) diff --git a/collector/pg_stat_bgwriter_test.go b/collector/pg_stat_bgwriter_test.go index 54f625c9e..11f55f6be 100644 --- a/collector/pg_stat_bgwriter_test.go +++ b/collector/pg_stat_bgwriter_test.go @@ -30,6 +30,8 @@ func TestPGStatBGWriterCollector(t *testing.T) { } defer db.Close() + inst := &instance{db: db} + columns := []string{ "checkpoints_timed", "checkpoints_req", @@ -57,7 +59,7 @@ func TestPGStatBGWriterCollector(t *testing.T) { defer close(ch) c := PGStatBGWriterCollector{} - if err := c.Update(context.Background(), db, ch); err != nil { + if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGStatBGWriterCollector.Update: %s", err) } }() diff --git a/collector/pg_stat_database.go b/collector/pg_stat_database.go index 346ed9ea9..bb39a84b1 100644 --- a/collector/pg_stat_database.go +++ b/collector/pg_stat_database.go @@ -204,7 +204,8 @@ var ( ) ) -func (PGStatDatabaseCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { +func (PGStatDatabaseCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() rows, err := db.QueryContext(ctx, `SELECT datid diff --git a/collector/pg_stat_statements.go b/collector/pg_stat_statements.go index 23e1f1567..eb629c381 100644 --- a/collector/pg_stat_statements.go +++ b/collector/pg_stat_statements.go @@ -15,7 +15,6 @@ package collector import ( "context" - "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" @@ -92,7 +91,8 @@ var ( LIMIT 100;` ) -func (PGStatStatementsCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { +func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() rows, err := db.QueryContext(ctx, pgStatStatementsQuery) diff --git a/collector/pg_stat_statements_test.go b/collector/pg_stat_statements_test.go index a5c5cab57..241699ad4 100644 --- a/collector/pg_stat_statements_test.go +++ b/collector/pg_stat_statements_test.go @@ -29,6 +29,8 @@ func TestPGStateStatementsCollector(t *testing.T) { } defer db.Close() + inst := &instance{db: db} + columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} rows := sqlmock.NewRows(columns). AddRow("postgres", "postgres", 1500, 5, 0.4, 100, 0.1, 0.2) @@ -39,7 +41,7 @@ func TestPGStateStatementsCollector(t *testing.T) { defer close(ch) c := PGStatStatementsCollector{} - if err := c.Update(context.Background(), db, ch); err != nil { + if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGStatStatementsCollector.Update: %s", err) } }() diff --git a/collector/pg_stat_user_tables.go b/collector/pg_stat_user_tables.go index 05aced91f..48ae96eb8 100644 --- a/collector/pg_stat_user_tables.go +++ b/collector/pg_stat_user_tables.go @@ -15,7 +15,6 @@ package collector import ( "context" - "database/sql" "time" "github.com/go-kit/log" @@ -179,7 +178,8 @@ var ( pg_stat_user_tables` ) -func (c *PGStatUserTablesCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { +func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() rows, err := db.QueryContext(ctx, statUserTablesQuery) diff --git a/collector/pg_stat_user_tables_test.go b/collector/pg_stat_user_tables_test.go index 29b5d15f1..8bb9bc31b 100644 --- a/collector/pg_stat_user_tables_test.go +++ b/collector/pg_stat_user_tables_test.go @@ -30,6 +30,8 @@ func TestPGStatUserTablesCollector(t *testing.T) { } defer db.Close() + inst := &instance{db: db} + lastVacuumTime, err := time.Parse("2006-01-02Z", "2023-06-02Z") if err != nil { t.Fatalf("Error parsing vacuum time: %s", err) @@ -99,7 +101,7 @@ func TestPGStatUserTablesCollector(t *testing.T) { defer close(ch) c := PGStatUserTablesCollector{} - if err := c.Update(context.Background(), db, ch); err != nil { + if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGStatUserTablesCollector.Update: %s", err) } }() diff --git a/collector/pg_statio_user_tables.go b/collector/pg_statio_user_tables.go index 043433d86..03d541615 100644 --- a/collector/pg_statio_user_tables.go +++ b/collector/pg_statio_user_tables.go @@ -15,7 +15,6 @@ package collector import ( "context" - "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" @@ -100,7 +99,8 @@ var ( FROM pg_statio_user_tables` ) -func (PGStatIOUserTablesCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { +func (PGStatIOUserTablesCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() rows, err := db.QueryContext(ctx, statioUserTablesQuery) diff --git a/collector/pg_statio_user_tables_test.go b/collector/pg_statio_user_tables_test.go index 0a7174d80..d57cab9f5 100644 --- a/collector/pg_statio_user_tables_test.go +++ b/collector/pg_statio_user_tables_test.go @@ -29,6 +29,8 @@ func TestPGStatIOUserTablesCollector(t *testing.T) { } defer db.Close() + inst := &instance{db: db} + columns := []string{ "datname", "schemaname", @@ -60,7 +62,7 @@ func TestPGStatIOUserTablesCollector(t *testing.T) { defer close(ch) c := PGStatIOUserTablesCollector{} - if err := c.Update(context.Background(), db, ch); err != nil { + if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGStatIOUserTablesCollector.Update: %s", err) } }() diff --git a/collector/probe.go b/collector/probe.go index 9044c40f9..834c65177 100644 --- a/collector/probe.go +++ b/collector/probe.go @@ -15,7 +15,6 @@ package collector import ( "context" - "database/sql" "sync" "github.com/go-kit/log" @@ -27,7 +26,7 @@ type ProbeCollector struct { registry *prometheus.Registry collectors map[string]Collector logger log.Logger - db *sql.DB + instance *instance } func NewProbeCollector(logger log.Logger, excludeDatabases []string, registry *prometheus.Registry, dsn config.DSN) (*ProbeCollector, error) { @@ -58,18 +57,16 @@ func NewProbeCollector(logger log.Logger, excludeDatabases []string, registry *p } } - db, err := sql.Open("postgres", dsn.GetConnectionString()) + instance, err := newInstance(dsn.GetConnectionString()) if err != nil { return nil, err } - db.SetMaxOpenConns(1) - db.SetMaxIdleConns(1) return &ProbeCollector{ registry: registry, collectors: collectors, logger: logger, - db: db, + instance: instance, }, nil } @@ -81,7 +78,7 @@ func (pc *ProbeCollector) Collect(ch chan<- prometheus.Metric) { wg.Add(len(pc.collectors)) for name, c := range pc.collectors { go func(name string, c Collector) { - execute(context.TODO(), name, c, pc.db, ch, pc.logger) + execute(context.TODO(), name, c, pc.instance, ch, pc.logger) wg.Done() }(name, c) } @@ -89,5 +86,5 @@ func (pc *ProbeCollector) Collect(ch chan<- prometheus.Metric) { } func (pc *ProbeCollector) Close() error { - return pc.db.Close() + return pc.instance.Close() } From b070e4534960fd42bd31f8d3f0198a820c6c1660 Mon Sep 17 00:00:00 2001 From: Alex Tymchuk Date: Fri, 23 Jun 2023 16:25:56 +0300 Subject: [PATCH 113/228] chore: fix a few typos Signed-off-by: Alex Tymchuk --- cmd/postgres_exporter/main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 64554d370..7d424b3d3 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -96,15 +96,15 @@ func main() { logger.Log("msg", "Excluded databases", "databases", fmt.Sprintf("%v", excludedDatabases)) if *queriesPath != "" { - level.Warn(logger).Log("msg", "The extend queries.yaml config is DEPRECATD", "file", *queriesPath) + level.Warn(logger).Log("msg", "The extended queries.yaml config is DEPRECATED", "file", *queriesPath) } if *autoDiscoverDatabases || *excludeDatabases != "" || *includeDatabases != "" { - level.Warn(logger).Log("msg", "Scraping additional databases via auto discovery is DEPRECATD") + level.Warn(logger).Log("msg", "Scraping additional databases via auto discovery is DEPRECATED") } if *constantLabelsList != "" { - level.Warn(logger).Log("msg", "Constant lables on all metrics is DEPRECATD") + level.Warn(logger).Log("msg", "Constant labels on all metrics is DEPRECATED") } opts := []ExporterOpt{ From 8d087f2c64c4a16d9214392ad39a31720eb38ee0 Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Mon, 26 Jun 2023 23:07:59 -0700 Subject: [PATCH 114/228] Bug fix: Make collector not fail on null values (#823) * Make all values nullable --------- Signed-off-by: Felix Yuan Co-authored-by: Ben Kochie --- collector/pg_database.go | 18 +- collector/pg_database_test.go | 40 +++ collector/pg_postmaster.go | 9 +- collector/pg_postmaster_test.go | 36 +++ collector/pg_process_idle.go | 36 ++- collector/pg_replication_slot.go | 35 ++- collector/pg_replication_slot_test.go | 81 ++++++ collector/pg_stat_bgwriter.go | 82 ++++-- collector/pg_stat_bgwriter_test.go | 61 ++++ collector/pg_stat_database.go | 227 +++++++++------ collector/pg_stat_database_test.go | 359 ++++++++++++++++++++++++ collector/pg_stat_statements.go | 69 +++-- collector/pg_stat_statements_test.go | 43 +++ collector/pg_stat_user_tables.go | 211 ++++++++++---- collector/pg_stat_user_tables_test.go | 99 +++++++ collector/pg_statio_user_tables.go | 97 +++++-- collector/pg_statio_user_tables_test.go | 67 +++++ 17 files changed, 1326 insertions(+), 244 deletions(-) create mode 100644 collector/pg_stat_database_test.go diff --git a/collector/pg_database.go b/collector/pg_database.go index a4ea50d0d..22d4918e4 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -15,6 +15,7 @@ package collector import ( "context" + "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" @@ -79,32 +80,39 @@ func (c PGDatabaseCollector) Update(ctx context.Context, instance *instance, ch var databases []string for rows.Next() { - var datname string + var datname sql.NullString if err := rows.Scan(&datname); err != nil { return err } + if !datname.Valid { + continue + } // Ignore excluded databases // Filtering is done here instead of in the query to avoid // a complicated NOT IN query with a variable number of parameters - if sliceContains(c.excludedDatabases, datname) { + if sliceContains(c.excludedDatabases, datname.String) { continue } - databases = append(databases, datname) + databases = append(databases, datname.String) } // Query the size of the databases for _, datname := range databases { - var size int64 + var size sql.NullFloat64 err = db.QueryRowContext(ctx, pgDatabaseSizeQuery, datname).Scan(&size) if err != nil { return err } + sizeMetric := 0.0 + if size.Valid { + sizeMetric = size.Float64 + } ch <- prometheus.MustNewConstMetric( pgDatabaseSizeDesc, - prometheus.GaugeValue, float64(size), datname, + prometheus.GaugeValue, sizeMetric, datname, ) } if err := rows.Err(); err != nil { diff --git a/collector/pg_database_test.go b/collector/pg_database_test.go index 058a6d252..b5052c5d1 100644 --- a/collector/pg_database_test.go +++ b/collector/pg_database_test.go @@ -59,3 +59,43 @@ func TestPGDatabaseCollector(t *testing.T) { t.Errorf("there were unfulfilled exceptions: %s", err) } } + +// TODO add a null db test + +func TestPGDatabaseCollectorNullMetric(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + mock.ExpectQuery(sanitizeQuery(pgDatabaseQuery)).WillReturnRows(sqlmock.NewRows([]string{"datname"}). + AddRow("postgres")) + + mock.ExpectQuery(sanitizeQuery(pgDatabaseSizeQuery)).WithArgs("postgres").WillReturnRows(sqlmock.NewRows([]string{"pg_database_size"}). + AddRow(nil)) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGDatabaseCollector{} + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGDatabaseCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datname": "postgres"}, value: 0, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_postmaster.go b/collector/pg_postmaster.go index eae82d567..4bef42964 100644 --- a/collector/pg_postmaster.go +++ b/collector/pg_postmaster.go @@ -15,6 +15,7 @@ package collector import ( "context" + "database/sql" "github.com/prometheus/client_golang/prometheus" ) @@ -51,14 +52,18 @@ func (c *PGPostmasterCollector) Update(ctx context.Context, instance *instance, row := db.QueryRowContext(ctx, pgPostmasterQuery) - var startTimeSeconds float64 + var startTimeSeconds sql.NullFloat64 err := row.Scan(&startTimeSeconds) if err != nil { return err } + startTimeSecondsMetric := 0.0 + if startTimeSeconds.Valid { + startTimeSecondsMetric = startTimeSeconds.Float64 + } ch <- prometheus.MustNewConstMetric( pgPostMasterStartTimeSeconds, - prometheus.GaugeValue, startTimeSeconds, + prometheus.GaugeValue, startTimeSecondsMetric, ) return nil } diff --git a/collector/pg_postmaster_test.go b/collector/pg_postmaster_test.go index c40fe03ad..8405b4225 100644 --- a/collector/pg_postmaster_test.go +++ b/collector/pg_postmaster_test.go @@ -57,3 +57,39 @@ func TestPgPostmasterCollector(t *testing.T) { t.Errorf("there were unfulfilled exceptions: %s", err) } } + +func TestPgPostmasterCollectorNullTime(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + mock.ExpectQuery(sanitizeQuery(pgPostmasterQuery)).WillReturnRows(sqlmock.NewRows([]string{"pg_postmaster_start_time"}). + AddRow(nil)) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGPostmasterCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGPostmasterCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{}, value: 0, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_process_idle.go b/collector/pg_process_idle.go index 06244975b..cc53fbb73 100644 --- a/collector/pg_process_idle.go +++ b/collector/pg_process_idle.go @@ -15,21 +15,23 @@ package collector import ( "context" + "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) -const processIdleSubsystem = "process_idle" - func init() { - registerCollector(processIdleSubsystem, defaultEnabled, NewPGProcessIdleCollector) + // Making this default disabled because we have no tests for it + registerCollector(processIdleSubsystem, defaultDisabled, NewPGProcessIdleCollector) } type PGProcessIdleCollector struct { log log.Logger } +const processIdleSubsystem = "process_idle" + func NewPGProcessIdleCollector(config collectorConfig) (Collector, error) { return &PGProcessIdleCollector{log: config.logger}, nil } @@ -41,8 +43,8 @@ var pgProcessIdleSeconds = prometheus.NewDesc( prometheus.Labels{}, ) -func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { - db := instance.getDB() +func (PGProcessIdleCollector) Update(ctx context.Context, inst *instance, ch chan<- prometheus.Metric) error { + db := inst.getDB() row := db.QueryRowContext(ctx, `WITH metrics AS ( @@ -79,9 +81,9 @@ func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch FROM metrics JOIN buckets USING (application_name) GROUP BY 1, 2, 3;`) - var applicationName string - var secondsSum int64 - var secondsCount uint64 + var applicationName sql.NullString + var secondsSum sql.NullInt64 + var secondsCount sql.NullInt64 var seconds []int64 var secondsBucket []uint64 @@ -97,10 +99,24 @@ func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch if err != nil { return err } + + applicationNameLabel := "unknown" + if applicationName.Valid { + applicationNameLabel = applicationName.String + } + + var secondsCountMetric uint64 + if secondsCount.Valid { + secondsCountMetric = uint64(secondsCount.Int64) + } + secondsSumMetric := 0.0 + if secondsSum.Valid { + secondsSumMetric = float64(secondsSum.Int64) + } ch <- prometheus.MustNewConstHistogram( pgProcessIdleSeconds, - secondsCount, float64(secondsSum), buckets, - applicationName, + secondsCountMetric, secondsSumMetric, buckets, + applicationNameLabel, ) return nil } diff --git a/collector/pg_replication_slot.go b/collector/pg_replication_slot.go index 4278923f8..43eb8a9db 100644 --- a/collector/pg_replication_slot.go +++ b/collector/pg_replication_slot.go @@ -15,6 +15,7 @@ package collector import ( "context" + "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" @@ -82,32 +83,44 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance defer rows.Close() for rows.Next() { - var slotName string - var walLSN int64 - var flushLSN int64 - var isActive bool + var slotName sql.NullString + var walLSN sql.NullFloat64 + var flushLSN sql.NullFloat64 + var isActive sql.NullBool if err := rows.Scan(&slotName, &walLSN, &flushLSN, &isActive); err != nil { return err } - isActiveValue := 0 - if isActive { - isActiveValue = 1 + isActiveValue := 0.0 + if isActive.Valid && isActive.Bool { + isActiveValue = 1.0 + } + slotNameLabel := "unknown" + if slotName.Valid { + slotNameLabel = slotName.String } + var walLSNMetric float64 + if walLSN.Valid { + walLSNMetric = walLSN.Float64 + } ch <- prometheus.MustNewConstMetric( pgReplicationSlotCurrentWalDesc, - prometheus.GaugeValue, float64(walLSN), slotName, + prometheus.GaugeValue, walLSNMetric, slotNameLabel, ) - if isActive { + if isActive.Valid && isActive.Bool { + var flushLSNMetric float64 + if flushLSN.Valid { + flushLSNMetric = flushLSN.Float64 + } ch <- prometheus.MustNewConstMetric( pgReplicationSlotCurrentFlushDesc, - prometheus.GaugeValue, float64(flushLSN), slotName, + prometheus.GaugeValue, flushLSNMetric, slotNameLabel, ) } ch <- prometheus.MustNewConstMetric( pgReplicationSlotIsActiveDesc, - prometheus.GaugeValue, float64(isActiveValue), slotName, + prometheus.GaugeValue, isActiveValue, slotNameLabel, ) } if err := rows.Err(); err != nil { diff --git a/collector/pg_replication_slot_test.go b/collector/pg_replication_slot_test.go index cb25b755a..7e91ea261 100644 --- a/collector/pg_replication_slot_test.go +++ b/collector/pg_replication_slot_test.go @@ -103,3 +103,84 @@ func TestPgReplicationSlotCollectorInActive(t *testing.T) { } } + +func TestPgReplicationSlotCollectorActiveNil(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{"slot_name", "current_wal_lsn", "confirmed_flush_lsn", "active"} + rows := sqlmock.NewRows(columns). + AddRow("test_slot", 6, 12, nil) + mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGReplicationSlotCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGReplicationSlotCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"slot_name": "test_slot"}, value: 6, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot"}, value: 0, metricType: dto.MetricType_GAUGE}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} + +func TestPgReplicationSlotCollectorTestNilValues(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{"slot_name", "current_wal_lsn", "confirmed_flush_lsn", "active"} + rows := sqlmock.NewRows(columns). + AddRow(nil, nil, nil, true) + mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGReplicationSlotCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGReplicationSlotCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"slot_name": "unknown"}, value: 0, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "unknown"}, value: 0, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "unknown"}, value: 1, metricType: dto.MetricType_GAUGE}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_stat_bgwriter.go b/collector/pg_stat_bgwriter.go index 2bdef8d40..ec446d58c 100644 --- a/collector/pg_stat_bgwriter.go +++ b/collector/pg_stat_bgwriter.go @@ -15,7 +15,7 @@ package collector import ( "context" - "time" + "database/sql" "github.com/prometheus/client_golang/prometheus" ) @@ -121,77 +121,113 @@ func (PGStatBGWriterCollector) Update(ctx context.Context, instance *instance, c row := db.QueryRowContext(ctx, statBGWriterQuery) - var cpt int - var cpr int - var cpwt float64 - var cpst float64 - var bcp int - var bc int - var mwc int - var bb int - var bbf int - var ba int - var sr time.Time + var cpt, cpr, bcp, bc, mwc, bb, bbf, ba sql.NullInt64 + var cpwt, cpst sql.NullFloat64 + var sr sql.NullTime err := row.Scan(&cpt, &cpr, &cpwt, &cpst, &bcp, &bc, &mwc, &bb, &bbf, &ba, &sr) if err != nil { return err } + cptMetric := 0.0 + if cpt.Valid { + cptMetric = float64(cpt.Int64) + } ch <- prometheus.MustNewConstMetric( statBGWriterCheckpointsTimedDesc, prometheus.CounterValue, - float64(cpt), + cptMetric, ) + cprMetric := 0.0 + if cpr.Valid { + cprMetric = float64(cpr.Int64) + } ch <- prometheus.MustNewConstMetric( statBGWriterCheckpointsReqDesc, prometheus.CounterValue, - float64(cpr), + cprMetric, ) + cpwtMetric := 0.0 + if cpwt.Valid { + cpwtMetric = float64(cpwt.Float64) + } ch <- prometheus.MustNewConstMetric( statBGWriterCheckpointsReqTimeDesc, prometheus.CounterValue, - float64(cpwt), + cpwtMetric, ) + cpstMetric := 0.0 + if cpst.Valid { + cpstMetric = float64(cpst.Float64) + } ch <- prometheus.MustNewConstMetric( statBGWriterCheckpointsSyncTimeDesc, prometheus.CounterValue, - float64(cpst), + cpstMetric, ) + bcpMetric := 0.0 + if bcp.Valid { + bcpMetric = float64(bcp.Int64) + } ch <- prometheus.MustNewConstMetric( statBGWriterBuffersCheckpointDesc, prometheus.CounterValue, - float64(bcp), + bcpMetric, ) + bcMetric := 0.0 + if bc.Valid { + bcMetric = float64(bc.Int64) + } ch <- prometheus.MustNewConstMetric( statBGWriterBuffersCleanDesc, prometheus.CounterValue, - float64(bc), + bcMetric, ) + mwcMetric := 0.0 + if mwc.Valid { + mwcMetric = float64(mwc.Int64) + } ch <- prometheus.MustNewConstMetric( statBGWriterMaxwrittenCleanDesc, prometheus.CounterValue, - float64(mwc), + mwcMetric, ) + bbMetric := 0.0 + if bb.Valid { + bbMetric = float64(bb.Int64) + } ch <- prometheus.MustNewConstMetric( statBGWriterBuffersBackendDesc, prometheus.CounterValue, - float64(bb), + bbMetric, ) + bbfMetric := 0.0 + if bbf.Valid { + bbfMetric = float64(bbf.Int64) + } ch <- prometheus.MustNewConstMetric( statBGWriterBuffersBackendFsyncDesc, prometheus.CounterValue, - float64(bbf), + bbfMetric, ) + baMetric := 0.0 + if ba.Valid { + baMetric = float64(ba.Int64) + } ch <- prometheus.MustNewConstMetric( statBGWriterBuffersAllocDesc, prometheus.CounterValue, - float64(ba), + baMetric, ) + srMetric := 0.0 + if sr.Valid { + srMetric = float64(sr.Time.Unix()) + } ch <- prometheus.MustNewConstMetric( statBGWriterStatsResetDesc, prometheus.CounterValue, - float64(sr.Unix()), + srMetric, ) return nil diff --git a/collector/pg_stat_bgwriter_test.go b/collector/pg_stat_bgwriter_test.go index 11f55f6be..ddf9976a2 100644 --- a/collector/pg_stat_bgwriter_test.go +++ b/collector/pg_stat_bgwriter_test.go @@ -88,3 +88,64 @@ func TestPGStatBGWriterCollector(t *testing.T) { t.Errorf("there were unfulfilled exceptions: %s", err) } } + +func TestPGStatBGWriterCollectorNullValues(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{ + "checkpoints_timed", + "checkpoints_req", + "checkpoint_write_time", + "checkpoint_sync_time", + "buffers_checkpoint", + "buffers_clean", + "maxwritten_clean", + "buffers_backend", + "buffers_backend_fsync", + "buffers_alloc", + "stats_reset"} + + rows := sqlmock.NewRows(columns). + AddRow(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + mock.ExpectQuery(sanitizeQuery(statBGWriterQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatBGWriterCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatBGWriterCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_stat_database.go b/collector/pg_stat_database.go index bb39a84b1..8a882f891 100644 --- a/collector/pg_stat_database.go +++ b/collector/pg_stat_database.go @@ -202,12 +202,9 @@ var ( []string{"datid", "datname"}, prometheus.Labels{}, ) -) -func (PGStatDatabaseCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { - db := instance.getDB() - rows, err := db.QueryContext(ctx, - `SELECT + statDatabaseQuery = ` + SELECT datid ,datname ,numbackends @@ -228,7 +225,13 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, instance *instance, c ,blk_write_time ,stats_reset FROM pg_stat_database; - `, + ` +) + +func (PGStatDatabaseCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + rows, err := db.QueryContext(ctx, + statDatabaseQuery, ) if err != nil { return err @@ -236,24 +239,8 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, instance *instance, c defer rows.Close() for rows.Next() { - var datid string - var datname string - var numBackends float64 - var xactCommit float64 - var xactRollback float64 - var blksRead float64 - var blksHit float64 - var tupReturned float64 - var tupFetched float64 - var tupInserted float64 - var tupUpdated float64 - var tupDeleted float64 - var conflicts float64 - var tempFiles float64 - var tempBytes float64 - var deadlocks float64 - var blkReadTime float64 - var blkWriteTime float64 + var datid, datname sql.NullString + var numBackends, xactCommit, xactRollback, blksRead, blksHit, tupReturned, tupFetched, tupInserted, tupUpdated, tupDeleted, conflicts, tempFiles, tempBytes, deadlocks, blkReadTime, blkWriteTime sql.NullFloat64 var statsReset sql.NullTime err := rows.Scan( @@ -280,152 +267,218 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, instance *instance, c if err != nil { return err } + datidLabel := "unknown" + if datid.Valid { + datidLabel = datid.String + } + datnameLabel := "unknown" + if datname.Valid { + datnameLabel = datname.String + } + numBackendsMetric := 0.0 + if numBackends.Valid { + numBackendsMetric = numBackends.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseNumbackends, prometheus.GaugeValue, - numBackends, - datid, - datname, + numBackendsMetric, + datidLabel, + datnameLabel, ) + xactCommitMetric := 0.0 + if xactCommit.Valid { + xactCommitMetric = xactCommit.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseXactCommit, prometheus.CounterValue, - xactCommit, - datid, - datname, + xactCommitMetric, + datidLabel, + datnameLabel, ) + xactRollbackMetric := 0.0 + if xactRollback.Valid { + xactRollbackMetric = xactRollback.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseXactRollback, prometheus.CounterValue, - xactRollback, - datid, - datname, + xactRollbackMetric, + datidLabel, + datnameLabel, ) + blksReadMetric := 0.0 + if blksRead.Valid { + blksReadMetric = blksRead.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseBlksRead, prometheus.CounterValue, - blksRead, - datid, - datname, + blksReadMetric, + datidLabel, + datnameLabel, ) + blksHitMetric := 0.0 + if blksHit.Valid { + blksHitMetric = blksHit.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseBlksHit, prometheus.CounterValue, - blksHit, - datid, - datname, + blksHitMetric, + datidLabel, + datnameLabel, ) + tupReturnedMetric := 0.0 + if tupReturned.Valid { + tupReturnedMetric = tupReturned.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseTupReturned, prometheus.CounterValue, - tupReturned, - datid, - datname, + tupReturnedMetric, + datidLabel, + datnameLabel, ) + tupFetchedMetric := 0.0 + if tupFetched.Valid { + tupFetchedMetric = tupFetched.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseTupFetched, prometheus.CounterValue, - tupFetched, - datid, - datname, + tupFetchedMetric, + datidLabel, + datnameLabel, ) + tupInsertedMetric := 0.0 + if tupInserted.Valid { + tupInsertedMetric = tupInserted.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseTupInserted, prometheus.CounterValue, - tupInserted, - datid, - datname, + tupInsertedMetric, + datidLabel, + datnameLabel, ) + tupUpdatedMetric := 0.0 + if tupUpdated.Valid { + tupUpdatedMetric = tupUpdated.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseTupUpdated, prometheus.CounterValue, - tupUpdated, - datid, - datname, + tupUpdatedMetric, + datidLabel, + datnameLabel, ) + tupDeletedMetric := 0.0 + if tupDeleted.Valid { + tupDeletedMetric = tupDeleted.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseTupDeleted, prometheus.CounterValue, - tupDeleted, - datid, - datname, + tupDeletedMetric, + datidLabel, + datnameLabel, ) + conflictsMetric := 0.0 + if conflicts.Valid { + conflictsMetric = conflicts.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseConflicts, prometheus.CounterValue, - conflicts, - datid, - datname, + conflictsMetric, + datidLabel, + datnameLabel, ) + tempFilesMetric := 0.0 + if tempFiles.Valid { + tempFilesMetric = tempFiles.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseTempFiles, prometheus.CounterValue, - tempFiles, - datid, - datname, + tempFilesMetric, + datidLabel, + datnameLabel, ) + tempBytesMetric := 0.0 + if tempBytes.Valid { + tempBytesMetric = tempBytes.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseTempBytes, prometheus.CounterValue, - tempBytes, - datid, - datname, + tempBytesMetric, + datidLabel, + datnameLabel, ) + deadlocksMetric := 0.0 + if deadlocks.Valid { + deadlocksMetric = deadlocks.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseDeadlocks, prometheus.CounterValue, - deadlocks, - datid, - datname, + deadlocksMetric, + datidLabel, + datnameLabel, ) + blkReadTimeMetric := 0.0 + if blkReadTime.Valid { + blkReadTimeMetric = blkReadTime.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseBlkReadTime, prometheus.CounterValue, - blkReadTime, - datid, - datname, + blkReadTimeMetric, + datidLabel, + datnameLabel, ) + blkWriteTimeMetric := 0.0 + if blkWriteTime.Valid { + blkWriteTimeMetric = blkWriteTime.Float64 + } ch <- prometheus.MustNewConstMetric( statDatabaseBlkWriteTime, prometheus.CounterValue, - blkWriteTime, - datid, - datname, + blkWriteTimeMetric, + datidLabel, + datnameLabel, ) + statsResetMetric := 0.0 if statsReset.Valid { - ch <- prometheus.MustNewConstMetric( - statDatabaseStatsReset, - prometheus.CounterValue, - float64(statsReset.Time.Unix()), - datid, - datname, - ) - } else { - ch <- prometheus.MustNewConstMetric( - statDatabaseStatsReset, - prometheus.CounterValue, - 0, - datid, - datname, - ) + statsResetMetric = float64(statsReset.Time.Unix()) } + ch <- prometheus.MustNewConstMetric( + statDatabaseStatsReset, + prometheus.CounterValue, + statsResetMetric, + datidLabel, + datnameLabel, + ) } return nil } diff --git a/collector/pg_stat_database_test.go b/collector/pg_stat_database_test.go new file mode 100644 index 000000000..0c2b5ea86 --- /dev/null +++ b/collector/pg_stat_database_test.go @@ -0,0 +1,359 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGStatDatabaseCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{ + "datid", + "datname", + "numbackends", + "xact_commit", + "xact_rollback", + "blks_read", + "blks_hit", + "tup_returned", + "tup_fetched", + "tup_inserted", + "tup_updated", + "tup_deleted", + "conflicts", + "temp_files", + "temp_bytes", + "deadlocks", + "blk_read_time", + "blk_write_time", + "stats_reset", + } + + srT, err := time.Parse("2006-01-02 15:04:05.00000-07", "2023-05-25 17:10:42.81132-07") + if err != nil { + t.Fatalf("Error parsing time: %s", err) + } + + rows := sqlmock.NewRows(columns). + AddRow( + "pid", + "postgres", + 354, + 4945, + 289097744, + 1242257, + 3275602074, + 89320867, + 450139, + 2034563757, + 0, + 2725688749, + 23, + 52, + 74, + 925, + 16, + 823, + srT) + + mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatDatabaseCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatDatabaseCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_GAUGE, value: 354}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 4945}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 289097744}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1242257}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 3275602074}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 89320867}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 450139}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 2034563757}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 2725688749}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 23}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 52}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 74}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} + +func TestPGStatDatabaseCollectorNullValues(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{ + "datid", + "datname", + "numbackends", + "xact_commit", + "xact_rollback", + "blks_read", + "blks_hit", + "tup_returned", + "tup_fetched", + "tup_inserted", + "tup_updated", + "tup_deleted", + "conflicts", + "temp_files", + "temp_bytes", + "deadlocks", + "blk_read_time", + "blk_write_time", + "stats_reset", + } + + rows := sqlmock.NewRows(columns). + AddRow( + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + ) + mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatDatabaseCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatDatabaseCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} +func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{ + "datid", + "datname", + "numbackends", + "xact_commit", + "xact_rollback", + "blks_read", + "blks_hit", + "tup_returned", + "tup_fetched", + "tup_inserted", + "tup_updated", + "tup_deleted", + "conflicts", + "temp_files", + "temp_bytes", + "deadlocks", + "blk_read_time", + "blk_write_time", + "stats_reset", + } + + srT, err := time.Parse("2006-01-02 15:04:05.00000-07", "2023-05-25 17:10:42.81132-07") + if err != nil { + t.Fatalf("Error parsing time: %s", err) + } + + rows := sqlmock.NewRows(columns). + AddRow( + "pid", + "postgres", + 354, + 4945, + 289097744, + 1242257, + 3275602074, + 89320867, + 450139, + 2034563757, + 0, + 2725688749, + 23, + 52, + 74, + 925, + 16, + 823, + srT). + AddRow( + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + ) + + mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatDatabaseCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatDatabaseCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_GAUGE, value: 354}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 4945}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 289097744}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1242257}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 3275602074}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 89320867}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 450139}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 2034563757}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 2725688749}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 23}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 52}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 74}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_stat_statements.go b/collector/pg_stat_statements.go index eb629c381..bbfee1a2b 100644 --- a/collector/pg_stat_statements.go +++ b/collector/pg_stat_statements.go @@ -15,6 +15,7 @@ package collector import ( "context" + "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" @@ -101,48 +102,80 @@ func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, } defer rows.Close() for rows.Next() { - var user string - var datname string - var queryid string - var callsTotal int64 - var secondsTotal float64 - var rowsTotal int64 - var blockReadSecondsTotal float64 - var blockWriteSecondsTotal float64 + var user, datname, queryid sql.NullString + var callsTotal, rowsTotal sql.NullInt64 + var secondsTotal, blockReadSecondsTotal, blockWriteSecondsTotal sql.NullFloat64 if err := rows.Scan(&user, &datname, &queryid, &callsTotal, &secondsTotal, &rowsTotal, &blockReadSecondsTotal, &blockWriteSecondsTotal); err != nil { return err } + userLabel := "unknown" + if user.Valid { + userLabel = user.String + } + datnameLabel := "unknown" + if datname.Valid { + datnameLabel = datname.String + } + queryidLabel := "unknown" + if queryid.Valid { + queryidLabel = queryid.String + } + + callsTotalMetric := 0.0 + if callsTotal.Valid { + callsTotalMetric = float64(callsTotal.Int64) + } ch <- prometheus.MustNewConstMetric( statSTatementsCallsTotal, prometheus.CounterValue, - float64(callsTotal), - user, datname, queryid, + callsTotalMetric, + userLabel, datnameLabel, queryidLabel, ) + + secondsTotalMetric := 0.0 + if secondsTotal.Valid { + secondsTotalMetric = secondsTotal.Float64 + } ch <- prometheus.MustNewConstMetric( statStatementsSecondsTotal, prometheus.CounterValue, - secondsTotal, - user, datname, queryid, + secondsTotalMetric, + userLabel, datnameLabel, queryidLabel, ) + + rowsTotalMetric := 0.0 + if rowsTotal.Valid { + rowsTotalMetric = float64(rowsTotal.Int64) + } ch <- prometheus.MustNewConstMetric( statStatementsRowsTotal, prometheus.CounterValue, - float64(rowsTotal), - user, datname, queryid, + rowsTotalMetric, + userLabel, datnameLabel, queryidLabel, ) + + blockReadSecondsTotalMetric := 0.0 + if blockReadSecondsTotal.Valid { + blockReadSecondsTotalMetric = blockReadSecondsTotal.Float64 + } ch <- prometheus.MustNewConstMetric( statStatementsBlockReadSecondsTotal, prometheus.CounterValue, - blockReadSecondsTotal, - user, datname, queryid, + blockReadSecondsTotalMetric, + userLabel, datnameLabel, queryidLabel, ) + + blockWriteSecondsTotalMetric := 0.0 + if blockWriteSecondsTotal.Valid { + blockWriteSecondsTotalMetric = blockWriteSecondsTotal.Float64 + } ch <- prometheus.MustNewConstMetric( statStatementsBlockWriteSecondsTotal, prometheus.CounterValue, - blockWriteSecondsTotal, - user, datname, queryid, + blockWriteSecondsTotalMetric, + userLabel, datnameLabel, queryidLabel, ) } if err := rows.Err(); err != nil { diff --git a/collector/pg_stat_statements_test.go b/collector/pg_stat_statements_test.go index 241699ad4..c4f89a60f 100644 --- a/collector/pg_stat_statements_test.go +++ b/collector/pg_stat_statements_test.go @@ -64,3 +64,46 @@ func TestPGStateStatementsCollector(t *testing.T) { t.Errorf("there were unfulfilled exceptions: %s", err) } } + +func TestPGStateStatementsCollectorNull(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} + rows := sqlmock.NewRows(columns). + AddRow(nil, nil, nil, nil, nil, nil, nil, nil) + mock.ExpectQuery(sanitizeQuery(pgStatStatementsQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatStatementsCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatStatementsCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_stat_user_tables.go b/collector/pg_stat_user_tables.go index 48ae96eb8..949a0ea2b 100644 --- a/collector/pg_stat_user_tables.go +++ b/collector/pg_stat_user_tables.go @@ -15,7 +15,7 @@ package collector import ( "context" - "time" + "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" @@ -189,146 +189,235 @@ func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instan defer rows.Close() for rows.Next() { - var datname string - var schemaname string - var relname string - var seqScan int64 - var seqTupRead int64 - var idxScan int64 - var idxTupFetch int64 - var nTupIns int64 - var nTupUpd int64 - var nTupDel int64 - var nTupHotUpd int64 - var nLiveTup int64 - var nDeadTup int64 - var nModSinceAnalyze int64 - var lastVacuum time.Time - var lastAutovacuum time.Time - var lastAnalyze time.Time - var lastAutoanalyze time.Time - var vacuumCount int64 - var autovacuumCount int64 - var analyzeCount int64 - var autoanalyzeCount int64 + var datname, schemaname, relname sql.NullString + var seqScan, seqTupRead, idxScan, idxTupFetch, nTupIns, nTupUpd, nTupDel, nTupHotUpd, nLiveTup, nDeadTup, + nModSinceAnalyze, vacuumCount, autovacuumCount, analyzeCount, autoanalyzeCount sql.NullInt64 + var lastVacuum, lastAutovacuum, lastAnalyze, lastAutoanalyze sql.NullTime if err := rows.Scan(&datname, &schemaname, &relname, &seqScan, &seqTupRead, &idxScan, &idxTupFetch, &nTupIns, &nTupUpd, &nTupDel, &nTupHotUpd, &nLiveTup, &nDeadTup, &nModSinceAnalyze, &lastVacuum, &lastAutovacuum, &lastAnalyze, &lastAutoanalyze, &vacuumCount, &autovacuumCount, &analyzeCount, &autoanalyzeCount); err != nil { return err } + datnameLabel := "unknown" + if datname.Valid { + datnameLabel = datname.String + } + schemanameLabel := "unknown" + if schemaname.Valid { + schemanameLabel = schemaname.String + } + relnameLabel := "unknown" + if relname.Valid { + relnameLabel = relname.String + } + + seqScanMetric := 0.0 + if seqScan.Valid { + seqScanMetric = float64(seqScan.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesSeqScan, prometheus.CounterValue, - float64(seqScan), - datname, schemaname, relname, + seqScanMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + seqTupReadMetric := 0.0 + if seqTupRead.Valid { + seqTupReadMetric = float64(seqTupRead.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesSeqTupRead, prometheus.CounterValue, - float64(seqTupRead), - datname, schemaname, relname, + seqTupReadMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + idxScanMetric := 0.0 + if idxScan.Valid { + idxScanMetric = float64(idxScan.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesIdxScan, prometheus.CounterValue, - float64(idxScan), - datname, schemaname, relname, + idxScanMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + idxTupFetchMetric := 0.0 + if idxTupFetch.Valid { + idxTupFetchMetric = float64(idxTupFetch.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesIdxTupFetch, prometheus.CounterValue, - float64(idxTupFetch), - datname, schemaname, relname, + idxTupFetchMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + nTupInsMetric := 0.0 + if nTupIns.Valid { + nTupInsMetric = float64(nTupIns.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesNTupIns, prometheus.CounterValue, - float64(nTupIns), - datname, schemaname, relname, + nTupInsMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + nTupUpdMetric := 0.0 + if nTupUpd.Valid { + nTupUpdMetric = float64(nTupUpd.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesNTupUpd, prometheus.CounterValue, - float64(nTupUpd), - datname, schemaname, relname, + nTupUpdMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + nTupDelMetric := 0.0 + if nTupDel.Valid { + nTupDelMetric = float64(nTupDel.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesNTupDel, prometheus.CounterValue, - float64(nTupDel), - datname, schemaname, relname, + nTupDelMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + nTupHotUpdMetric := 0.0 + if nTupHotUpd.Valid { + nTupHotUpdMetric = float64(nTupHotUpd.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesNTupHotUpd, prometheus.CounterValue, - float64(nTupHotUpd), - datname, schemaname, relname, + nTupHotUpdMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + nLiveTupMetric := 0.0 + if nLiveTup.Valid { + nLiveTupMetric = float64(nLiveTup.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesNLiveTup, prometheus.GaugeValue, - float64(nLiveTup), - datname, schemaname, relname, + nLiveTupMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + nDeadTupMetric := 0.0 + if nDeadTup.Valid { + nDeadTupMetric = float64(nDeadTup.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesNDeadTup, prometheus.GaugeValue, - float64(nDeadTup), - datname, schemaname, relname, + nDeadTupMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + nModSinceAnalyzeMetric := 0.0 + if nModSinceAnalyze.Valid { + nModSinceAnalyzeMetric = float64(nModSinceAnalyze.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesNModSinceAnalyze, prometheus.GaugeValue, - float64(nModSinceAnalyze), - datname, schemaname, relname, + nModSinceAnalyzeMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + lastVacuumMetric := 0.0 + if lastVacuum.Valid { + lastVacuumMetric = float64(lastVacuum.Time.Unix()) + } ch <- prometheus.MustNewConstMetric( statUserTablesLastVacuum, prometheus.GaugeValue, - float64(lastVacuum.Unix()), - datname, schemaname, relname, + lastVacuumMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + lastAutovacuumMetric := 0.0 + if lastAutovacuum.Valid { + lastAutovacuumMetric = float64(lastAutovacuum.Time.Unix()) + } ch <- prometheus.MustNewConstMetric( statUserTablesLastAutovacuum, prometheus.GaugeValue, - float64(lastAutovacuum.Unix()), - datname, schemaname, relname, + lastAutovacuumMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + lastAnalyzeMetric := 0.0 + if lastAnalyze.Valid { + lastAnalyzeMetric = float64(lastAnalyze.Time.Unix()) + } ch <- prometheus.MustNewConstMetric( statUserTablesLastAnalyze, prometheus.GaugeValue, - float64(lastAnalyze.Unix()), - datname, schemaname, relname, + lastAnalyzeMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + lastAutoanalyzeMetric := 0.0 + if lastAutoanalyze.Valid { + lastAutoanalyzeMetric = float64(lastAutoanalyze.Time.Unix()) + } ch <- prometheus.MustNewConstMetric( statUserTablesLastAutoanalyze, prometheus.GaugeValue, - float64(lastAutoanalyze.Unix()), - datname, schemaname, relname, + lastAutoanalyzeMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + vacuumCountMetric := 0.0 + if vacuumCount.Valid { + vacuumCountMetric = float64(vacuumCount.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesVacuumCount, prometheus.CounterValue, - float64(vacuumCount), - datname, schemaname, relname, + vacuumCountMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + autovacuumCountMetric := 0.0 + if autovacuumCount.Valid { + autovacuumCountMetric = float64(autovacuumCount.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesAutovacuumCount, prometheus.CounterValue, - float64(autovacuumCount), - datname, schemaname, relname, + autovacuumCountMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + analyzeCountMetric := 0.0 + if analyzeCount.Valid { + analyzeCountMetric = float64(analyzeCount.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesAnalyzeCount, prometheus.CounterValue, - float64(analyzeCount), - datname, schemaname, relname, + analyzeCountMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + autoanalyzeCountMetric := 0.0 + if autoanalyzeCount.Valid { + autoanalyzeCountMetric = float64(autoanalyzeCount.Int64) + } ch <- prometheus.MustNewConstMetric( statUserTablesAutoanalyzeCount, prometheus.CounterValue, - float64(autoanalyzeCount), - datname, schemaname, relname, + autoanalyzeCountMetric, + datnameLabel, schemanameLabel, relnameLabel, ) } diff --git a/collector/pg_stat_user_tables_test.go b/collector/pg_stat_user_tables_test.go index 8bb9bc31b..e592fa5e4 100644 --- a/collector/pg_stat_user_tables_test.go +++ b/collector/pg_stat_user_tables_test.go @@ -138,3 +138,102 @@ func TestPGStatUserTablesCollector(t *testing.T) { t.Errorf("there were unfulfilled exceptions: %s", err) } } + +func TestPGStatUserTablesCollectorNullValues(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{ + "datname", + "schemaname", + "relname", + "seq_scan", + "seq_tup_read", + "idx_scan", + "idx_tup_fetch", + "n_tup_ins", + "n_tup_upd", + "n_tup_del", + "n_tup_hot_upd", + "n_live_tup", + "n_dead_tup", + "n_mod_since_analyze", + "last_vacuum", + "last_autovacuum", + "last_analyze", + "last_autoanalyze", + "vacuum_count", + "autovacuum_count", + "analyze_count", + "autoanalyze_count"} + rows := sqlmock.NewRows(columns). + AddRow("postgres", + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil) + mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows) + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatUserTablesCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatUserTablesCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} diff --git a/collector/pg_statio_user_tables.go b/collector/pg_statio_user_tables.go index 03d541615..89fdec532 100644 --- a/collector/pg_statio_user_tables.go +++ b/collector/pg_statio_user_tables.go @@ -15,6 +15,7 @@ package collector import ( "context" + "database/sql" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" @@ -110,69 +111,111 @@ func (PGStatIOUserTablesCollector) Update(ctx context.Context, instance *instanc defer rows.Close() for rows.Next() { - var datname string - var schemaname string - var relname string - var heapBlksRead int64 - var heapBlksHit int64 - var idxBlksRead int64 - var idxBlksHit int64 - var toastBlksRead int64 - var toastBlksHit int64 - var tidxBlksRead int64 - var tidxBlksHit int64 + var datname, schemaname, relname sql.NullString + var heapBlksRead, heapBlksHit, idxBlksRead, idxBlksHit, toastBlksRead, toastBlksHit, tidxBlksRead, tidxBlksHit sql.NullInt64 if err := rows.Scan(&datname, &schemaname, &relname, &heapBlksRead, &heapBlksHit, &idxBlksRead, &idxBlksHit, &toastBlksRead, &toastBlksHit, &tidxBlksRead, &tidxBlksHit); err != nil { return err } + datnameLabel := "unknown" + if datname.Valid { + datnameLabel = datname.String + } + schemanameLabel := "unknown" + if schemaname.Valid { + schemanameLabel = schemaname.String + } + relnameLabel := "unknown" + if relname.Valid { + relnameLabel = relname.String + } + heapBlksReadMetric := 0.0 + if heapBlksRead.Valid { + heapBlksReadMetric = float64(heapBlksRead.Int64) + } ch <- prometheus.MustNewConstMetric( statioUserTablesHeapBlksRead, prometheus.CounterValue, - float64(heapBlksRead), - datname, schemaname, relname, + heapBlksReadMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + heapBlksHitMetric := 0.0 + if heapBlksHit.Valid { + heapBlksHitMetric = float64(heapBlksHit.Int64) + } ch <- prometheus.MustNewConstMetric( statioUserTablesHeapBlksHit, prometheus.CounterValue, - float64(heapBlksHit), - datname, schemaname, relname, + heapBlksHitMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + idxBlksReadMetric := 0.0 + if idxBlksRead.Valid { + idxBlksReadMetric = float64(idxBlksRead.Int64) + } ch <- prometheus.MustNewConstMetric( statioUserTablesIdxBlksRead, prometheus.CounterValue, - float64(idxBlksRead), - datname, schemaname, relname, + idxBlksReadMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + idxBlksHitMetric := 0.0 + if idxBlksHit.Valid { + idxBlksHitMetric = float64(idxBlksHit.Int64) + } ch <- prometheus.MustNewConstMetric( statioUserTablesIdxBlksHit, prometheus.CounterValue, - float64(idxBlksHit), - datname, schemaname, relname, + idxBlksHitMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + toastBlksReadMetric := 0.0 + if toastBlksRead.Valid { + toastBlksReadMetric = float64(toastBlksRead.Int64) + } ch <- prometheus.MustNewConstMetric( statioUserTablesToastBlksRead, prometheus.CounterValue, - float64(toastBlksRead), - datname, schemaname, relname, + toastBlksReadMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + toastBlksHitMetric := 0.0 + if toastBlksHit.Valid { + toastBlksHitMetric = float64(toastBlksHit.Int64) + } ch <- prometheus.MustNewConstMetric( statioUserTablesToastBlksHit, prometheus.CounterValue, - float64(toastBlksHit), - datname, schemaname, relname, + toastBlksHitMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + tidxBlksReadMetric := 0.0 + if tidxBlksRead.Valid { + tidxBlksReadMetric = float64(tidxBlksRead.Int64) + } ch <- prometheus.MustNewConstMetric( statioUserTablesTidxBlksRead, prometheus.CounterValue, - float64(tidxBlksRead), - datname, schemaname, relname, + tidxBlksReadMetric, + datnameLabel, schemanameLabel, relnameLabel, ) + + tidxBlksHitMetric := 0.0 + if tidxBlksHit.Valid { + tidxBlksHitMetric = float64(tidxBlksHit.Int64) + } ch <- prometheus.MustNewConstMetric( statioUserTablesTidxBlksHit, prometheus.CounterValue, - float64(tidxBlksHit), - datname, schemaname, relname, + tidxBlksHitMetric, + datnameLabel, schemanameLabel, relnameLabel, ) } if err := rows.Err(); err != nil { diff --git a/collector/pg_statio_user_tables_test.go b/collector/pg_statio_user_tables_test.go index d57cab9f5..c7304a38c 100644 --- a/collector/pg_statio_user_tables_test.go +++ b/collector/pg_statio_user_tables_test.go @@ -88,3 +88,70 @@ func TestPGStatIOUserTablesCollector(t *testing.T) { t.Errorf("there were unfulfilled exceptions: %s", err) } } + +func TestPGStatIOUserTablesCollectorNullValues(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{ + "datname", + "schemaname", + "relname", + "heap_blks_read", + "heap_blks_hit", + "idx_blks_read", + "idx_blks_hit", + "toast_blks_read", + "toast_blks_hit", + "tidx_blks_read", + "tidx_blks_hit", + } + rows := sqlmock.NewRows(columns). + AddRow(nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil) + mock.ExpectQuery(sanitizeQuery(statioUserTablesQuery)).WillReturnRows(rows) + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatIOUserTablesCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatIOUserTablesCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datname": "unknown", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "unknown", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "unknown", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "unknown", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "unknown", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "unknown", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "unknown", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "unknown", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From bf4e4fb6cca3191d3c41df2efdf5d15d17b5fa60 Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Tue, 27 Jun 2023 13:13:41 +0200 Subject: [PATCH 115/228] Release 0.13.1 (#824) * [BUGFIX] Make collectors not fail on null values #823 Signed-off-by: SuperQ --- CHANGELOG.md | 4 ++++ VERSION | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a13c53eb..318e3648e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.13.1 / 2023-06-27 + +* [BUGFIX] Make collectors not fail on null values #823 + ## 0.13.0 / 2023-06-21 BREAKING CHANGES: diff --git a/VERSION b/VERSION index 54d1a4f2a..c317a9189 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.13.0 +0.13.1 From 6a1bb59efb69df5d9fb223f6a72764174d8d4449 Mon Sep 17 00:00:00 2001 From: Vadim Voitenko <74241416+wwoytenko@users.noreply.github.com> Date: Tue, 27 Jun 2023 16:47:33 +0300 Subject: [PATCH 116/228] Fixed replication pgReplicationSlotQuery - now it's working correctly for replica and primary (#825) Signed-off-by: Vadim Voitenko Co-authored-by: Vadim Voitenko --- collector/pg_replication_slot.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/collector/pg_replication_slot.go b/collector/pg_replication_slot.go index 43eb8a9db..dec1b5da0 100644 --- a/collector/pg_replication_slot.go +++ b/collector/pg_replication_slot.go @@ -66,11 +66,14 @@ var ( pgReplicationSlotQuery = `SELECT slot_name, - pg_current_wal_lsn() - '0/0' AS current_wal_lsn, - coalesce(confirmed_flush_lsn, '0/0') - '0/0', + CASE WHEN pg_is_in_recovery() THEN + pg_last_wal_receive_lsn() - '0/0' + ELSE + pg_current_wal_lsn() - '0/0' + END AS current_wal_lsn, + COALESCE(confirmed_flush_lsn, '0/0') - '0/0', active - FROM - pg_replication_slots;` + FROM pg_replication_slots;` ) func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { From 1a4e8993f6b5cf7de273d65e1054482fae610ef2 Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Tue, 27 Jun 2023 15:59:30 +0200 Subject: [PATCH 117/228] Migrate pg_locks to collector package (#817) Migrate the `pg_locks_count` query from `main` to the `collector` package. Signed-off-by: SuperQ --- README.md | 5 +- cmd/postgres_exporter/postgres_exporter.go | 9 -- cmd/postgres_exporter/queries.go | 25 ---- collector/pg_locks.go | 129 +++++++++++++++++++++ collector/pg_locks_test.go | 60 ++++++++++ 5 files changed, 193 insertions(+), 35 deletions(-) create mode 100644 collector/pg_locks.go create mode 100644 collector/pg_locks_test.go diff --git a/README.md b/README.md index 912ea0c5d..e3774c85c 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,10 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra * `[no-]collector.database` - Enable the database collector (default: enabled). + Enable the `database` collector (default: enabled). + +* `[no-]collector.locks` + Enable the `locks` collector (default: enabled). * `[no-]collector.postmaster` Enable the `postmaster` collector (default: enabled). diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index 6b5908e43..fa34eecc5 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -176,15 +176,6 @@ var builtinMetricMaps = map[string]intermediateMetricMap{ true, 0, }, - "pg_locks": { - map[string]ColumnMapping{ - "datname": {LABEL, "Name of this database", nil, nil}, - "mode": {LABEL, "Type of Lock", nil, nil}, - "count": {GAUGE, "Number of locks", nil, nil}, - }, - true, - 0, - }, "pg_stat_replication": { map[string]ColumnMapping{ "procpid": {DISCARD, "Process ID of a WAL sender process", nil, semver.MustParseRange("<9.2.0")}, diff --git a/cmd/postgres_exporter/queries.go b/cmd/postgres_exporter/queries.go index 14c14b4f8..fa0b5c272 100644 --- a/cmd/postgres_exporter/queries.go +++ b/cmd/postgres_exporter/queries.go @@ -46,31 +46,6 @@ type OverrideQuery struct { // Overriding queries for namespaces above. // TODO: validate this is a closed set in tests, and there are no overlaps var queryOverrides = map[string][]OverrideQuery{ - "pg_locks": { - { - semver.MustParseRange(">0.0.0"), - `SELECT pg_database.datname,tmp.mode,COALESCE(count,0) as count - FROM - ( - VALUES ('accesssharelock'), - ('rowsharelock'), - ('rowexclusivelock'), - ('shareupdateexclusivelock'), - ('sharelock'), - ('sharerowexclusivelock'), - ('exclusivelock'), - ('accessexclusivelock'), - ('sireadlock') - ) AS tmp(mode) CROSS JOIN pg_database - LEFT JOIN - (SELECT database, lower(mode) AS mode,count(*) AS count - FROM pg_locks WHERE database IS NOT NULL - GROUP BY database, lower(mode) - ) AS tmp2 - ON tmp.mode=tmp2.mode and pg_database.oid = tmp2.database ORDER BY 1`, - }, - }, - "pg_stat_replication": { { semver.MustParseRange(">=10.0.0"), diff --git a/collector/pg_locks.go b/collector/pg_locks.go new file mode 100644 index 000000000..d2c77ccd5 --- /dev/null +++ b/collector/pg_locks.go @@ -0,0 +1,129 @@ +// Copyright 2023 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 collector + +import ( + "context" + "database/sql" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +const locksSubsystem = "locks" + +func init() { + registerCollector(locksSubsystem, defaultEnabled, NewPGLocksCollector) +} + +type PGLocksCollector struct { + log log.Logger +} + +func NewPGLocksCollector(config collectorConfig) (Collector, error) { + return &PGLocksCollector{ + log: config.logger, + }, nil +} + +var ( + pgLocksDesc = prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + locksSubsystem, + "count", + ), + "Number of locks", + []string{"datname", "mode"}, nil, + ) + + pgLocksQuery = ` + SELECT + pg_database.datname as datname, + tmp.mode as mode, + COALESCE(count, 0) as count + FROM + ( + VALUES + ('accesssharelock'), + ('rowsharelock'), + ('rowexclusivelock'), + ('shareupdateexclusivelock'), + ('sharelock'), + ('sharerowexclusivelock'), + ('exclusivelock'), + ('accessexclusivelock'), + ('sireadlock') + ) AS tmp(mode) + CROSS JOIN pg_database + LEFT JOIN ( + SELECT + database, + lower(mode) AS mode, + count(*) AS count + FROM + pg_locks + WHERE + database IS NOT NULL + GROUP BY + database, + lower(mode) + ) AS tmp2 ON tmp.mode = tmp2.mode + and pg_database.oid = tmp2.database + ORDER BY + 1 + ` +) + +// Update implements Collector and exposes database locks. +// It is called by the Prometheus registry when collecting metrics. +func (c PGLocksCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + // Query the list of databases + rows, err := db.QueryContext(ctx, + pgLocksQuery, + ) + if err != nil { + return err + } + defer rows.Close() + + var datname, mode sql.NullString + var count sql.NullInt64 + + for rows.Next() { + if err := rows.Scan(&datname, &mode, &count); err != nil { + return err + } + + if !datname.Valid || !mode.Valid { + continue + } + + countMetric := 0.0 + if count.Valid { + countMetric = float64(count.Int64) + } + + ch <- prometheus.MustNewConstMetric( + pgLocksDesc, + prometheus.GaugeValue, countMetric, + datname.String, mode.String, + ) + } + if err := rows.Err(); err != nil { + return err + } + return nil +} diff --git a/collector/pg_locks_test.go b/collector/pg_locks_test.go new file mode 100644 index 000000000..99597ea2d --- /dev/null +++ b/collector/pg_locks_test.go @@ -0,0 +1,60 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGLocksCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + rows := sqlmock.NewRows([]string{"datname", "mode", "count"}). + AddRow("test", "exclusivelock", 42) + + mock.ExpectQuery(sanitizeQuery(pgLocksQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGLocksCollector{} + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGLocksCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datname": "test", "mode": "exclusivelock"}, value: 42, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From 030a2a9bc713097e93d037b6c7031114e21dbd60 Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Tue, 27 Jun 2023 16:40:12 +0200 Subject: [PATCH 118/228] Cleanup collectors (#826) Fix up `replication` and `process_idle` Update input params to match the rest of the collectors. Signed-off-by: SuperQ --- collector/pg_process_idle.go | 4 ++-- collector/pg_replication.go | 4 ++-- collector/pg_replication_test.go | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/collector/pg_process_idle.go b/collector/pg_process_idle.go index cc53fbb73..4f4aa4cdd 100644 --- a/collector/pg_process_idle.go +++ b/collector/pg_process_idle.go @@ -43,8 +43,8 @@ var pgProcessIdleSeconds = prometheus.NewDesc( prometheus.Labels{}, ) -func (PGProcessIdleCollector) Update(ctx context.Context, inst *instance, ch chan<- prometheus.Metric) error { - db := inst.getDB() +func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() row := db.QueryRowContext(ctx, `WITH metrics AS ( diff --git a/collector/pg_replication.go b/collector/pg_replication.go index 1a8a3569f..ee92e74fc 100644 --- a/collector/pg_replication.go +++ b/collector/pg_replication.go @@ -15,7 +15,6 @@ package collector import ( "context" - "database/sql" "github.com/prometheus/client_golang/prometheus" ) @@ -64,7 +63,8 @@ var ( END as is_replica` ) -func (c *PGReplicationCollector) Update(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error { +func (c *PGReplicationCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() row := db.QueryRowContext(ctx, pgReplicationQuery, ) diff --git a/collector/pg_replication_test.go b/collector/pg_replication_test.go index 4d240cdf3..b6df698e3 100644 --- a/collector/pg_replication_test.go +++ b/collector/pg_replication_test.go @@ -29,6 +29,8 @@ func TestPgReplicationCollector(t *testing.T) { } defer db.Close() + inst := &instance{db: db} + columns := []string{"lag", "is_replica"} rows := sqlmock.NewRows(columns). AddRow(1000, 1) @@ -39,7 +41,7 @@ func TestPgReplicationCollector(t *testing.T) { defer close(ch) c := PGReplicationCollector{} - if err := c.Update(context.Background(), db, ch); err != nil { + if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGReplicationCollector.Update: %s", err) } }() From e6ce2ecba94d543e3232625d2402fe6ccbf78f30 Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Tue, 27 Jun 2023 11:18:02 -0700 Subject: [PATCH 119/228] Bug Fix: Fix lingering type issues (#828) * Fix postmaster type issue * Disable postmaster collector by default --------- Signed-off-by: Felix Yuan --- collector/pg_postmaster.go | 4 ++-- collector/pg_process_idle.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/collector/pg_postmaster.go b/collector/pg_postmaster.go index 4bef42964..b81e4f905 100644 --- a/collector/pg_postmaster.go +++ b/collector/pg_postmaster.go @@ -23,7 +23,7 @@ import ( const postmasterSubsystem = "postmaster" func init() { - registerCollector(postmasterSubsystem, defaultEnabled, NewPGPostmasterCollector) + registerCollector(postmasterSubsystem, defaultDisabled, NewPGPostmasterCollector) } type PGPostmasterCollector struct { @@ -44,7 +44,7 @@ var ( []string{}, nil, ) - pgPostmasterQuery = "SELECT pg_postmaster_start_time from pg_postmaster_start_time();" + pgPostmasterQuery = "SELECT extract(epoch from pg_postmaster_start_time) from pg_postmaster_start_time();" ) func (c *PGPostmasterCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { diff --git a/collector/pg_process_idle.go b/collector/pg_process_idle.go index 4f4aa4cdd..57df723a3 100644 --- a/collector/pg_process_idle.go +++ b/collector/pg_process_idle.go @@ -84,7 +84,7 @@ func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch var applicationName sql.NullString var secondsSum sql.NullInt64 var secondsCount sql.NullInt64 - var seconds []int64 + var seconds []uint64 var secondsBucket []uint64 err := row.Scan(&applicationName, &secondsSum, &secondsCount, &seconds, &secondsBucket) From dcf498e709b121eb1ff2e193f66c8ff2d4611b58 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Tue, 27 Jun 2023 20:18:40 +0200 Subject: [PATCH 120/228] Update common Prometheus files (#829) Signed-off-by: prombot --- Makefile.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.common b/Makefile.common index e372d3473..787feff08 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.51.2 +GOLANGCI_LINT_VERSION ?= v1.53.3 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) From d9205532273ecfdcf15e27e0059bc6b3e99b586e Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Mon, 3 Jul 2023 17:51:50 +0100 Subject: [PATCH 121/228] Fix replication collector Signed-off-by: Tom Hughes --- collector/pg_replication.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collector/pg_replication.go b/collector/pg_replication.go index ee92e74fc..790f85329 100644 --- a/collector/pg_replication.go +++ b/collector/pg_replication.go @@ -29,7 +29,7 @@ type PGReplicationCollector struct { } func NewPGReplicationCollector(collectorConfig) (Collector, error) { - return &PGPostmasterCollector{}, nil + return &PGReplicationCollector{}, nil } var ( From 099d3ddb6f7235e51b6ebc1f53130dab94529838 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Tue, 4 Jul 2023 19:08:35 +0100 Subject: [PATCH 122/228] Add some more escapes to the query sanitizer Signed-off-by: Tom Hughes --- collector/collector_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/collector/collector_test.go b/collector/collector_test.go index 061de8895..00c21ed23 100644 --- a/collector/collector_test.go +++ b/collector/collector_test.go @@ -50,7 +50,12 @@ func sanitizeQuery(q string) string { q = strings.Join(strings.Fields(q), " ") q = strings.Replace(q, "(", "\\(", -1) q = strings.Replace(q, ")", "\\)", -1) + q = strings.Replace(q, "[", "\\[", -1) + q = strings.Replace(q, "]", "\\]", -1) + q = strings.Replace(q, "{", "\\{", -1) + q = strings.Replace(q, "}", "\\}", -1) q = strings.Replace(q, "*", "\\*", -1) + q = strings.Replace(q, "^", "\\^", -1) q = strings.Replace(q, "$", "\\$", -1) return q } From 2ca1798188dbcf5fe1c83c299ee8bc1932e2c9b1 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Tue, 4 Jul 2023 19:08:54 +0100 Subject: [PATCH 123/228] Add a collector to gather metrics on WAL size Signed-off-by: Tom Hughes --- collector/pg_wal.go | 84 ++++++++++++++++++++++++++++++++++++++++ collector/pg_wal_test.go | 63 ++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 collector/pg_wal.go create mode 100644 collector/pg_wal_test.go diff --git a/collector/pg_wal.go b/collector/pg_wal.go new file mode 100644 index 000000000..afa8fcef6 --- /dev/null +++ b/collector/pg_wal.go @@ -0,0 +1,84 @@ +// Copyright 2023 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 collector + +import ( + "context" + + "github.com/prometheus/client_golang/prometheus" +) + +const walSubsystem = "wal" + +func init() { + registerCollector(walSubsystem, defaultEnabled, NewPGWALCollector) +} + +type PGWALCollector struct { +} + +func NewPGWALCollector(config collectorConfig) (Collector, error) { + return &PGWALCollector{}, nil +} + +var ( + pgWALSegments = prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + walSubsystem, + "segments", + ), + "Number of WAL segments", + []string{}, nil, + ) + pgWALSize = prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + walSubsystem, + "size_bytes", + ), + "Total size of WAL segments", + []string{}, nil, + ) + + pgWALQuery = ` + SELECT + COUNT(*) AS segments, + SUM(size) AS size + FROM pg_ls_waldir() + WHERE name ~ '^[0-9A-F]{24}$'` +) + +func (c PGWALCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + row := db.QueryRowContext(ctx, + pgWALQuery, + ) + + var segments uint64 + var size uint64 + err := row.Scan(&segments, &size) + if err != nil { + return err + } + ch <- prometheus.MustNewConstMetric( + pgWALSegments, + prometheus.GaugeValue, float64(segments), + ) + ch <- prometheus.MustNewConstMetric( + pgWALSize, + prometheus.GaugeValue, float64(size), + ) + return nil +} diff --git a/collector/pg_wal_test.go b/collector/pg_wal_test.go new file mode 100644 index 000000000..745105a13 --- /dev/null +++ b/collector/pg_wal_test.go @@ -0,0 +1,63 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPgWALCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{"segments", "size"} + rows := sqlmock.NewRows(columns). + AddRow(47, 788529152) + mock.ExpectQuery(sanitizeQuery(pgWALQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGWALCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGWALCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{}, value: 47, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{}, value: 788529152, metricType: dto.MetricType_GAUGE}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From a6012e0b5443e7ed675ac95ae8fdc2874dfd00bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Jul 2023 15:10:03 +0200 Subject: [PATCH 124/228] Bump github.com/prometheus/client_golang from 1.15.1 to 1.16.0 (#853) Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.15.1 to 1.16.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.15.1...v1.16.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 6444a66e4..d51515c2b 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 github.com/lib/pq v1.10.9 - github.com/prometheus/client_golang v1.15.1 + github.com/prometheus/client_golang v1.16.0 github.com/prometheus/client_model v0.4.0 github.com/prometheus/common v0.44.0 github.com/prometheus/exporter-toolkit v0.10.0 @@ -32,14 +32,14 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/prometheus/procfs v0.9.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smartystreets/assertions v1.13.1 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect golang.org/x/crypto v0.8.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sync v0.1.0 // indirect + golang.org/x/sync v0.2.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 12673c116..ec641e8e8 100644 --- a/go.sum +++ b/go.sum @@ -49,16 +49,16 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= -github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= @@ -80,8 +80,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 2477aba363853d062181125b9dd9752272375684 Mon Sep 17 00:00:00 2001 From: Daniel Swarbrick Date: Wed, 5 Jul 2023 15:10:47 +0200 Subject: [PATCH 125/228] Fix untyped integer overflows on 32-bit archs (#857) go-sqlmock's Rows.AddRow() takes values which have a type alias of "any", and appear to default to untyped ints if not explicitly cast. When large values are passed which would overflow int32, tests fail. Signed-off-by: Daniel Swarbrick --- collector/pg_stat_bgwriter_test.go | 2 +- collector/pg_stat_database_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/collector/pg_stat_bgwriter_test.go b/collector/pg_stat_bgwriter_test.go index ddf9976a2..1c2cf98de 100644 --- a/collector/pg_stat_bgwriter_test.go +++ b/collector/pg_stat_bgwriter_test.go @@ -51,7 +51,7 @@ func TestPGStatBGWriterCollector(t *testing.T) { } rows := sqlmock.NewRows(columns). - AddRow(354, 4945, 289097744, 1242257, 3275602074, 89320867, 450139, 2034563757, 0, 2725688749, srT) + AddRow(354, 4945, 289097744, 1242257, int64(3275602074), 89320867, 450139, 2034563757, 0, int64(2725688749), srT) mock.ExpectQuery(sanitizeQuery(statBGWriterQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) diff --git a/collector/pg_stat_database_test.go b/collector/pg_stat_database_test.go index 0c2b5ea86..1fe92eedc 100644 --- a/collector/pg_stat_database_test.go +++ b/collector/pg_stat_database_test.go @@ -67,12 +67,12 @@ func TestPGStatDatabaseCollector(t *testing.T) { 4945, 289097744, 1242257, - 3275602074, + int64(3275602074), 89320867, 450139, 2034563757, 0, - 2725688749, + int64(2725688749), 23, 52, 74, @@ -263,12 +263,12 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { 4945, 289097744, 1242257, - 3275602074, + int64(3275602074), 89320867, 450139, 2034563757, 0, - 2725688749, + int64(2725688749), 23, 52, 74, From 401711b2e3fd0e58ba0575c43cdcf7d2d21246e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jul 2023 08:42:23 +0200 Subject: [PATCH 126/228] Bump github.com/smartystreets/goconvey from 1.8.0 to 1.8.1 (#852) Bumps [github.com/smartystreets/goconvey](https://github.com/smartystreets/goconvey) from 1.8.0 to 1.8.1. - [Release notes](https://github.com/smartystreets/goconvey/releases) - [Commits](https://github.com/smartystreets/goconvey/compare/v1.8.0...v1.8.1) --- updated-dependencies: - dependency-name: github.com/smartystreets/goconvey dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index d51515c2b..1e1d70c4e 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/prometheus/client_model v0.4.0 github.com/prometheus/common v0.44.0 github.com/prometheus/exporter-toolkit v0.10.0 - github.com/smartystreets/goconvey v1.8.0 + github.com/smartystreets/goconvey v1.8.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 @@ -34,7 +34,7 @@ require ( github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect - github.com/smartystreets/assertions v1.13.1 // indirect + github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect golang.org/x/crypto v0.8.0 // indirect golang.org/x/net v0.10.0 // indirect diff --git a/go.sum b/go.sum index ec641e8e8..c6efce431 100644 --- a/go.sum +++ b/go.sum @@ -62,10 +62,10 @@ github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPH github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0ZxudX+ThRdWfU= -github.com/smartystreets/assertions v1.13.1/go.mod h1:cXr/IwVfSo/RbCSPhoAPv73p3hlSdrBH/b3SdnW/LMY= -github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w= -github.com/smartystreets/goconvey v1.8.0/go.mod h1:EdX8jtrTIj26jmjCOVNMVSIYAtgexqXKHOXW2Dx9JLg= +github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= +github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= +github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= +github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= From 6b56e2f057e43b93a56d1f1ba781605973e4688a Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Thu, 6 Jul 2023 08:33:54 +0100 Subject: [PATCH 127/228] Unpack postgres arrays for process idle times correctly (#855) Signed-off-by: Ben Kochie --- collector/pg_process_idle.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/collector/pg_process_idle.go b/collector/pg_process_idle.go index 57df723a3..8d995ab55 100644 --- a/collector/pg_process_idle.go +++ b/collector/pg_process_idle.go @@ -18,6 +18,7 @@ import ( "database/sql" "github.com/go-kit/log" + "github.com/lib/pq" "github.com/prometheus/client_golang/prometheus" ) @@ -82,22 +83,22 @@ func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch GROUP BY 1, 2, 3;`) var applicationName sql.NullString - var secondsSum sql.NullInt64 + var secondsSum sql.NullFloat64 var secondsCount sql.NullInt64 - var seconds []uint64 - var secondsBucket []uint64 + var seconds []float64 + var secondsBucket []int64 - err := row.Scan(&applicationName, &secondsSum, &secondsCount, &seconds, &secondsBucket) + err := row.Scan(&applicationName, &secondsSum, &secondsCount, pq.Array(&seconds), pq.Array(&secondsBucket)) + if err != nil { + return err + } var buckets = make(map[float64]uint64, len(seconds)) for i, second := range seconds { if i >= len(secondsBucket) { break } - buckets[float64(second)] = secondsBucket[i] - } - if err != nil { - return err + buckets[second] = uint64(secondsBucket[i]) } applicationNameLabel := "unknown" @@ -111,7 +112,7 @@ func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch } secondsSumMetric := 0.0 if secondsSum.Valid { - secondsSumMetric = float64(secondsSum.Int64) + secondsSumMetric = secondsSum.Float64 } ch <- prometheus.MustNewConstHistogram( pgProcessIdleSeconds, From a8b86cf7dad808e167892fb45a5a01c17389c55a Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Tue, 4 Jul 2023 11:14:36 +0100 Subject: [PATCH 128/228] Include all idle processes in the process idle metrics Signed-off-by: Tom Hughes --- collector/pg_process_idle.go | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/collector/pg_process_idle.go b/collector/pg_process_idle.go index 8d995ab55..c401ab56f 100644 --- a/collector/pg_process_idle.go +++ b/collector/pg_process_idle.go @@ -40,7 +40,7 @@ func NewPGProcessIdleCollector(config collectorConfig) (Collector, error) { var pgProcessIdleSeconds = prometheus.NewDesc( prometheus.BuildFQName(namespace, processIdleSubsystem, "seconds"), "Idle time of server processes", - []string{"application_name"}, + []string{"state", "application_name"}, prometheus.Labels{}, ) @@ -50,15 +50,17 @@ func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch `WITH metrics AS ( SELECT + state, application_name, SUM(EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - state_change))::bigint)::float AS process_idle_seconds_sum, COUNT(*) AS process_idle_seconds_count FROM pg_stat_activity - WHERE state = 'idle' - GROUP BY application_name + WHERE state ~ '^idle' + GROUP BY state, application_name ), buckets AS ( SELECT + state, application_name, le, SUM( @@ -70,25 +72,27 @@ func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch FROM pg_stat_activity, UNNEST(ARRAY[1, 2, 5, 15, 30, 60, 90, 120, 300]) AS le - GROUP BY application_name, le - ORDER BY application_name, le + GROUP BY state, application_name, le + ORDER BY state, application_name, le ) SELECT + state, application_name, process_idle_seconds_sum as seconds_sum, process_idle_seconds_count as seconds_count, ARRAY_AGG(le) AS seconds, ARRAY_AGG(bucket) AS seconds_bucket - FROM metrics JOIN buckets USING (application_name) - GROUP BY 1, 2, 3;`) + FROM metrics JOIN buckets USING (state, application_name) + GROUP BY 1, 2, 3, 4;`) + var state sql.NullString var applicationName sql.NullString var secondsSum sql.NullFloat64 var secondsCount sql.NullInt64 var seconds []float64 var secondsBucket []int64 - err := row.Scan(&applicationName, &secondsSum, &secondsCount, pq.Array(&seconds), pq.Array(&secondsBucket)) + err := row.Scan(&state, &applicationName, &secondsSum, &secondsCount, pq.Array(&seconds), pq.Array(&secondsBucket)) if err != nil { return err } @@ -101,6 +105,11 @@ func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch buckets[second] = uint64(secondsBucket[i]) } + stateLabel := "unknown" + if state.Valid { + stateLabel = state.String + } + applicationNameLabel := "unknown" if applicationName.Valid { applicationNameLabel = applicationName.String @@ -117,7 +126,7 @@ func (PGProcessIdleCollector) Update(ctx context.Context, instance *instance, ch ch <- prometheus.MustNewConstHistogram( pgProcessIdleSeconds, secondsCountMetric, secondsSumMetric, buckets, - applicationNameLabel, + stateLabel, applicationNameLabel, ) return nil } From 5f917ccdd97e639b1e50acdd5199e930b13c168f Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Thu, 6 Jul 2023 13:08:45 +0200 Subject: [PATCH 129/228] Improve linting (#861) * Disable unused-parameter check due to false positives on Collect() calls. * Enable misspell. * Simplify error returns. Signed-off-by: SuperQ --- .golangci.yml | 7 +++++++ collector/pg_database.go | 5 +---- collector/pg_replication_slot.go | 5 +---- collector/pg_statio_user_tables.go | 5 +---- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 7a03966aa..96487c898 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,7 @@ --- linters: enable: + - misspell - revive issues: @@ -14,3 +15,9 @@ linters-settings: exclude-functions: # Never check for logger errors. - (github.com/go-kit/log.Logger).Log + revive: + rules: + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter + - name: unused-parameter + severity: warning + disabled: true diff --git a/collector/pg_database.go b/collector/pg_database.go index 22d4918e4..d2c4b206a 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -115,10 +115,7 @@ func (c PGDatabaseCollector) Update(ctx context.Context, instance *instance, ch prometheus.GaugeValue, sizeMetric, datname, ) } - if err := rows.Err(); err != nil { - return err - } - return nil + return rows.Err() } func sliceContains(slice []string, s string) bool { diff --git a/collector/pg_replication_slot.go b/collector/pg_replication_slot.go index dec1b5da0..c625fd4d5 100644 --- a/collector/pg_replication_slot.go +++ b/collector/pg_replication_slot.go @@ -126,8 +126,5 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance prometheus.GaugeValue, isActiveValue, slotNameLabel, ) } - if err := rows.Err(); err != nil { - return err - } - return nil + return rows.Err() } diff --git a/collector/pg_statio_user_tables.go b/collector/pg_statio_user_tables.go index 89fdec532..4315fda0a 100644 --- a/collector/pg_statio_user_tables.go +++ b/collector/pg_statio_user_tables.go @@ -218,8 +218,5 @@ func (PGStatIOUserTablesCollector) Update(ctx context.Context, instance *instanc datnameLabel, schemanameLabel, relnameLabel, ) } - if err := rows.Err(); err != nil { - return err - } - return nil + return rows.Err() } From d7766801fd0c02851cb66b7b8b91f587ff5a5726 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Thu, 6 Jul 2023 14:13:24 +0200 Subject: [PATCH 130/228] Update common Prometheus files (#860) Signed-off-by: prombot Co-authored-by: Ben Kochie --- .github/workflows/golangci-lint.yml | 4 +++- .yamllint | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 100cf9329..433f71b88 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -1,3 +1,5 @@ +--- +# This action is synced from https://github.com/prometheus/prometheus name: golangci-lint on: push: @@ -27,4 +29,4 @@ jobs: - name: Lint uses: golangci/golangci-lint-action@v3.4.0 with: - version: v1.51.2 + version: v1.53.3 diff --git a/.yamllint b/.yamllint index 19552574b..955a5a627 100644 --- a/.yamllint +++ b/.yamllint @@ -20,5 +20,4 @@ rules: config/testdata/section_key_dup.bad.yml line-length: disable truthy: - ignore: | - .github/workflows/*.yml + check-keys: false From c514fcad2d3c4a9beaca7b71d18f494a1b62724c Mon Sep 17 00:00:00 2001 From: prombot Date: Thu, 6 Jul 2023 17:49:55 +0000 Subject: [PATCH 131/228] Update common Prometheus files Signed-off-by: prombot --- Makefile.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.common b/Makefile.common index 787feff08..0ce7ea461 100644 --- a/Makefile.common +++ b/Makefile.common @@ -55,7 +55,7 @@ ifneq ($(shell command -v gotestsum > /dev/null),) endif endif -PROMU_VERSION ?= 0.14.0 +PROMU_VERSION ?= 0.15.0 PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz SKIP_GOLANGCI_LINT := From 4aa8cd4996715213df9c4c51223e37c334f929c2 Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Fri, 14 Jul 2023 13:42:12 -0700 Subject: [PATCH 132/228] Gitlab collector: Database wraparound collector and test (#834) * Database wraparound collector and test --------- Signed-off-by: Felix Yuan Co-authored-by: Joe Adams --- collector/pg_database_wraparound.go | 115 +++++++++++++++++++++++ collector/pg_database_wraparound_test.go | 64 +++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 collector/pg_database_wraparound.go create mode 100644 collector/pg_database_wraparound_test.go diff --git a/collector/pg_database_wraparound.go b/collector/pg_database_wraparound.go new file mode 100644 index 000000000..d46270637 --- /dev/null +++ b/collector/pg_database_wraparound.go @@ -0,0 +1,115 @@ +// Copyright 2023 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 collector + +import ( + "context" + "database/sql" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus/client_golang/prometheus" +) + +const databaseWraparoundSubsystem = "database_wraparound" + +func init() { + registerCollector(databaseWraparoundSubsystem, defaultDisabled, NewPGDatabaseWraparoundCollector) +} + +type PGDatabaseWraparoundCollector struct { + log log.Logger +} + +func NewPGDatabaseWraparoundCollector(config collectorConfig) (Collector, error) { + return &PGDatabaseWraparoundCollector{log: config.logger}, nil +} + +var ( + databaseWraparoundAgeDatfrozenxid = prometheus.NewDesc( + prometheus.BuildFQName(namespace, databaseWraparoundSubsystem, "age_datfrozenxid_seconds"), + "Age of the oldest transaction ID that has not been frozen.", + []string{"datname"}, + prometheus.Labels{}, + ) + databaseWraparoundAgeDatminmxid = prometheus.NewDesc( + prometheus.BuildFQName(namespace, databaseWraparoundSubsystem, "age_datminmxid_seconds"), + "Age of the oldest multi-transaction ID that has been replaced with a transaction ID.", + []string{"datname"}, + prometheus.Labels{}, + ) + + databaseWraparoundQuery = ` + SELECT + datname, + age(d.datfrozenxid) as age_datfrozenxid, + mxid_age(d.datminmxid) as age_datminmxid + FROM + pg_catalog.pg_database d + WHERE + d.datallowconn + ` +) + +func (c *PGDatabaseWraparoundCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + rows, err := db.QueryContext(ctx, + databaseWraparoundQuery) + + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var datname sql.NullString + var ageDatfrozenxid, ageDatminmxid sql.NullFloat64 + + if err := rows.Scan(&datname, &ageDatfrozenxid, &ageDatminmxid); err != nil { + return err + } + + if !datname.Valid { + level.Debug(c.log).Log("msg", "Skipping database with NULL name") + continue + } + if !ageDatfrozenxid.Valid { + level.Debug(c.log).Log("msg", "Skipping stat emission with NULL age_datfrozenxid") + continue + } + if !ageDatminmxid.Valid { + level.Debug(c.log).Log("msg", "Skipping stat emission with NULL age_datminmxid") + continue + } + + ageDatfrozenxidMetric := ageDatfrozenxid.Float64 + + ch <- prometheus.MustNewConstMetric( + databaseWraparoundAgeDatfrozenxid, + prometheus.GaugeValue, + ageDatfrozenxidMetric, datname.String, + ) + + ageDatminmxidMetric := ageDatminmxid.Float64 + ch <- prometheus.MustNewConstMetric( + databaseWraparoundAgeDatminmxid, + prometheus.GaugeValue, + ageDatminmxidMetric, datname.String, + ) + } + if err := rows.Err(); err != nil { + return err + } + return nil +} diff --git a/collector/pg_database_wraparound_test.go b/collector/pg_database_wraparound_test.go new file mode 100644 index 000000000..d0a74c362 --- /dev/null +++ b/collector/pg_database_wraparound_test.go @@ -0,0 +1,64 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGDatabaseWraparoundCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + inst := &instance{db: db} + columns := []string{ + "datname", + "age_datfrozenxid", + "age_datminmxid", + } + rows := sqlmock.NewRows(columns). + AddRow("newreddit", 87126426, 0) + + mock.ExpectQuery(sanitizeQuery(databaseWraparoundQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGDatabaseWraparoundCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGDatabaseWraparoundCollector.Update: %s", err) + } + }() + expected := []MetricResult{ + {labels: labelMap{"datname": "newreddit"}, value: 87126426, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"datname": "newreddit"}, value: 0, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From 12c12cf368cd9dabc305336bbec11f2f9d61ca93 Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Wed, 19 Jul 2023 14:24:08 -0700 Subject: [PATCH 133/228] Add a logger to stat_database collector to get better handle on error (also clean up some metric validity checks) Signed-off-by: Felix Yuan --- collector/pg_stat_database.go | 246 ++++++++++++++--------------- collector/pg_stat_database_test.go | 165 ++++++++++++------- 2 files changed, 225 insertions(+), 186 deletions(-) diff --git a/collector/pg_stat_database.go b/collector/pg_stat_database.go index 8a882f891..382ff7825 100644 --- a/collector/pg_stat_database.go +++ b/collector/pg_stat_database.go @@ -17,6 +17,8 @@ import ( "context" "database/sql" + "github.com/go-kit/log" + "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) @@ -26,10 +28,12 @@ func init() { registerCollector(statDatabaseSubsystem, defaultEnabled, NewPGStatDatabaseCollector) } -type PGStatDatabaseCollector struct{} +type PGStatDatabaseCollector struct { + log log.Logger +} func NewPGStatDatabaseCollector(config collectorConfig) (Collector, error) { - return &PGStatDatabaseCollector{}, nil + return &PGStatDatabaseCollector{log: config.logger}, nil } var ( @@ -228,7 +232,7 @@ var ( ` ) -func (PGStatDatabaseCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { +func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { db := instance.getDB() rows, err := db.QueryContext(ctx, statDatabaseQuery, @@ -267,217 +271,203 @@ func (PGStatDatabaseCollector) Update(ctx context.Context, instance *instance, c if err != nil { return err } - datidLabel := "unknown" - if datid.Valid { - datidLabel = datid.String + + if !datid.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no datid") + continue } - datnameLabel := "unknown" - if datname.Valid { - datnameLabel = datname.String + if !datname.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no datname") + continue } - - numBackendsMetric := 0.0 - if numBackends.Valid { - numBackendsMetric = numBackends.Float64 + if !numBackends.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no numbackends") + continue + } + if !xactCommit.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no xact_commit") + continue + } + if !xactRollback.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no xact_rollback") + continue + } + if !blksRead.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blks_read") + continue + } + if !blksHit.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blks_hit") + continue + } + if !tupReturned.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no tup_returned") + continue + } + if !tupFetched.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no tup_fetched") + continue + } + if !tupInserted.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no tup_inserted") + continue + } + if !tupUpdated.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no tup_updated") + continue + } + if !tupDeleted.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no tup_deleted") + continue + } + if !conflicts.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no conflicts") + continue + } + if !tempFiles.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no temp_files") + continue + } + if !tempBytes.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no temp_bytes") + continue + } + if !deadlocks.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no deadlocks") + continue + } + if !blkReadTime.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blk_read_time") + continue + } + if !blkWriteTime.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blk_write_time") + continue + } + if !statsReset.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no stats_reset") + continue } + + labels := []string{datid.String, datname.String} + ch <- prometheus.MustNewConstMetric( statDatabaseNumbackends, prometheus.GaugeValue, - numBackendsMetric, - datidLabel, - datnameLabel, + numBackends.Float64, + labels..., ) - xactCommitMetric := 0.0 - if xactCommit.Valid { - xactCommitMetric = xactCommit.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseXactCommit, prometheus.CounterValue, - xactCommitMetric, - datidLabel, - datnameLabel, + xactCommit.Float64, + labels..., ) - xactRollbackMetric := 0.0 - if xactRollback.Valid { - xactRollbackMetric = xactRollback.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseXactRollback, prometheus.CounterValue, - xactRollbackMetric, - datidLabel, - datnameLabel, + xactRollback.Float64, + labels..., ) - blksReadMetric := 0.0 - if blksRead.Valid { - blksReadMetric = blksRead.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseBlksRead, prometheus.CounterValue, - blksReadMetric, - datidLabel, - datnameLabel, + blksRead.Float64, + labels..., ) - blksHitMetric := 0.0 - if blksHit.Valid { - blksHitMetric = blksHit.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseBlksHit, prometheus.CounterValue, - blksHitMetric, - datidLabel, - datnameLabel, + blksHit.Float64, + labels..., ) - tupReturnedMetric := 0.0 - if tupReturned.Valid { - tupReturnedMetric = tupReturned.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseTupReturned, prometheus.CounterValue, - tupReturnedMetric, - datidLabel, - datnameLabel, + tupReturned.Float64, + labels..., ) - tupFetchedMetric := 0.0 - if tupFetched.Valid { - tupFetchedMetric = tupFetched.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseTupFetched, prometheus.CounterValue, - tupFetchedMetric, - datidLabel, - datnameLabel, + tupFetched.Float64, + labels..., ) - tupInsertedMetric := 0.0 - if tupInserted.Valid { - tupInsertedMetric = tupInserted.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseTupInserted, prometheus.CounterValue, - tupInsertedMetric, - datidLabel, - datnameLabel, + tupInserted.Float64, + labels..., ) - tupUpdatedMetric := 0.0 - if tupUpdated.Valid { - tupUpdatedMetric = tupUpdated.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseTupUpdated, prometheus.CounterValue, - tupUpdatedMetric, - datidLabel, - datnameLabel, + tupUpdated.Float64, + labels..., ) - tupDeletedMetric := 0.0 - if tupDeleted.Valid { - tupDeletedMetric = tupDeleted.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseTupDeleted, prometheus.CounterValue, - tupDeletedMetric, - datidLabel, - datnameLabel, + tupDeleted.Float64, + labels..., ) - conflictsMetric := 0.0 - if conflicts.Valid { - conflictsMetric = conflicts.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseConflicts, prometheus.CounterValue, - conflictsMetric, - datidLabel, - datnameLabel, + conflicts.Float64, + labels..., ) - tempFilesMetric := 0.0 - if tempFiles.Valid { - tempFilesMetric = tempFiles.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseTempFiles, prometheus.CounterValue, - tempFilesMetric, - datidLabel, - datnameLabel, + tempFiles.Float64, + labels..., ) - tempBytesMetric := 0.0 - if tempBytes.Valid { - tempBytesMetric = tempBytes.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseTempBytes, prometheus.CounterValue, - tempBytesMetric, - datidLabel, - datnameLabel, + tempBytes.Float64, + labels..., ) - deadlocksMetric := 0.0 - if deadlocks.Valid { - deadlocksMetric = deadlocks.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseDeadlocks, prometheus.CounterValue, - deadlocksMetric, - datidLabel, - datnameLabel, + deadlocks.Float64, + labels..., ) - blkReadTimeMetric := 0.0 - if blkReadTime.Valid { - blkReadTimeMetric = blkReadTime.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseBlkReadTime, prometheus.CounterValue, - blkReadTimeMetric, - datidLabel, - datnameLabel, + blkReadTime.Float64, + labels..., ) - blkWriteTimeMetric := 0.0 - if blkWriteTime.Valid { - blkWriteTimeMetric = blkWriteTime.Float64 - } ch <- prometheus.MustNewConstMetric( statDatabaseBlkWriteTime, prometheus.CounterValue, - blkWriteTimeMetric, - datidLabel, - datnameLabel, + blkWriteTime.Float64, + labels..., ) - statsResetMetric := 0.0 - if statsReset.Valid { - statsResetMetric = float64(statsReset.Time.Unix()) - } ch <- prometheus.MustNewConstMetric( statDatabaseStatsReset, prometheus.CounterValue, - statsResetMetric, - datidLabel, - datnameLabel, + float64(statsReset.Time.Unix()), + labels..., ) } return nil diff --git a/collector/pg_stat_database_test.go b/collector/pg_stat_database_test.go index 1fe92eedc..70c73eb5b 100644 --- a/collector/pg_stat_database_test.go +++ b/collector/pg_stat_database_test.go @@ -18,6 +18,7 @@ import ( "time" "github.com/DATA-DOG/go-sqlmock" + "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" "github.com/smartystreets/goconvey/convey" @@ -86,7 +87,9 @@ func TestPGStatDatabaseCollector(t *testing.T) { ch := make(chan prometheus.Metric) go func() { defer close(ch) - c := PGStatDatabaseCollector{} + c := PGStatDatabaseCollector{ + log: log.With(log.NewNopLogger(), "collector", "pg_stat_database"), + } if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGStatDatabaseCollector.Update: %s", err) @@ -131,6 +134,10 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { } defer db.Close() + srT, err := time.Parse("2006-01-02 15:04:05.00000-07", "2023-05-25 17:10:42.81132-07") + if err != nil { + t.Fatalf("Error parsing time: %s", err) + } inst := &instance{db: db} columns := []string{ @@ -158,31 +165,52 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { rows := sqlmock.NewRows(columns). AddRow( nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - ) + "postgres", + 354, + 4945, + 289097744, + 1242257, + int64(3275602074), + 89320867, + 450139, + 2034563757, + 0, + int64(2725688749), + 23, + 52, + 74, + 925, + 16, + 823, + srT). + AddRow( + "pid", + "postgres", + 354, + 4945, + 289097744, + 1242257, + int64(3275602074), + 89320867, + 450139, + 2034563757, + 0, + int64(2725688749), + 23, + 52, + 74, + 925, + 16, + 823, + srT) mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { defer close(ch) - c := PGStatDatabaseCollector{} + c := PGStatDatabaseCollector{ + log: log.With(log.NewNopLogger(), "collector", "pg_stat_database"), + } if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGStatDatabaseCollector.Update: %s", err) @@ -190,23 +218,23 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { }() expected := []MetricResult{ - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_GAUGE, value: 354}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 4945}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 289097744}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1242257}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 3275602074}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 89320867}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 450139}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 2034563757}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 2725688749}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 23}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 52}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 74}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, } convey.Convey("Metrics comparison", t, func() { @@ -296,14 +324,35 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { nil, nil, nil, - ) - + ). + AddRow( + "pid", + "postgres", + 355, + 4946, + 289097745, + 1242258, + int64(3275602075), + 89320868, + 450140, + 2034563758, + 1, + int64(2725688750), + 24, + 53, + 75, + 926, + 17, + 824, + srT) mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { defer close(ch) - c := PGStatDatabaseCollector{} + c := PGStatDatabaseCollector{ + log: log.With(log.NewNopLogger(), "collector", "pg_stat_database"), + } if err := c.Update(context.Background(), inst, ch); err != nil { t.Errorf("Error calling PGStatDatabaseCollector.Update: %s", err) @@ -328,23 +377,23 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, - {labels: labelMap{"datid": "unknown", "datname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_GAUGE, value: 355}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 4946}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 289097745}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1242258}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 3275602075}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 89320868}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 450140}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 2034563758}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 2725688750}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 24}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 53}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 75}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 926}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 17}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 824}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, } convey.Convey("Metrics comparison", t, func() { From 24a45f2fe3856671449e83479ea7a511f27b3a20 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Fri, 21 Jul 2023 14:20:19 -0400 Subject: [PATCH 134/228] Update changelog for release 0.13.2 (#872) Signed-off-by: Joe Adams --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 318e3648e..f9ab3cb24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.13.2 / 2023-07-21 + +* [BUGFIX] Fix type issues on pg_postmaster metrics #828 +* [BUGFIX] Fix pg_replication collector instantiation #854 +* [BUGFIX] Fix pg_process_idle metrics #855 + ## 0.13.1 / 2023-06-27 * [BUGFIX] Make collectors not fail on null values #823 From dc3e813f430602dddeb15146a9960960c61a7ffd Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Fri, 21 Jul 2023 11:41:25 -0700 Subject: [PATCH 135/228] Gitlab Collector: Autovacuum collector and test (#840) * Autovacuum collector and test Signed-off-by: Felix Yuan * Update collector/pg_stat_activity_autovacuum.go Co-authored-by: Joe Adams Signed-off-by: Felix Yuan * Update collector/pg_stat_activity_autovacuum.go Co-authored-by: Joe Adams Signed-off-by: Felix Yuan * Use timestamp seconds Signed-off-by: Felix Yuan * query formating Signed-off-by: Felix Yuan * SQL format Signed-off-by: Felix Yuan * Loosen autovacuum query Signed-off-by: Felix Yuan --------- Signed-off-by: Felix Yuan Co-authored-by: Joe Adams --- collector/pg_stat_activity_autovacuum.go | 84 +++++++++++++++++++ collector/pg_stat_activity_autovacuum_test.go | 62 ++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 collector/pg_stat_activity_autovacuum.go create mode 100644 collector/pg_stat_activity_autovacuum_test.go diff --git a/collector/pg_stat_activity_autovacuum.go b/collector/pg_stat_activity_autovacuum.go new file mode 100644 index 000000000..5e2d2d2ca --- /dev/null +++ b/collector/pg_stat_activity_autovacuum.go @@ -0,0 +1,84 @@ +// Copyright 2023 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 collector + +import ( + "context" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +const statActivityAutovacuumSubsystem = "stat_activity_autovacuum" + +func init() { + registerCollector(statActivityAutovacuumSubsystem, defaultDisabled, NewPGStatActivityAutovacuumCollector) +} + +type PGStatActivityAutovacuumCollector struct { + log log.Logger +} + +func NewPGStatActivityAutovacuumCollector(config collectorConfig) (Collector, error) { + return &PGStatActivityAutovacuumCollector{log: config.logger}, nil +} + +var ( + statActivityAutovacuumAgeInSeconds = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statActivityAutovacuumSubsystem, "timestamp_seconds"), + "Start timestamp of the vacuum process in seconds", + []string{"relname"}, + prometheus.Labels{}, + ) + + statActivityAutovacuumQuery = ` + SELECT + SPLIT_PART(query, '.', 2) AS relname, + EXTRACT(xact_start) AS timestamp_seconds + FROM + pg_catalog.pg_stat_activity + WHERE + query LIKE 'autovacuum:%' + ` +) + +func (PGStatActivityAutovacuumCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + rows, err := db.QueryContext(ctx, + statActivityAutovacuumQuery) + + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var relname string + var ageInSeconds float64 + + if err := rows.Scan(&relname, &ageInSeconds); err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric( + statActivityAutovacuumAgeInSeconds, + prometheus.GaugeValue, + ageInSeconds, relname, + ) + } + if err := rows.Err(); err != nil { + return err + } + return nil +} diff --git a/collector/pg_stat_activity_autovacuum_test.go b/collector/pg_stat_activity_autovacuum_test.go new file mode 100644 index 000000000..a6fcdbcad --- /dev/null +++ b/collector/pg_stat_activity_autovacuum_test.go @@ -0,0 +1,62 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGStatActivityAutovacuumCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + inst := &instance{db: db} + columns := []string{ + "relname", + "timestamp_seconds", + } + rows := sqlmock.NewRows(columns). + AddRow("test", 3600) + + mock.ExpectQuery(sanitizeQuery(statActivityAutovacuumQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatActivityAutovacuumCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatActivityAutovacuumCollector.Update: %s", err) + } + }() + expected := []MetricResult{ + {labels: labelMap{"relname": "test"}, value: 3600, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From 2d7e15275147ce7dfb7b7dc6f959d60e106c11a1 Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Fri, 21 Jul 2023 11:42:08 -0700 Subject: [PATCH 136/228] Gitlab Collector: Wal Receiver Collector and Test (#844) * Wal Receiver Collector and Test Signed-off-by: Felix Yuan * Add more escapes Signed-off-by: Felix Yuan * Corrections to wal_receiver Signed-off-by: Felix Yuan * Continue on null labels Signed-off-by: Felix Yuan * Skip nulls and log a message Signed-off-by: Felix Yuan * Redundant breaks Signed-off-by: Felix Yuan * Fix up walreceiver Signed-off-by: Felix Yuan * Remove extra label Signed-off-by: Felix Yuan * Update collector/pg_stat_walreceiver.go Co-authored-by: Ben Kochie Signed-off-by: Felix Yuan * Clean up the extra assignments Signed-off-by: Felix Yuan * Update collector/pg_stat_walreceiver.go Co-authored-by: Joe Adams Signed-off-by: Felix Yuan --------- Signed-off-by: Felix Yuan Co-authored-by: Ben Kochie Co-authored-by: Joe Adams --- collector/collector_test.go | 1 + collector/pg_stat_walreceiver.go | 269 ++++++++++++++++++++++++++ collector/pg_stat_walreceiver_test.go | 186 ++++++++++++++++++ 3 files changed, 456 insertions(+) create mode 100644 collector/pg_stat_walreceiver.go create mode 100644 collector/pg_stat_walreceiver_test.go diff --git a/collector/collector_test.go b/collector/collector_test.go index 00c21ed23..18101f00e 100644 --- a/collector/collector_test.go +++ b/collector/collector_test.go @@ -49,6 +49,7 @@ func readMetric(m prometheus.Metric) MetricResult { func sanitizeQuery(q string) string { q = strings.Join(strings.Fields(q), " ") q = strings.Replace(q, "(", "\\(", -1) + q = strings.Replace(q, "?", "\\?", -1) q = strings.Replace(q, ")", "\\)", -1) q = strings.Replace(q, "[", "\\[", -1) q = strings.Replace(q, "]", "\\]", -1) diff --git a/collector/pg_stat_walreceiver.go b/collector/pg_stat_walreceiver.go new file mode 100644 index 000000000..3134c025b --- /dev/null +++ b/collector/pg_stat_walreceiver.go @@ -0,0 +1,269 @@ +// Copyright 2023 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 collector + +import ( + "context" + "database/sql" + "fmt" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus/client_golang/prometheus" +) + +func init() { + registerCollector(statWalReceiverSubsystem, defaultDisabled, NewPGStatWalReceiverCollector) +} + +type PGStatWalReceiverCollector struct { + log log.Logger +} + +const statWalReceiverSubsystem = "stat_wal_receiver" + +func NewPGStatWalReceiverCollector(config collectorConfig) (Collector, error) { + return &PGStatWalReceiverCollector{log: config.logger}, nil +} + +var ( + labelCats = []string{"upstream_host", "slot_name", "status"} + statWalReceiverReceiveStartLsn = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statWalReceiverSubsystem, "receive_start_lsn"), + "First write-ahead log location used when WAL receiver is started represented as a decimal", + labelCats, + prometheus.Labels{}, + ) + statWalReceiverReceiveStartTli = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statWalReceiverSubsystem, "receive_start_tli"), + "First timeline number used when WAL receiver is started", + labelCats, + prometheus.Labels{}, + ) + statWalReceiverFlushedLSN = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statWalReceiverSubsystem, "flushed_lsn"), + "Last write-ahead log location already received and flushed to disk, the initial value of this field being the first log location used when WAL receiver is started represented as a decimal", + labelCats, + prometheus.Labels{}, + ) + statWalReceiverReceivedTli = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statWalReceiverSubsystem, "received_tli"), + "Timeline number of last write-ahead log location received and flushed to disk", + labelCats, + prometheus.Labels{}, + ) + statWalReceiverLastMsgSendTime = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statWalReceiverSubsystem, "last_msg_send_time"), + "Send time of last message received from origin WAL sender", + labelCats, + prometheus.Labels{}, + ) + statWalReceiverLastMsgReceiptTime = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statWalReceiverSubsystem, "last_msg_receipt_time"), + "Send time of last message received from origin WAL sender", + labelCats, + prometheus.Labels{}, + ) + statWalReceiverLatestEndLsn = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statWalReceiverSubsystem, "latest_end_lsn"), + "Last write-ahead log location reported to origin WAL sender as integer", + labelCats, + prometheus.Labels{}, + ) + statWalReceiverLatestEndTime = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statWalReceiverSubsystem, "latest_end_time"), + "Time of last write-ahead log location reported to origin WAL sender", + labelCats, + prometheus.Labels{}, + ) + statWalReceiverUpstreamNode = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statWalReceiverSubsystem, "upstream_node"), + "Node ID of the upstream node", + labelCats, + prometheus.Labels{}, + ) + + pgStatWalColumnQuery = ` + SELECT + column_name + FROM information_schema.columns + WHERE + table_name = 'pg_stat_wal_receiver' and + column_name = 'flushed_lsn' + ` + + pgStatWalReceiverQueryTemplate = ` + SELECT + trim(both '''' from substring(conninfo from 'host=([^ ]*)')) as upstream_host, + slot_name, + status, + (receive_start_lsn- '0/0') % (2^52)::bigint as receive_start_lsn, + %s +receive_start_tli, + received_tli, + extract(epoch from last_msg_send_time) as last_msg_send_time, + extract(epoch from last_msg_receipt_time) as last_msg_receipt_time, + (latest_end_lsn - '0/0') % (2^52)::bigint as latest_end_lsn, + extract(epoch from latest_end_time) as latest_end_time, + substring(slot_name from 'repmgr_slot_([0-9]*)') as upstream_node + FROM pg_catalog.pg_stat_wal_receiver + ` +) + +func (c *PGStatWalReceiverCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + hasFlushedLSNRows, err := db.QueryContext(ctx, pgStatWalColumnQuery) + if err != nil { + return err + } + + defer hasFlushedLSNRows.Close() + hasFlushedLSN := hasFlushedLSNRows.Next() + var query string + if hasFlushedLSN { + query = fmt.Sprintf(pgStatWalReceiverQueryTemplate, "(flushed_lsn - '0/0') % (2^52)::bigint as flushed_lsn,\n") + } else { + query = fmt.Sprintf(pgStatWalReceiverQueryTemplate, "") + } + rows, err := db.QueryContext(ctx, query) + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var upstreamHost, slotName, status sql.NullString + var receiveStartLsn, receiveStartTli, flushedLsn, receivedTli, latestEndLsn, upstreamNode sql.NullInt64 + var lastMsgSendTime, lastMsgReceiptTime, latestEndTime sql.NullFloat64 + + if hasFlushedLSN { + if err := rows.Scan(&upstreamHost, &slotName, &status, &receiveStartLsn, &receiveStartTli, &flushedLsn, &receivedTli, &lastMsgSendTime, &lastMsgReceiptTime, &latestEndLsn, &latestEndTime, &upstreamNode); err != nil { + return err + } + } else { + if err := rows.Scan(&upstreamHost, &slotName, &status, &receiveStartLsn, &receiveStartTli, &receivedTli, &lastMsgSendTime, &lastMsgReceiptTime, &latestEndLsn, &latestEndTime, &upstreamNode); err != nil { + return err + } + } + if !upstreamHost.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because upstream host is null") + continue + } + + if !slotName.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because slotname host is null") + continue + } + + if !status.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because status is null") + continue + } + labels := []string{upstreamHost.String, slotName.String, status.String} + + if !receiveStartLsn.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because receive_start_lsn is null") + continue + } + if !receiveStartTli.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because receive_start_tli is null") + continue + } + if hasFlushedLSN && !flushedLsn.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because flushed_lsn is null") + continue + } + if !receivedTli.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because received_tli is null") + continue + } + if !lastMsgSendTime.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because last_msg_send_time is null") + continue + } + if !lastMsgReceiptTime.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because last_msg_receipt_time is null") + continue + } + if !latestEndLsn.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because latest_end_lsn is null") + continue + } + if !latestEndTime.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because latest_end_time is null") + continue + } + if !upstreamNode.Valid { + level.Debug(c.log).Log("msg", "Skipping wal receiver stats because upstream_node is null") + continue + } + ch <- prometheus.MustNewConstMetric( + statWalReceiverReceiveStartLsn, + prometheus.CounterValue, + float64(receiveStartLsn.Int64), + labels...) + + ch <- prometheus.MustNewConstMetric( + statWalReceiverReceiveStartTli, + prometheus.GaugeValue, + float64(receiveStartTli.Int64), + labels...) + + if hasFlushedLSN { + ch <- prometheus.MustNewConstMetric( + statWalReceiverFlushedLSN, + prometheus.CounterValue, + float64(flushedLsn.Int64), + labels...) + } + + ch <- prometheus.MustNewConstMetric( + statWalReceiverReceivedTli, + prometheus.GaugeValue, + float64(receivedTli.Int64), + labels...) + + ch <- prometheus.MustNewConstMetric( + statWalReceiverLastMsgSendTime, + prometheus.CounterValue, + float64(lastMsgSendTime.Float64), + labels...) + + ch <- prometheus.MustNewConstMetric( + statWalReceiverLastMsgReceiptTime, + prometheus.CounterValue, + float64(lastMsgReceiptTime.Float64), + labels...) + + ch <- prometheus.MustNewConstMetric( + statWalReceiverLatestEndLsn, + prometheus.CounterValue, + float64(latestEndLsn.Int64), + labels...) + + ch <- prometheus.MustNewConstMetric( + statWalReceiverLatestEndTime, + prometheus.CounterValue, + latestEndTime.Float64, + labels...) + + ch <- prometheus.MustNewConstMetric( + statWalReceiverUpstreamNode, + prometheus.GaugeValue, + float64(upstreamNode.Int64), + labels...) + } + if err := rows.Err(); err != nil { + return err + } + return nil +} diff --git a/collector/pg_stat_walreceiver_test.go b/collector/pg_stat_walreceiver_test.go new file mode 100644 index 000000000..3e2418b25 --- /dev/null +++ b/collector/pg_stat_walreceiver_test.go @@ -0,0 +1,186 @@ +// Copyright 2023 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 collector + +import ( + "context" + "fmt" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +var queryWithFlushedLSN = fmt.Sprintf(pgStatWalReceiverQueryTemplate, "(flushed_lsn - '0/0') % (2^52)::bigint as flushed_lsn,\n") +var queryWithNoFlushedLSN = fmt.Sprintf(pgStatWalReceiverQueryTemplate, "") + +func TestPGStatWalReceiverCollectorWithFlushedLSN(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + infoSchemaColumns := []string{ + "column_name", + } + + infoSchemaRows := sqlmock.NewRows(infoSchemaColumns). + AddRow( + "flushed_lsn", + ) + + mock.ExpectQuery(sanitizeQuery(pgStatWalColumnQuery)).WillReturnRows(infoSchemaRows) + + columns := []string{ + "upstream_host", + "slot_name", + "status", + "receive_start_lsn", + "receive_start_tli", + "flushed_lsn", + "received_tli", + "last_msg_send_time", + "last_msg_receipt_time", + "latest_end_lsn", + "latest_end_time", + "upstream_node", + } + rows := sqlmock.NewRows(columns). + AddRow( + "foo", + "bar", + "stopping", + 1200668684563608, + 1687321285, + 1200668684563609, + 1687321280, + 1687321275, + 1687321276, + 1200668684563610, + 1687321277, + 5, + ) + + mock.ExpectQuery(sanitizeQuery(queryWithFlushedLSN)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatWalReceiverCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PgStatWalReceiverCollector.Update: %s", err) + } + }() + expected := []MetricResult{ + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "stopping"}, value: 1200668684563608, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "stopping"}, value: 1687321285, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "stopping"}, value: 1200668684563609, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "stopping"}, value: 1687321280, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "stopping"}, value: 1687321275, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "stopping"}, value: 1687321276, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "stopping"}, value: 1200668684563610, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "stopping"}, value: 1687321277, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "stopping"}, value: 5, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } + +} + +func TestPGStatWalReceiverCollectorWithNoFlushedLSN(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + infoSchemaColumns := []string{ + "column_name", + } + + infoSchemaRows := sqlmock.NewRows(infoSchemaColumns) + + mock.ExpectQuery(sanitizeQuery(pgStatWalColumnQuery)).WillReturnRows(infoSchemaRows) + + columns := []string{ + "upstream_host", + "slot_name", + "status", + "receive_start_lsn", + "receive_start_tli", + "received_tli", + "last_msg_send_time", + "last_msg_receipt_time", + "latest_end_lsn", + "latest_end_time", + "upstream_node", + } + rows := sqlmock.NewRows(columns). + AddRow( + "foo", + "bar", + "starting", + 1200668684563608, + 1687321285, + 1687321280, + 1687321275, + 1687321276, + 1200668684563610, + 1687321277, + 5, + ) + mock.ExpectQuery(sanitizeQuery(queryWithNoFlushedLSN)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatWalReceiverCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PgStatWalReceiverCollector.Update: %s", err) + } + }() + expected := []MetricResult{ + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "starting"}, value: 1200668684563608, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "starting"}, value: 1687321285, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "starting"}, value: 1687321280, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "starting"}, value: 1687321275, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "starting"}, value: 1687321276, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "starting"}, value: 1200668684563610, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "starting"}, value: 1687321277, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"upstream_host": "foo", "slot_name": "bar", "status": "starting"}, value: 5, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } + +} From 74800f483a9bdcbd7efe0c4baf0f8ac1820f21db Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Fri, 21 Jul 2023 11:42:43 -0700 Subject: [PATCH 137/228] Gitlab collector: Xlog location collector and test (#849) * Xlog location collector and test Signed-off-by: Felix Yuan * Add more escapes Signed-off-by: Felix Yuan * Change to Gauge Signed-off-by: Felix Yuan --------- Signed-off-by: Felix Yuan --- collector/pg_xlog_location.go | 80 ++++++++++++++++++++++++++++++ collector/pg_xlog_location_test.go | 61 +++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 collector/pg_xlog_location.go create mode 100644 collector/pg_xlog_location_test.go diff --git a/collector/pg_xlog_location.go b/collector/pg_xlog_location.go new file mode 100644 index 000000000..92ac44acb --- /dev/null +++ b/collector/pg_xlog_location.go @@ -0,0 +1,80 @@ +// Copyright 2023 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 collector + +import ( + "context" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +const xlogLocationSubsystem = "xlog_location" + +func init() { + registerCollector(xlogLocationSubsystem, defaultDisabled, NewPGXlogLocationCollector) +} + +type PGXlogLocationCollector struct { + log log.Logger +} + +func NewPGXlogLocationCollector(config collectorConfig) (Collector, error) { + return &PGXlogLocationCollector{log: config.logger}, nil +} + +var ( + xlogLocationBytes = prometheus.NewDesc( + prometheus.BuildFQName(namespace, xlogLocationSubsystem, "bytes"), + "Postgres LSN (log sequence number) being generated on primary or replayed on replica (truncated to low 52 bits)", + []string{}, + prometheus.Labels{}, + ) + + xlogLocationQuery = ` + SELECT CASE + WHEN pg_is_in_recovery() THEN (pg_last_xlog_replay_location() - '0/0') % (2^52)::bigint + ELSE (pg_current_xlog_location() - '0/0') % (2^52)::bigint + END AS bytes + ` +) + +func (PGXlogLocationCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + rows, err := db.QueryContext(ctx, + xlogLocationQuery) + + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var bytes float64 + + if err := rows.Scan(&bytes); err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric( + xlogLocationBytes, + prometheus.GaugeValue, + bytes, + ) + } + if err := rows.Err(); err != nil { + return err + } + return nil +} diff --git a/collector/pg_xlog_location_test.go b/collector/pg_xlog_location_test.go new file mode 100644 index 000000000..561a7df94 --- /dev/null +++ b/collector/pg_xlog_location_test.go @@ -0,0 +1,61 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGXlogLocationCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + inst := &instance{db: db} + columns := []string{ + "bytes", + } + rows := sqlmock.NewRows(columns). + AddRow(53401) + + mock.ExpectQuery(sanitizeQuery(xlogLocationQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGXlogLocationCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGXlogLocationCollector.Update: %s", err) + } + }() + expected := []MetricResult{ + {labels: labelMap{}, value: 53401, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From f9277b04b7f614a03a4ca70194abe2045f17c36a Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Tue, 25 Jul 2023 16:20:37 +0200 Subject: [PATCH 138/228] Handle new pg_stat_statements column names (#874) Update pg_stat_statements collector to handle the new column names in PostgreSQL 13. Fixes: https://github.com/prometheus-community/postgres_exporter/issues/502 Signed-off-by: SuperQ --- collector/pg_stat_statements.go | 30 +++++++++++++++-- collector/pg_stat_statements_test.go | 50 ++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/collector/pg_stat_statements.go b/collector/pg_stat_statements.go index bbfee1a2b..e28c1c595 100644 --- a/collector/pg_stat_statements.go +++ b/collector/pg_stat_statements.go @@ -17,6 +17,7 @@ import ( "context" "database/sql" + "github.com/blang/semver/v4" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -90,12 +91,37 @@ var ( ) ORDER BY seconds_total DESC LIMIT 100;` + + pgStatStatementsNewQuery = `SELECT + pg_get_userbyid(userid) as user, + pg_database.datname, + pg_stat_statements.queryid, + pg_stat_statements.calls as calls_total, + pg_stat_statements.total_exec_time / 1000.0 as seconds_total, + pg_stat_statements.rows as rows_total, + pg_stat_statements.blk_read_time / 1000.0 as block_read_seconds_total, + pg_stat_statements.blk_write_time / 1000.0 as block_write_seconds_total + FROM pg_stat_statements + JOIN pg_database + ON pg_database.oid = pg_stat_statements.dbid + WHERE + total_time > ( + SELECT percentile_cont(0.1) + WITHIN GROUP (ORDER BY total_time) + FROM pg_stat_statements + ) + ORDER BY seconds_total DESC + LIMIT 100;` ) func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + query := pgStatStatementsQuery + if instance.version.GE(semver.MustParse("13.0.0")) { + query = pgStatStatementsNewQuery + } + db := instance.getDB() - rows, err := db.QueryContext(ctx, - pgStatStatementsQuery) + rows, err := db.QueryContext(ctx, query) if err != nil { return err diff --git a/collector/pg_stat_statements_test.go b/collector/pg_stat_statements_test.go index c4f89a60f..08aba34c2 100644 --- a/collector/pg_stat_statements_test.go +++ b/collector/pg_stat_statements_test.go @@ -17,6 +17,7 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + "github.com/blang/semver/v4" "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" "github.com/smartystreets/goconvey/convey" @@ -29,7 +30,7 @@ func TestPGStateStatementsCollector(t *testing.T) { } defer db.Close() - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("12.0.0")} columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} rows := sqlmock.NewRows(columns). @@ -72,12 +73,12 @@ func TestPGStateStatementsCollectorNull(t *testing.T) { } defer db.Close() - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("13.3.7")} columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} rows := sqlmock.NewRows(columns). AddRow(nil, nil, nil, nil, nil, nil, nil, nil) - mock.ExpectQuery(sanitizeQuery(pgStatStatementsQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(pgStatStatementsNewQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -107,3 +108,46 @@ func TestPGStateStatementsCollectorNull(t *testing.T) { t.Errorf("there were unfulfilled exceptions: %s", err) } } + +func TestPGStateStatementsCollectorNewPG(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db, version: semver.MustParse("13.3.7")} + + columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} + rows := sqlmock.NewRows(columns). + AddRow("postgres", "postgres", 1500, 5, 0.4, 100, 0.1, 0.2) + mock.ExpectQuery(sanitizeQuery(pgStatStatementsNewQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatStatementsCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatStatementsCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 5}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.4}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 100}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.1}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.2}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From 716ac23f202f664845d04c0d7b07000feae19c59 Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Tue, 25 Jul 2023 22:36:51 +0200 Subject: [PATCH 139/228] Fixup new pg_stats_statements query (#876) Fix all renames of `total_time` to `total_exec_time`. Fixes: https://github.com/prometheus-community/postgres_exporter/issues/502 Signed-off-by: SuperQ --- collector/pg_stat_statements.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/collector/pg_stat_statements.go b/collector/pg_stat_statements.go index e28c1c595..c03e78b92 100644 --- a/collector/pg_stat_statements.go +++ b/collector/pg_stat_statements.go @@ -105,9 +105,9 @@ var ( JOIN pg_database ON pg_database.oid = pg_stat_statements.dbid WHERE - total_time > ( + total_exec_time > ( SELECT percentile_cont(0.1) - WITHIN GROUP (ORDER BY total_time) + WITHIN GROUP (ORDER BY total_exec_time) FROM pg_stat_statements ) ORDER BY seconds_total DESC From 04bb60ce31575d30d4380630ed2f2b98010e69fe Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Tue, 15 Aug 2023 13:49:05 +0200 Subject: [PATCH 140/228] Add a multi-target example config (#890) Add an example Prometheus scrape config, similar to the blackbox_exporter's example config. Fixes: https://github.com/prometheus-community/postgres_exporter/issues/888 Signed-off-by: SuperQ --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index e3774c85c..88c6c098c 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,26 @@ To use the multi-target functionality, send an http request to the endpoint `/pr To avoid putting sensitive information like username and password in the URL, preconfigured auth modules are supported via the [auth_modules](#auth_modules) section of the config file. auth_modules for DSNs can be used with the `/probe` endpoint by specifying the `?auth_module=foo` http parameter. +Example Prometheus config: +```yaml +scrape_configs: + - job_name: 'postgres' + static_configs: + - targets: + - server1:5432 + - server2:5432 + metrics_path: /probe + params: + auth_module: [foo] + relabel_configs: + - source_labels: [__address__] + target_label: __param_target + - source_labels: [__param_target] + target_label: instance + - target_label: __address__ + replacement: 127.0.0.1:9116 # The postgres exporter's real hostname:port. +``` + ## Configuration File The configuration file controls the behavior of the exporter. It can be set using the `--config.file` command line flag and defaults to `postgres_exporter.yml`. From b74852a5353b4bf2cb2cc944f329d651fbf99064 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 23 Aug 2023 17:33:47 -0400 Subject: [PATCH 141/228] Delay database connection until scrape (#882) This no longer returns an error when creating a collector.instance when the database cannot be reached for the version query. This will resolve the entire postgresCollector not being registered for metrics collection when a database is not available. If the version query fails, the scrape will fail. Resolves #880 Signed-off-by: Joe Adams --- collector/collector.go | 8 ++++++++ collector/instance.go | 30 ++++++++++++++++++++++-------- collector/probe.go | 8 ++++++++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/collector/collector.go b/collector/collector.go index c1bf2af9a..e06ef7d1c 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -166,6 +166,14 @@ func (p PostgresCollector) Describe(ch chan<- *prometheus.Desc) { // Collect implements the prometheus.Collector interface. func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) { ctx := context.TODO() + + // Set up the database connection for the collector. + err := p.instance.setup() + if err != nil { + level.Error(p.logger).Log("msg", "Error opening connection to database", "err", err) + return + } + wg := sync.WaitGroup{} wg.Add(len(p.Collectors)) for name, c := range p.Collectors { diff --git a/collector/instance.go b/collector/instance.go index 9b2bbf47f..87eb0591c 100644 --- a/collector/instance.go +++ b/collector/instance.go @@ -22,29 +22,43 @@ import ( ) type instance struct { + dsn string db *sql.DB version semver.Version } func newInstance(dsn string) (*instance, error) { - i := &instance{} + i := &instance{ + dsn: dsn, + } + + // "Create" a database handle to verify the DSN provided is valid. + // Open is not guaranteed to create a connection. db, err := sql.Open("postgres", dsn) if err != nil { return nil, err } + db.Close() + + return i, nil +} + +func (i *instance) setup() error { + db, err := sql.Open("postgres", i.dsn) + if err != nil { + return err + } db.SetMaxOpenConns(1) db.SetMaxIdleConns(1) i.db = db - version, err := queryVersion(db) + version, err := queryVersion(i.db) if err != nil { - db.Close() - return nil, err + return fmt.Errorf("error querying postgresql version: %w", err) + } else { + i.version = version } - - i.version = version - - return i, nil + return nil } func (i *instance) getDB() *sql.DB { diff --git a/collector/probe.go b/collector/probe.go index 834c65177..a7630272e 100644 --- a/collector/probe.go +++ b/collector/probe.go @@ -18,6 +18,7 @@ import ( "sync" "github.com/go-kit/log" + "github.com/go-kit/log/level" "github.com/prometheus-community/postgres_exporter/config" "github.com/prometheus/client_golang/prometheus" ) @@ -74,6 +75,13 @@ func (pc *ProbeCollector) Describe(ch chan<- *prometheus.Desc) { } func (pc *ProbeCollector) Collect(ch chan<- prometheus.Metric) { + // Set up the database connection for the collector. + err := pc.instance.setup() + if err != nil { + level.Error(pc.logger).Log("msg", "Error opening connection to database", "err", err) + return + } + wg := sync.WaitGroup{} wg.Add(len(pc.collectors)) for name, c := range pc.collectors { From 2402783205210bb61e01b3e4e15451e7d4655a7b Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Thu, 24 Aug 2023 00:51:26 -0700 Subject: [PATCH 142/228] Bugfix: Make statsreset nullable (#877) * Stats_reset as null seems to actually be legitimate for new databases, so don't fail for it --------- Signed-off-by: Felix Yuan Co-authored-by: Ben Kochie --- collector/pg_stat_database.go | 10 ++- collector/pg_stat_database_test.go | 98 ++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 3 deletions(-) diff --git a/collector/pg_stat_database.go b/collector/pg_stat_database.go index 382ff7825..328afee2c 100644 --- a/collector/pg_stat_database.go +++ b/collector/pg_stat_database.go @@ -344,9 +344,13 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blk_write_time") continue } + + statsResetMetric := 0.0 if !statsReset.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no stats_reset") - continue + level.Debug(c.log).Log("msg", "No metric for stats_reset, will collect 0 instead") + } + if statsReset.Valid { + statsResetMetric = float64(statsReset.Time.Unix()) } labels := []string{datid.String, datname.String} @@ -466,7 +470,7 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance ch <- prometheus.MustNewConstMetric( statDatabaseStatsReset, prometheus.CounterValue, - float64(statsReset.Time.Unix()), + statsResetMetric, labels..., ) } diff --git a/collector/pg_stat_database_test.go b/collector/pg_stat_database_test.go index 70c73eb5b..fe1b17066 100644 --- a/collector/pg_stat_database_test.go +++ b/collector/pg_stat_database_test.go @@ -406,3 +406,101 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { t.Errorf("there were unfulfilled exceptions: %s", err) } } + +func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{ + "datid", + "datname", + "numbackends", + "xact_commit", + "xact_rollback", + "blks_read", + "blks_hit", + "tup_returned", + "tup_fetched", + "tup_inserted", + "tup_updated", + "tup_deleted", + "conflicts", + "temp_files", + "temp_bytes", + "deadlocks", + "blk_read_time", + "blk_write_time", + "stats_reset", + } + + rows := sqlmock.NewRows(columns). + AddRow( + "pid", + "postgres", + 354, + 4945, + 289097744, + 1242257, + int64(3275602074), + 89320867, + 450139, + 2034563757, + 0, + int64(2725688749), + 23, + 52, + 74, + 925, + 16, + 823, + nil) + + mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatDatabaseCollector{ + log: log.With(log.NewNopLogger(), "collector", "pg_stat_database"), + } + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatDatabaseCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_GAUGE, value: 354}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 4945}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 289097744}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1242257}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 3275602074}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 89320867}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 450139}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 2034563757}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 2725688749}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 23}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 52}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 74}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From ce74daee9216f8530bcf13fafc03c0d430bf0a1f Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Thu, 24 Aug 2023 00:55:26 -0700 Subject: [PATCH 143/228] Gitlab Collector: User Index io stats collector and test (#845) * User Index io stats collector and test --------- Signed-off-by: Felix Yuan --- collector/pg_statio_user_indexes.go | 118 +++++++++++++++++++++++ collector/pg_statio_user_indexes_test.go | 109 +++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 collector/pg_statio_user_indexes.go create mode 100644 collector/pg_statio_user_indexes_test.go diff --git a/collector/pg_statio_user_indexes.go b/collector/pg_statio_user_indexes.go new file mode 100644 index 000000000..b5516338d --- /dev/null +++ b/collector/pg_statio_user_indexes.go @@ -0,0 +1,118 @@ +// Copyright 2023 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 collector + +import ( + "context" + "database/sql" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +func init() { + registerCollector(statioUserIndexesSubsystem, defaultDisabled, NewPGStatioUserIndexesCollector) +} + +type PGStatioUserIndexesCollector struct { + log log.Logger +} + +const statioUserIndexesSubsystem = "statio_user_indexes" + +func NewPGStatioUserIndexesCollector(config collectorConfig) (Collector, error) { + return &PGStatioUserIndexesCollector{log: config.logger}, nil +} + +var ( + statioUserIndexesIdxBlksRead = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statioUserIndexesSubsystem, "idx_blks_read_total"), + "Number of disk blocks read from this index", + []string{"schemaname", "relname", "indexrelname"}, + prometheus.Labels{}, + ) + statioUserIndexesIdxBlksHit = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statioUserIndexesSubsystem, "idx_blks_hit_total"), + "Number of buffer hits in this index", + []string{"schemaname", "relname", "indexrelname"}, + prometheus.Labels{}, + ) + + statioUserIndexesQuery = ` + SELECT + schemaname, + relname, + indexrelname, + idx_blks_read, + idx_blks_hit + FROM pg_statio_user_indexes + ` +) + +func (c *PGStatioUserIndexesCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + rows, err := db.QueryContext(ctx, + statioUserIndexesQuery) + + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var schemaname, relname, indexrelname sql.NullString + var idxBlksRead, idxBlksHit sql.NullFloat64 + + if err := rows.Scan(&schemaname, &relname, &indexrelname, &idxBlksRead, &idxBlksHit); err != nil { + return err + } + schemanameLabel := "unknown" + if schemaname.Valid { + schemanameLabel = schemaname.String + } + relnameLabel := "unknown" + if relname.Valid { + relnameLabel = relname.String + } + indexrelnameLabel := "unknown" + if indexrelname.Valid { + indexrelnameLabel = indexrelname.String + } + labels := []string{schemanameLabel, relnameLabel, indexrelnameLabel} + + idxBlksReadMetric := 0.0 + if idxBlksRead.Valid { + idxBlksReadMetric = idxBlksRead.Float64 + } + ch <- prometheus.MustNewConstMetric( + statioUserIndexesIdxBlksRead, + prometheus.CounterValue, + idxBlksReadMetric, + labels..., + ) + + idxBlksHitMetric := 0.0 + if idxBlksHit.Valid { + idxBlksHitMetric = idxBlksHit.Float64 + } + ch <- prometheus.MustNewConstMetric( + statioUserIndexesIdxBlksHit, + prometheus.CounterValue, + idxBlksHitMetric, + labels..., + ) + } + if err := rows.Err(); err != nil { + return err + } + return nil +} diff --git a/collector/pg_statio_user_indexes_test.go b/collector/pg_statio_user_indexes_test.go new file mode 100644 index 000000000..174012162 --- /dev/null +++ b/collector/pg_statio_user_indexes_test.go @@ -0,0 +1,109 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPgStatioUserIndexesCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + inst := &instance{db: db} + columns := []string{ + "schemaname", + "relname", + "indexrelname", + "idx_blks_read", + "idx_blks_hit", + } + rows := sqlmock.NewRows(columns). + AddRow("public", "pgtest_accounts", "pgtest_accounts_pkey", 8, 9) + + mock.ExpectQuery(sanitizeQuery(statioUserIndexesQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatioUserIndexesCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatioUserIndexesCollector.Update: %s", err) + } + }() + expected := []MetricResult{ + {labels: labelMap{"schemaname": "public", "relname": "pgtest_accounts", "indexrelname": "pgtest_accounts_pkey"}, value: 8, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"schemaname": "public", "relname": "pgtest_accounts", "indexrelname": "pgtest_accounts_pkey"}, value: 9, metricType: dto.MetricType_COUNTER}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} + +func TestPgStatioUserIndexesCollectorNull(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + inst := &instance{db: db} + columns := []string{ + "schemaname", + "relname", + "indexrelname", + "idx_blks_read", + "idx_blks_hit", + } + rows := sqlmock.NewRows(columns). + AddRow(nil, nil, nil, nil, nil) + + mock.ExpectQuery(sanitizeQuery(statioUserIndexesQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatioUserIndexesCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatioUserIndexesCollector.Update: %s", err) + } + }() + expected := []MetricResult{ + {labels: labelMap{"schemaname": "unknown", "relname": "unknown", "indexrelname": "unknown"}, value: 0, metricType: dto.MetricType_COUNTER}, + {labels: labelMap{"schemaname": "unknown", "relname": "unknown", "indexrelname": "unknown"}, value: 0, metricType: dto.MetricType_COUNTER}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From ce4ee0507fb644f166021449b105c5d468203874 Mon Sep 17 00:00:00 2001 From: Mathis Raguin Date: Thu, 24 Aug 2023 09:58:41 +0200 Subject: [PATCH 144/228] Update README to reflect changes made in #828 (#894) Signed-off-by: Mathis Raguin --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 88c6c098c..5a41f50e4 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra Enable the `postmaster` collector (default: enabled). * `[no-]collector.process_idle` - Enable the `process_idle` collector (default: enabled). + Enable the `process_idle` collector (default: disabled). * `[no-]collector.replication` Enable the `replication` collector (default: enabled). From 589087912638d738d1dfeaffbace77660dc3e52e Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Fri, 25 Aug 2023 02:20:10 -0700 Subject: [PATCH 145/228] Gitlab Collector: Long running transactions collector and test (#836) * Long running transactions collector and test --------- Signed-off-by: Felix Yuan Co-authored-by: Ben Kochie --- collector/pg_long_running_transactions.go | 93 +++++++++++++++++++ .../pg_long_running_transactions_test.go | 63 +++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 collector/pg_long_running_transactions.go create mode 100644 collector/pg_long_running_transactions_test.go diff --git a/collector/pg_long_running_transactions.go b/collector/pg_long_running_transactions.go new file mode 100644 index 000000000..ffd89d5f0 --- /dev/null +++ b/collector/pg_long_running_transactions.go @@ -0,0 +1,93 @@ +// Copyright 2023 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 collector + +import ( + "context" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +const longRunningTransactionsSubsystem = "long_running_transactions" + +func init() { + registerCollector(longRunningTransactionsSubsystem, defaultDisabled, NewPGLongRunningTransactionsCollector) +} + +type PGLongRunningTransactionsCollector struct { + log log.Logger +} + +func NewPGLongRunningTransactionsCollector(config collectorConfig) (Collector, error) { + return &PGLongRunningTransactionsCollector{log: config.logger}, nil +} + +var ( + longRunningTransactionsCount = prometheus.NewDesc( + "pg_long_running_transactions", + "Current number of long running transactions", + []string{}, + prometheus.Labels{}, + ) + + longRunningTransactionsAgeInSeconds = prometheus.NewDesc( + prometheus.BuildFQName(namespace, longRunningTransactionsSubsystem, "oldest_timestamp_seconds"), + "The current maximum transaction age in seconds", + []string{}, + prometheus.Labels{}, + ) + + longRunningTransactionsQuery = ` + SELECT + COUNT(*) as transactions, + MAX(EXTRACT(EPOCH FROM clock_timestamp())) AS oldest_timestamp_seconds + FROM pg_catalog.pg_stat_activity + WHERE state is distinct from 'idle' AND query not like 'autovacuum:%' + ` +) + +func (PGLongRunningTransactionsCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + rows, err := db.QueryContext(ctx, + longRunningTransactionsQuery) + + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var transactions, ageInSeconds float64 + + if err := rows.Scan(&transactions, &ageInSeconds); err != nil { + return err + } + + ch <- prometheus.MustNewConstMetric( + longRunningTransactionsCount, + prometheus.GaugeValue, + transactions, + ) + ch <- prometheus.MustNewConstMetric( + longRunningTransactionsAgeInSeconds, + prometheus.GaugeValue, + ageInSeconds, + ) + } + if err := rows.Err(); err != nil { + return err + } + return nil +} diff --git a/collector/pg_long_running_transactions_test.go b/collector/pg_long_running_transactions_test.go new file mode 100644 index 000000000..eedda7c65 --- /dev/null +++ b/collector/pg_long_running_transactions_test.go @@ -0,0 +1,63 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGLongRunningTransactionsCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + inst := &instance{db: db} + columns := []string{ + "transactions", + "age_in_seconds", + } + rows := sqlmock.NewRows(columns). + AddRow(20, 1200) + + mock.ExpectQuery(sanitizeQuery(longRunningTransactionsQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGLongRunningTransactionsCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGLongRunningTransactionsCollector.Update: %s", err) + } + }() + expected := []MetricResult{ + {labels: labelMap{}, value: 20, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{}, value: 1200, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From a181fba6740dc375686dd4b911934a1cc7afb93a Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Sun, 3 Sep 2023 08:49:01 +0200 Subject: [PATCH 146/228] Update common Prometheus files (#900) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 2 +- Makefile.common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 433f71b88..a619a7325 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -29,4 +29,4 @@ jobs: - name: Lint uses: golangci/golangci-lint-action@v3.4.0 with: - version: v1.53.3 + version: v1.54.2 diff --git a/Makefile.common b/Makefile.common index 0ce7ea461..062a28185 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.53.3 +GOLANGCI_LINT_VERSION ?= v1.54.2 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) From 68ea16786653993f290ffe29d5f82c7f41d470e0 Mon Sep 17 00:00:00 2001 From: Christian Albrecht Date: Wed, 6 Sep 2023 04:07:37 +0200 Subject: [PATCH 147/228] Fix a connection leak (#902) The leak was introduced in PR#882 Signed-off-by: Christian Albrecht Co-authored-by: Christian Albrecht --- collector/collector.go | 1 + collector/probe.go | 1 + 2 files changed, 2 insertions(+) diff --git a/collector/collector.go b/collector/collector.go index e06ef7d1c..c643bd91e 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -173,6 +173,7 @@ func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) { level.Error(p.logger).Log("msg", "Error opening connection to database", "err", err) return } + defer p.instance.Close() wg := sync.WaitGroup{} wg.Add(len(p.Collectors)) diff --git a/collector/probe.go b/collector/probe.go index a7630272e..4c0f0419b 100644 --- a/collector/probe.go +++ b/collector/probe.go @@ -81,6 +81,7 @@ func (pc *ProbeCollector) Collect(ch chan<- prometheus.Metric) { level.Error(pc.logger).Log("msg", "Error opening connection to database", "err", err) return } + defer pc.instance.Close() wg := sync.WaitGroup{} wg.Add(len(pc.collectors)) From dbc7b0b2299dad9813bfb987faab1037b4e661a4 Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 8 Sep 2023 15:08:06 -0500 Subject: [PATCH 148/228] Fix cross-compilation command in README.md (#903) Signed-off-by: David Cook --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a41f50e4..d37ff4e68 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ auth_modules: To build the Docker image: make promu - promu crossbuild -p linux/amd64 -p linux/armv7 -p linux/amd64 -p linux/ppc64le + promu crossbuild -p linux/amd64 -p linux/armv7 -p linux/arm64 -p linux/ppc64le make docker This will build the docker image as `prometheuscommunity/postgres_exporter:${branch}`. From 0b6d9860abb2340412a15be1fc2b4d25e154b8c3 Mon Sep 17 00:00:00 2001 From: Vladimir Luksha Date: Fri, 8 Sep 2023 23:20:19 +0300 Subject: [PATCH 149/228] fix pg_replication_lag_seconds (#895) Signed-off-by: Vladimir Luksha Co-authored-by: Vladimir Luksha --- collector/pg_replication.go | 1 + 1 file changed, 1 insertion(+) diff --git a/collector/pg_replication.go b/collector/pg_replication.go index 790f85329..6067cc9b1 100644 --- a/collector/pg_replication.go +++ b/collector/pg_replication.go @@ -55,6 +55,7 @@ var ( pgReplicationQuery = `SELECT CASE WHEN NOT pg_is_in_recovery() THEN 0 + WHEN pg_last_wal_receive_lsn () = pg_last_wal_replay_lsn () THEN 0 ELSE GREATEST (0, EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))) END AS lag, CASE From 31ef4ed5a2c3835bca7da0ac0a77a516af472e26 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 12 Sep 2023 08:07:36 -0500 Subject: [PATCH 150/228] stat_user_tables: Add total size metric (#904) Signed-off-by: David Cook --- collector/pg_stat_user_tables.go | 24 +++++++++++++++++++++--- collector/pg_stat_user_tables_test.go | 10 +++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/collector/pg_stat_user_tables.go b/collector/pg_stat_user_tables.go index 949a0ea2b..af3822ca8 100644 --- a/collector/pg_stat_user_tables.go +++ b/collector/pg_stat_user_tables.go @@ -150,6 +150,12 @@ var ( []string{"datname", "schemaname", "relname"}, prometheus.Labels{}, ) + statUserTablesTotalSize = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "size_bytes"), + "Total disk space used by this table, in bytes, including all indexes and TOAST data", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) statUserTablesQuery = `SELECT current_database() datname, @@ -173,7 +179,8 @@ var ( vacuum_count, autovacuum_count, analyze_count, - autoanalyze_count + autoanalyze_count, + pg_total_relation_size(relid) as total_size FROM pg_stat_user_tables` ) @@ -191,10 +198,10 @@ func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instan for rows.Next() { var datname, schemaname, relname sql.NullString var seqScan, seqTupRead, idxScan, idxTupFetch, nTupIns, nTupUpd, nTupDel, nTupHotUpd, nLiveTup, nDeadTup, - nModSinceAnalyze, vacuumCount, autovacuumCount, analyzeCount, autoanalyzeCount sql.NullInt64 + nModSinceAnalyze, vacuumCount, autovacuumCount, analyzeCount, autoanalyzeCount, totalSize sql.NullInt64 var lastVacuum, lastAutovacuum, lastAnalyze, lastAutoanalyze sql.NullTime - if err := rows.Scan(&datname, &schemaname, &relname, &seqScan, &seqTupRead, &idxScan, &idxTupFetch, &nTupIns, &nTupUpd, &nTupDel, &nTupHotUpd, &nLiveTup, &nDeadTup, &nModSinceAnalyze, &lastVacuum, &lastAutovacuum, &lastAnalyze, &lastAutoanalyze, &vacuumCount, &autovacuumCount, &analyzeCount, &autoanalyzeCount); err != nil { + if err := rows.Scan(&datname, &schemaname, &relname, &seqScan, &seqTupRead, &idxScan, &idxTupFetch, &nTupIns, &nTupUpd, &nTupDel, &nTupHotUpd, &nLiveTup, &nDeadTup, &nModSinceAnalyze, &lastVacuum, &lastAutovacuum, &lastAnalyze, &lastAutoanalyze, &vacuumCount, &autovacuumCount, &analyzeCount, &autoanalyzeCount, &totalSize); err != nil { return err } @@ -419,6 +426,17 @@ func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instan autoanalyzeCountMetric, datnameLabel, schemanameLabel, relnameLabel, ) + + totalSizeMetric := 0.0 + if totalSize.Valid { + totalSizeMetric = float64(totalSize.Int64) + } + ch <- prometheus.MustNewConstMetric( + statUserTablesTotalSize, + prometheus.GaugeValue, + totalSizeMetric, + datnameLabel, schemanameLabel, relnameLabel, + ) } if err := rows.Err(); err != nil { diff --git a/collector/pg_stat_user_tables_test.go b/collector/pg_stat_user_tables_test.go index e592fa5e4..5e82335c3 100644 --- a/collector/pg_stat_user_tables_test.go +++ b/collector/pg_stat_user_tables_test.go @@ -71,7 +71,8 @@ func TestPGStatUserTablesCollector(t *testing.T) { "vacuum_count", "autovacuum_count", "analyze_count", - "autoanalyze_count"} + "autoanalyze_count", + "total_size"} rows := sqlmock.NewRows(columns). AddRow("postgres", "public", @@ -94,7 +95,8 @@ func TestPGStatUserTablesCollector(t *testing.T) { 11, 12, 13, - 14) + 14, + 15) mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -170,7 +172,8 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) { "vacuum_count", "autovacuum_count", "analyze_count", - "autoanalyze_count"} + "autoanalyze_count", + "total_size"} rows := sqlmock.NewRows(columns). AddRow("postgres", nil, @@ -193,6 +196,7 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) { nil, nil, nil, + nil, nil) mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) From 4e521d460e1ed6fa963c2266c8ee02ba519acf6d Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Wed, 13 Sep 2023 09:19:21 -0400 Subject: [PATCH 151/228] Fix bugs mentioned in #908 (#910) * Fix bugs mentioned in #908 These collectors are disabled by default, so unless enabled, they are not tested regularly. Signed-off-by: Joe Adams --------- Signed-off-by: Joe Adams --- collector/pg_stat_activity_autovacuum.go | 2 +- collector/pg_stat_walreceiver.go | 8 +++++--- collector/pg_xlog_location.go | 13 ++++++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/collector/pg_stat_activity_autovacuum.go b/collector/pg_stat_activity_autovacuum.go index 5e2d2d2ca..6cf8cdcec 100644 --- a/collector/pg_stat_activity_autovacuum.go +++ b/collector/pg_stat_activity_autovacuum.go @@ -45,7 +45,7 @@ var ( statActivityAutovacuumQuery = ` SELECT SPLIT_PART(query, '.', 2) AS relname, - EXTRACT(xact_start) AS timestamp_seconds + EXTRACT(EPOCH FROM xact_start) AS timestamp_seconds FROM pg_catalog.pg_stat_activity WHERE diff --git a/collector/pg_stat_walreceiver.go b/collector/pg_stat_walreceiver.go index 3134c025b..db533ab55 100644 --- a/collector/pg_stat_walreceiver.go +++ b/collector/pg_stat_walreceiver.go @@ -107,13 +107,13 @@ var ( trim(both '''' from substring(conninfo from 'host=([^ ]*)')) as upstream_host, slot_name, status, - (receive_start_lsn- '0/0') % (2^52)::bigint as receive_start_lsn, + (receive_start_lsn- '0/0') %% (2^52)::bigint as receive_start_lsn, %s receive_start_tli, received_tli, extract(epoch from last_msg_send_time) as last_msg_send_time, extract(epoch from last_msg_receipt_time) as last_msg_receipt_time, - (latest_end_lsn - '0/0') % (2^52)::bigint as latest_end_lsn, + (latest_end_lsn - '0/0') %% (2^52)::bigint as latest_end_lsn, extract(epoch from latest_end_time) as latest_end_time, substring(slot_name from 'repmgr_slot_([0-9]*)') as upstream_node FROM pg_catalog.pg_stat_wal_receiver @@ -127,7 +127,6 @@ func (c *PGStatWalReceiverCollector) Update(ctx context.Context, instance *insta return err } - defer hasFlushedLSNRows.Close() hasFlushedLSN := hasFlushedLSNRows.Next() var query string if hasFlushedLSN { @@ -135,6 +134,9 @@ func (c *PGStatWalReceiverCollector) Update(ctx context.Context, instance *insta } else { query = fmt.Sprintf(pgStatWalReceiverQueryTemplate, "") } + + hasFlushedLSNRows.Close() + rows, err := db.QueryContext(ctx, query) if err != nil { return err diff --git a/collector/pg_xlog_location.go b/collector/pg_xlog_location.go index 92ac44acb..237204f7d 100644 --- a/collector/pg_xlog_location.go +++ b/collector/pg_xlog_location.go @@ -16,7 +16,9 @@ package collector import ( "context" + "github.com/blang/semver/v4" "github.com/go-kit/log" + "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) @@ -50,8 +52,17 @@ var ( ` ) -func (PGXlogLocationCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { +func (c PGXlogLocationCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { db := instance.getDB() + + // xlog was renmaed to WAL in PostgreSQL 10 + // https://wiki.postgresql.org/wiki/New_in_postgres_10#Renaming_of_.22xlog.22_to_.22wal.22_Globally_.28and_location.2Flsn.29 + after10 := instance.version.Compare(semver.MustParse("10.0.0")) + if after10 >= 0 { + level.Warn(c.log).Log("msg", "xlog_location collector is not available on PostgreSQL >= 10.0.0, skipping") + return nil + } + rows, err := db.QueryContext(ctx, xlogLocationQuery) From add5b86cff544fcda8c45a54a399a043ddae13c2 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Sun, 17 Sep 2023 11:04:14 +0200 Subject: [PATCH 152/228] Update common Prometheus files (#913) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index a619a7325..8ace97bde 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -18,15 +18,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: install Go - uses: actions/setup-go@v3 + uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 with: go-version: 1.20.x - name: Install snmp_exporter/generator dependencies run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@v3.4.0 + uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 with: version: v1.54.2 From c06e57db4e502696ab4e8b8898bb2a59b7b33a59 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Tue, 19 Sep 2023 21:27:45 -0400 Subject: [PATCH 153/228] Add changelog for v0.14 (#906) * Add changelog for v0.14 - Add changelog entries since v0.13.2 - Update README with new options - Bump version file Signed-off-by: Joe Adams * Add changelog entry for #904 Signed-off-by: Joe Adams --------- Signed-off-by: Joe Adams --- CHANGELOG.md | 17 +++++++++++++++++ README.md | 29 +++++++++++++++++++++++++---- VERSION | 2 +- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9ab3cb24..f55bde533 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +## 0.14.0 / 2023-09-11 + +* [CHANGE] Add `state` label to pg_process_idle_seconds #862 +* [CHANGE] Change database connections to one per scrape #882 #902 +* [ENHANCEMENT] Add wal collector #858 +* [ENHANCEMENT] Add database_wraparound collector #834 +* [ENHANCEMENT] Add stat_activity_autovacuum collector #840 +* [ENHANCEMENT] Add stat_wal_receiver collector #844 +* [ENHANCEMENT] Add xlog_location collector #849 +* [ENHANCEMENT] Add statio_user_indexes collector #845 +* [ENHANCEMENT] Add long_running_transactions collector #836 +* [ENHANCEMENT] Add pg_stat_user_tables_size_bytes metric #904 +* [BUGFIX] Fix tests on 32-bit systems #857 +* [BUGFIX] Fix pg_stat_statements metrics on Postgres 13+ #874 #876 +* [BUGFIX] Fix pg_stat_database metrics for NULL stats_reset #877 +* [BUGFIX] Fix pg_replication_lag_seconds on Postgres 10+ when master is idle #895 + ## 0.13.2 / 2023-07-21 * [BUGFIX] Fix type issues on pg_postmaster metrics #828 diff --git a/README.md b/README.md index d37ff4e68..3b7730bc8 100644 --- a/README.md +++ b/README.md @@ -95,11 +95,17 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra * `[no-]collector.database` Enable the `database` collector (default: enabled). +* `[no-]collector.database_wraparound` + Enable the `database_wraparound` collector (default: disabled). + * `[no-]collector.locks` Enable the `locks` collector (default: enabled). +* `[no-]collector.long_running_transactions` + Enable the `long_running_transactions` collector (default: disabled). + * `[no-]collector.postmaster` - Enable the `postmaster` collector (default: enabled). + Enable the `postmaster` collector (default: disabled). * `[no-]collector.process_idle` Enable the `process_idle` collector (default: disabled). @@ -110,21 +116,36 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra * `[no-]collector.replication_slot` Enable the `replication_slot` collector (default: enabled). +* `[no-]collector.stat_activity_autovacuum` + Enable the `stat_activity_autovacuum` collector (default: disabled). + * `[no-]collector.stat_bgwriter` Enable the `stat_bgwriter` collector (default: enabled). * `[no-]collector.stat_database` Enable the `stat_database` collector (default: enabled). -* `[no-]collector.statio_user_tables` - Enable the `statio_user_tables` collector (default: enabled). - * `[no-]collector.stat_statements` Enable the `stat_statements` collector (default: disabled). * `[no-]collector.stat_user_tables` Enable the `stat_user_tables` collector (default: enabled). +* `[no-]collector.stat_wal_receiver` + Enable the `stat_wal_receiver` collector (default: disabled). + +* `[no-]collector.statio_user_indexes` + Enable the `statio_user_indexes` collector (default: disabled). + +* `[no-]collector.statio_user_tables` + Enable the `statio_user_tables` collector (default: enabled). + +* `[no-]collector.wal` + Enable the `wal` collector (default: enabled). + +* `[no-]collector.xlog_location` + Enable the `xlog_location` collector (default: disabled). + * `config.file` Set the config file path. Default is `postgres_exporter.yml` diff --git a/VERSION b/VERSION index c317a9189..a803cc227 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.13.1 +0.14.0 From e3eaa91c0bcc498e11db1a17686ee53a8c45456c Mon Sep 17 00:00:00 2001 From: Eric Tyrrell <58529434+Eric-Tyrrell22@users.noreply.github.com> Date: Tue, 19 Sep 2023 21:40:29 -0400 Subject: [PATCH 154/228] Adds 1kB and 2kB units (#915) Signed-off-by: Eric tyrrell --- cmd/postgres_exporter/pg_setting.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/pg_setting.go b/cmd/postgres_exporter/pg_setting.go index 30b60ca1c..f162c354a 100644 --- a/cmd/postgres_exporter/pg_setting.go +++ b/cmd/postgres_exporter/pg_setting.go @@ -129,7 +129,7 @@ func (s *pgSetting) normaliseUnit() (val float64, unit string, err error) { return case "ms", "s", "min", "h", "d": unit = "seconds" - case "B", "kB", "MB", "GB", "TB", "4kB", "8kB", "16kB", "32kB", "64kB", "16MB", "32MB", "64MB": + case "B", "kB", "MB", "GB", "TB", "1kB", "2kB", "4kB", "8kB", "16kB", "32kB", "64kB", "16MB", "32MB", "64MB": unit = "bytes" default: err = fmt.Errorf("Unknown unit for runtime variable: %q", s.unit) @@ -158,6 +158,10 @@ func (s *pgSetting) normaliseUnit() (val float64, unit string, err error) { val *= math.Pow(2, 30) case "TB": val *= math.Pow(2, 40) + case "1kB": + val *= math.Pow(2, 10) + case "2kB": + val *= math.Pow(2, 11) case "4kB": val *= math.Pow(2, 12) case "8kB": From 30d7d25a7eb7e4e92167fa5ae69499c12dba3450 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Thu, 21 Sep 2023 07:13:14 -0400 Subject: [PATCH 155/228] Add error log when probe collector creation fails (#918) Signed-off-by: Joe Adams --- cmd/postgres_exporter/probe.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go index 827314a7a..5945e07b8 100644 --- a/cmd/postgres_exporter/probe.go +++ b/cmd/postgres_exporter/probe.go @@ -85,6 +85,7 @@ func handleProbe(logger log.Logger, excludeDatabases []string) http.HandlerFunc // Run the probe pc, err := collector.NewProbeCollector(tl, excludeDatabases, registry, dsn) if err != nil { + level.Error(logger).Log("msg", "Error creating probe collector", "err", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } From 51415a0e5b60504f262ecc50d238c658810375af Mon Sep 17 00:00:00 2001 From: Daniel Swarbrick Date: Thu, 21 Sep 2023 14:58:46 +0200 Subject: [PATCH 156/228] Fix test build failures on 32-bit arch again (#919) Another case of untyped integer overflows on 32-bit arch. Signed-off-by: Daniel Swarbrick --- collector/pg_stat_walreceiver_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/collector/pg_stat_walreceiver_test.go b/collector/pg_stat_walreceiver_test.go index 3e2418b25..c81c9ecae 100644 --- a/collector/pg_stat_walreceiver_test.go +++ b/collector/pg_stat_walreceiver_test.go @@ -64,13 +64,13 @@ func TestPGStatWalReceiverCollectorWithFlushedLSN(t *testing.T) { "foo", "bar", "stopping", - 1200668684563608, + int64(1200668684563608), 1687321285, - 1200668684563609, + int64(1200668684563609), 1687321280, 1687321275, 1687321276, - 1200668684563610, + int64(1200668684563610), 1687321277, 5, ) @@ -143,12 +143,12 @@ func TestPGStatWalReceiverCollectorWithNoFlushedLSN(t *testing.T) { "foo", "bar", "starting", - 1200668684563608, + int64(1200668684563608), 1687321285, 1687321280, 1687321275, 1687321276, - 1200668684563610, + int64(1200668684563610), 1687321277, 5, ) From 5e24d43e3e881a434a5c4e5c76f668a0c9782849 Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Thu, 21 Sep 2023 15:27:00 +0200 Subject: [PATCH 157/228] Add 32-bit testing to CI (#920) Run Go tests with 32-bit to validate value overflow. Signed-off-by: SuperQ --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 508120e67..d586cb290 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,6 +16,7 @@ jobs: steps: - prometheus/setup_environment + - run: GOHOSTARCH=386 GOARCH=386 make test - run: make - prometheus/store_artifact: file: postgres_exporter From 69fc35b0ecb4c02030bca1410913a171e1a847d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:00:41 +0200 Subject: [PATCH 158/228] Bump github.com/prometheus/client_golang from 1.16.0 to 1.17.0 (#925) * Bump github.com/prometheus/client_golang from 1.16.0 to 1.17.0 Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.16.0 to 1.17.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.16.0...v1.17.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update tests for latest client_golang. Signed-off-by: SuperQ --------- Signed-off-by: dependabot[bot] Signed-off-by: SuperQ Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: SuperQ --- cmd/postgres_exporter/pg_setting_test.go | 22 +++++++++++----------- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/cmd/postgres_exporter/pg_setting_test.go b/cmd/postgres_exporter/pg_setting_test.go index 1b1168c7e..0e010444d 100644 --- a/cmd/postgres_exporter/pg_setting_test.go +++ b/cmd/postgres_exporter/pg_setting_test.go @@ -40,7 +40,7 @@ var fixtures = []fixture{ unit: "seconds", err: "", }, - d: `Desc{fqName: "pg_settings_seconds_fixture_metric_seconds", help: "Server Parameter: seconds_fixture_metric [Units converted to seconds.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_seconds_fixture_metric_seconds", help: "Server Parameter: seconds_fixture_metric [Units converted to seconds.]", constLabels: {}, variableLabels: {}}`, v: 5, }, { @@ -56,7 +56,7 @@ var fixtures = []fixture{ unit: "seconds", err: "", }, - d: `Desc{fqName: "pg_settings_milliseconds_fixture_metric_seconds", help: "Server Parameter: milliseconds_fixture_metric [Units converted to seconds.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_milliseconds_fixture_metric_seconds", help: "Server Parameter: milliseconds_fixture_metric [Units converted to seconds.]", constLabels: {}, variableLabels: {}}`, v: 5, }, { @@ -72,7 +72,7 @@ var fixtures = []fixture{ unit: "bytes", err: "", }, - d: `Desc{fqName: "pg_settings_eight_kb_fixture_metric_bytes", help: "Server Parameter: eight_kb_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_eight_kb_fixture_metric_bytes", help: "Server Parameter: eight_kb_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: {}}`, v: 139264, }, { @@ -88,7 +88,7 @@ var fixtures = []fixture{ unit: "bytes", err: "", }, - d: `Desc{fqName: "pg_settings_16_kb_real_fixture_metric_bytes", help: "Server Parameter: 16_kb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_16_kb_real_fixture_metric_bytes", help: "Server Parameter: 16_kb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: {}}`, v: 49152, }, { @@ -104,7 +104,7 @@ var fixtures = []fixture{ unit: "bytes", err: "", }, - d: `Desc{fqName: "pg_settings_16_mb_real_fixture_metric_bytes", help: "Server Parameter: 16_mb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_16_mb_real_fixture_metric_bytes", help: "Server Parameter: 16_mb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: {}}`, v: 5.0331648e+07, }, { @@ -120,7 +120,7 @@ var fixtures = []fixture{ unit: "bytes", err: "", }, - d: `Desc{fqName: "pg_settings_32_mb_real_fixture_metric_bytes", help: "Server Parameter: 32_mb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_32_mb_real_fixture_metric_bytes", help: "Server Parameter: 32_mb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: {}}`, v: 1.00663296e+08, }, { @@ -136,7 +136,7 @@ var fixtures = []fixture{ unit: "bytes", err: "", }, - d: `Desc{fqName: "pg_settings_64_mb_real_fixture_metric_bytes", help: "Server Parameter: 64_mb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_64_mb_real_fixture_metric_bytes", help: "Server Parameter: 64_mb_real_fixture_metric [Units converted to bytes.]", constLabels: {}, variableLabels: {}}`, v: 2.01326592e+08, }, { @@ -152,7 +152,7 @@ var fixtures = []fixture{ unit: "", err: "", }, - d: `Desc{fqName: "pg_settings_bool_on_fixture_metric", help: "Server Parameter: bool_on_fixture_metric", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_bool_on_fixture_metric", help: "Server Parameter: bool_on_fixture_metric", constLabels: {}, variableLabels: {}}`, v: 1, }, { @@ -168,7 +168,7 @@ var fixtures = []fixture{ unit: "", err: "", }, - d: `Desc{fqName: "pg_settings_bool_off_fixture_metric", help: "Server Parameter: bool_off_fixture_metric", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_bool_off_fixture_metric", help: "Server Parameter: bool_off_fixture_metric", constLabels: {}, variableLabels: {}}`, v: 0, }, { @@ -184,7 +184,7 @@ var fixtures = []fixture{ unit: "seconds", err: "", }, - d: `Desc{fqName: "pg_settings_special_minus_one_value_seconds", help: "Server Parameter: special_minus_one_value [Units converted to seconds.]", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_special_minus_one_value_seconds", help: "Server Parameter: special_minus_one_value [Units converted to seconds.]", constLabels: {}, variableLabels: {}}`, v: -1, }, { @@ -200,7 +200,7 @@ var fixtures = []fixture{ unit: "", err: "", }, - d: `Desc{fqName: "pg_settings_rds_rds_superuser_reserved_connections", help: "Server Parameter: rds.rds_superuser_reserved_connections", constLabels: {}, variableLabels: []}`, + d: `Desc{fqName: "pg_settings_rds_rds_superuser_reserved_connections", help: "Server Parameter: rds.rds_superuser_reserved_connections", constLabels: {}, variableLabels: {}}`, v: 2, }, { diff --git a/go.mod b/go.mod index 1e1d70c4e..ca6f8b53b 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 github.com/lib/pq v1.10.9 - github.com/prometheus/client_golang v1.16.0 - github.com/prometheus/client_model v0.4.0 + github.com/prometheus/client_golang v1.17.0 + github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 github.com/prometheus/common v0.44.0 github.com/prometheus/exporter-toolkit v0.10.0 github.com/smartystreets/goconvey v1.8.1 @@ -32,16 +32,16 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/prometheus/procfs v0.10.1 // indirect + github.com/prometheus/procfs v0.11.1 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect golang.org/x/crypto v0.8.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.8.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.11.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/go.sum b/go.sum index c6efce431..ba96fa3ba 100644 --- a/go.sum +++ b/go.sum @@ -49,16 +49,16 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY= -github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= +github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= @@ -80,11 +80,11 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= @@ -95,8 +95,8 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From f0f051cb9aca2d174ffda5f8ac2658a78bd74d1b Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Sun, 8 Oct 2023 14:02:26 +0200 Subject: [PATCH 159/228] Update common Prometheus files (#926) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 8ace97bde..15cf547be 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: install Go uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 with: From 2a5692c0283fddf96e776cc73c2fc0d5caed1af6 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Tue, 10 Oct 2023 07:07:37 -0400 Subject: [PATCH 160/228] Adjust collector to use separate connection per scrape (#931) Fixes #921 Signed-off-by: Joe Adams --- collector/collector.go | 9 ++++++--- collector/instance.go | 7 +++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/collector/collector.go b/collector/collector.go index c643bd91e..121129871 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -167,19 +167,22 @@ func (p PostgresCollector) Describe(ch chan<- *prometheus.Desc) { func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) { ctx := context.TODO() + // copy the instance so that concurrent scrapes have independent instances + inst := p.instance.copy() + // Set up the database connection for the collector. - err := p.instance.setup() + err := inst.setup() if err != nil { level.Error(p.logger).Log("msg", "Error opening connection to database", "err", err) return } - defer p.instance.Close() + defer inst.Close() wg := sync.WaitGroup{} wg.Add(len(p.Collectors)) for name, c := range p.Collectors { go func(name string, c Collector) { - execute(ctx, name, c, p.instance, ch, p.logger) + execute(ctx, name, c, inst, ch, p.logger) wg.Done() }(name, c) } diff --git a/collector/instance.go b/collector/instance.go index 87eb0591c..a365697d6 100644 --- a/collector/instance.go +++ b/collector/instance.go @@ -43,6 +43,13 @@ func newInstance(dsn string) (*instance, error) { return i, nil } +// copy returns a copy of the instance. +func (i *instance) copy() *instance { + return &instance{ + dsn: i.dsn, + } +} + func (i *instance) setup() error { db, err := sql.Open("postgres", i.dsn) if err != nil { From e2892a7976ffbcb68d5ac6757d5dd9719a8459b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 13:57:17 +0200 Subject: [PATCH 161/228] Bump golang.org/x/net from 0.10.0 to 0.17.0 (#936) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.10.0 to 0.17.0. - [Commits](https://github.com/golang/net/compare/v0.10.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index ca6f8b53b..4ddfbfbe5 100644 --- a/go.mod +++ b/go.mod @@ -36,12 +36,12 @@ require ( github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.8.0 // indirect - golang.org/x/net v0.10.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/go.sum b/go.sum index ba96fa3ba..3a163d16b 100644 --- a/go.sum +++ b/go.sum @@ -72,23 +72,23 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= From 68c176b8833b7580bf847cecf60f8e0ad5923f9a Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Fri, 27 Oct 2023 10:25:39 -0400 Subject: [PATCH 162/228] Release v0.15.0 (#944) * [ENHANCEMENT] Add 1kB and 2kB units #915 * [BUGFIX] Add error log when probe collector creation fails #918 * [BUGFIX] Fix test build failures on 32-bit arch #919 * [BUGFIX] Adjust collector to use separate connection per scrape #936 Signed-off-by: SuperQ --- .circleci/config.yml | 8 ++++---- .promu.yml | 3 +-- CHANGELOG.md | 7 +++++++ README.md | 2 +- VERSION | 2 +- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d586cb290..98099e295 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,7 +8,7 @@ executors: # This must match .promu.yml. golang: docker: - - image: cimg/go:1.20 + - image: cimg/go:1.21 jobs: test: @@ -57,12 +57,12 @@ workflows: matrix: parameters: postgres_image: - - circleci/postgres:10 - circleci/postgres:11 - circleci/postgres:12 - circleci/postgres:13 - - cimg/postgres:14.1 - - cimg/postgres:15.1 + - cimg/postgres:14.9 + - cimg/postgres:15.4 + - cimg/postgres:16.0 - prometheus/build: name: build parallelism: 3 diff --git a/.promu.yml b/.promu.yml index 55c73712e..dbad0ba95 100644 --- a/.promu.yml +++ b/.promu.yml @@ -1,13 +1,12 @@ go: # This must match .circle/config.yml. - version: 1.20 + version: 1.21 repository: path: github.com/prometheus-community/postgres_exporter build: binaries: - name: postgres_exporter path: ./cmd/postgres_exporter - flags: -a -tags 'netgo static_build' ldflags: | -X github.com/prometheus/common/version.Version={{.Version}} -X github.com/prometheus/common/version.Revision={{.Revision}} diff --git a/CHANGELOG.md b/CHANGELOG.md index f55bde533..4d17f536b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.15.0 / 2023-10-27 + +* [ENHANCEMENT] Add 1kB and 2kB units #915 +* [BUGFIX] Add error log when probe collector creation fails #918 +* [BUGFIX] Fix test build failures on 32-bit arch #919 +* [BUGFIX] Adjust collector to use separate connection per scrape #936 + ## 0.14.0 / 2023-09-11 * [CHANGE] Add `state` label to pg_process_idle_seconds #862 diff --git a/README.md b/README.md index 3b7730bc8..429058e6d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Prometheus exporter for PostgreSQL server metrics. -CI Tested PostgreSQL versions: `10`, `11`, `12`, `13`, `14`, `15` +CI Tested PostgreSQL versions: `11`, `12`, `13`, `14`, `15`, `16` ## Quick Start This package is available for Docker: diff --git a/VERSION b/VERSION index a803cc227..a55105169 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.14.0 +0.15.0 From 94b065124668db87196d0cc0ebdbd188e54be918 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Wed, 15 Nov 2023 04:03:52 +0100 Subject: [PATCH 163/228] Update common Prometheus files (#951) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 15cf547be..babd8a0c4 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: install Go uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 with: From f0ea0163bbbc2aef53f6d07865363da989699320 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Thu, 23 Nov 2023 09:42:58 +0100 Subject: [PATCH 164/228] Update common Prometheus files (#963) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index babd8a0c4..ffa6b3090 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -22,7 +22,7 @@ jobs: - name: install Go uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 with: - go-version: 1.20.x + go-version: 1.21.x - name: Install snmp_exporter/generator dependencies run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' From ae1375b28e9d186945fa43a16bf64d19a6825101 Mon Sep 17 00:00:00 2001 From: Alex Simenduev Date: Thu, 23 Nov 2023 10:44:58 +0200 Subject: [PATCH 165/228] pg_replication_slot: add slot type label (#960) Signed-off-by: Alex Simenduev --- collector/pg_replication_slot.go | 28 +++++++++++++-------- collector/pg_replication_slot_test.go | 36 +++++++++++++-------------- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/collector/pg_replication_slot.go b/collector/pg_replication_slot.go index c625fd4d5..7f1ba003e 100644 --- a/collector/pg_replication_slot.go +++ b/collector/pg_replication_slot.go @@ -43,7 +43,7 @@ var ( "slot_current_wal_lsn", ), "current wal lsn value", - []string{"slot_name"}, nil, + []string{"slot_name", "slot_type"}, nil, ) pgReplicationSlotCurrentFlushDesc = prometheus.NewDesc( prometheus.BuildFQName( @@ -52,7 +52,7 @@ var ( "slot_confirmed_flush_lsn", ), "last lsn confirmed flushed to the replication slot", - []string{"slot_name"}, nil, + []string{"slot_name", "slot_type"}, nil, ) pgReplicationSlotIsActiveDesc = prometheus.NewDesc( prometheus.BuildFQName( @@ -61,17 +61,18 @@ var ( "slot_is_active", ), "whether the replication slot is active or not", - []string{"slot_name"}, nil, + []string{"slot_name", "slot_type"}, nil, ) pgReplicationSlotQuery = `SELECT slot_name, - CASE WHEN pg_is_in_recovery() THEN + slot_type, + CASE WHEN pg_is_in_recovery() THEN pg_last_wal_receive_lsn() - '0/0' - ELSE - pg_current_wal_lsn() - '0/0' + ELSE + pg_current_wal_lsn() - '0/0' END AS current_wal_lsn, - COALESCE(confirmed_flush_lsn, '0/0') - '0/0', + COALESCE(confirmed_flush_lsn, '0/0') - '0/0' AS confirmed_flush_lsn, active FROM pg_replication_slots;` ) @@ -87,10 +88,11 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance for rows.Next() { var slotName sql.NullString + var slotType sql.NullString var walLSN sql.NullFloat64 var flushLSN sql.NullFloat64 var isActive sql.NullBool - if err := rows.Scan(&slotName, &walLSN, &flushLSN, &isActive); err != nil { + if err := rows.Scan(&slotName, &slotType, &walLSN, &flushLSN, &isActive); err != nil { return err } @@ -102,6 +104,10 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance if slotName.Valid { slotNameLabel = slotName.String } + slotTypeLabel := "unknown" + if slotType.Valid { + slotTypeLabel = slotType.String + } var walLSNMetric float64 if walLSN.Valid { @@ -109,7 +115,7 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance } ch <- prometheus.MustNewConstMetric( pgReplicationSlotCurrentWalDesc, - prometheus.GaugeValue, walLSNMetric, slotNameLabel, + prometheus.GaugeValue, walLSNMetric, slotNameLabel, slotTypeLabel, ) if isActive.Valid && isActive.Bool { var flushLSNMetric float64 @@ -118,12 +124,12 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance } ch <- prometheus.MustNewConstMetric( pgReplicationSlotCurrentFlushDesc, - prometheus.GaugeValue, flushLSNMetric, slotNameLabel, + prometheus.GaugeValue, flushLSNMetric, slotNameLabel, slotTypeLabel, ) } ch <- prometheus.MustNewConstMetric( pgReplicationSlotIsActiveDesc, - prometheus.GaugeValue, isActiveValue, slotNameLabel, + prometheus.GaugeValue, isActiveValue, slotNameLabel, slotTypeLabel, ) } return rows.Err() diff --git a/collector/pg_replication_slot_test.go b/collector/pg_replication_slot_test.go index 7e91ea261..212050c46 100644 --- a/collector/pg_replication_slot_test.go +++ b/collector/pg_replication_slot_test.go @@ -31,9 +31,9 @@ func TestPgReplicationSlotCollectorActive(t *testing.T) { inst := &instance{db: db} - columns := []string{"slot_name", "current_wal_lsn", "confirmed_flush_lsn", "active"} + columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active"} rows := sqlmock.NewRows(columns). - AddRow("test_slot", 5, 3, true) + AddRow("test_slot", "physical", 5, 3, true) mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -47,9 +47,9 @@ func TestPgReplicationSlotCollectorActive(t *testing.T) { }() expected := []MetricResult{ - {labels: labelMap{"slot_name": "test_slot"}, value: 5, metricType: dto.MetricType_GAUGE}, - {labels: labelMap{"slot_name": "test_slot"}, value: 3, metricType: dto.MetricType_GAUGE}, - {labels: labelMap{"slot_name": "test_slot"}, value: 1, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 5, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 3, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 1, metricType: dto.MetricType_GAUGE}, } convey.Convey("Metrics comparison", t, func() { @@ -72,9 +72,9 @@ func TestPgReplicationSlotCollectorInActive(t *testing.T) { inst := &instance{db: db} - columns := []string{"slot_name", "current_wal_lsn", "confirmed_flush_lsn", "active"} + columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active"} rows := sqlmock.NewRows(columns). - AddRow("test_slot", 6, 12, false) + AddRow("test_slot", "physical", 6, 12, false) mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -88,8 +88,8 @@ func TestPgReplicationSlotCollectorInActive(t *testing.T) { }() expected := []MetricResult{ - {labels: labelMap{"slot_name": "test_slot"}, value: 6, metricType: dto.MetricType_GAUGE}, - {labels: labelMap{"slot_name": "test_slot"}, value: 0, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 6, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 0, metricType: dto.MetricType_GAUGE}, } convey.Convey("Metrics comparison", t, func() { @@ -113,9 +113,9 @@ func TestPgReplicationSlotCollectorActiveNil(t *testing.T) { inst := &instance{db: db} - columns := []string{"slot_name", "current_wal_lsn", "confirmed_flush_lsn", "active"} + columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active"} rows := sqlmock.NewRows(columns). - AddRow("test_slot", 6, 12, nil) + AddRow("test_slot", "physical", 6, 12, nil) mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -129,8 +129,8 @@ func TestPgReplicationSlotCollectorActiveNil(t *testing.T) { }() expected := []MetricResult{ - {labels: labelMap{"slot_name": "test_slot"}, value: 6, metricType: dto.MetricType_GAUGE}, - {labels: labelMap{"slot_name": "test_slot"}, value: 0, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 6, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 0, metricType: dto.MetricType_GAUGE}, } convey.Convey("Metrics comparison", t, func() { @@ -153,9 +153,9 @@ func TestPgReplicationSlotCollectorTestNilValues(t *testing.T) { inst := &instance{db: db} - columns := []string{"slot_name", "current_wal_lsn", "confirmed_flush_lsn", "active"} + columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active"} rows := sqlmock.NewRows(columns). - AddRow(nil, nil, nil, true) + AddRow(nil, nil, nil, nil, true) mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -169,9 +169,9 @@ func TestPgReplicationSlotCollectorTestNilValues(t *testing.T) { }() expected := []MetricResult{ - {labels: labelMap{"slot_name": "unknown"}, value: 0, metricType: dto.MetricType_GAUGE}, - {labels: labelMap{"slot_name": "unknown"}, value: 0, metricType: dto.MetricType_GAUGE}, - {labels: labelMap{"slot_name": "unknown"}, value: 1, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "unknown", "slot_type": "unknown"}, value: 0, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "unknown", "slot_type": "unknown"}, value: 0, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "unknown", "slot_type": "unknown"}, value: 1, metricType: dto.MetricType_GAUGE}, } convey.Convey("Metrics comparison", t, func() { From 34f5443ca04d5e21e561da01ab81eb49a2bcabcf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 09:45:22 +0100 Subject: [PATCH 166/228] Bump github.com/prometheus/common from 0.44.0 to 0.45.0 (#948) Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.44.0 to 0.45.0. - [Release notes](https://github.com/prometheus/common/releases) - [Commits](https://github.com/prometheus/common/compare/v0.44.0...v0.45.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 14 ++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 4ddfbfbe5..2cb4e8b74 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/lib/pq v1.10.9 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 - github.com/prometheus/common v0.44.0 + github.com/prometheus/common v0.45.0 github.com/prometheus/exporter-toolkit v0.10.0 github.com/smartystreets/goconvey v1.8.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c @@ -30,7 +30,7 @@ require ( github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/prometheus/procfs v0.11.1 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect @@ -38,7 +38,7 @@ require ( github.com/xhit/go-str2duration/v2 v2.1.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect diff --git a/go.sum b/go.sum index 3a163d16b..f438656ed 100644 --- a/go.sum +++ b/go.sum @@ -20,7 +20,6 @@ github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -42,8 +41,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -53,8 +52,8 @@ github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1 github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY= github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= @@ -77,9 +76,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= From 5ceae7f4142101e980bee04516b02995cef54fc2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 09:42:42 +0100 Subject: [PATCH 167/228] Bump github.com/prometheus/client_model (#949) Bumps [github.com/prometheus/client_model](https://github.com/prometheus/client_model) from 0.4.1-0.20230718164431-9a2bf3000d16 to 0.5.0. - [Release notes](https://github.com/prometheus/client_model/releases) - [Commits](https://github.com/prometheus/client_model/commits/v0.5.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_model dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2cb4e8b74..c6ef4f4c8 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/go-kit/log v0.2.1 github.com/lib/pq v1.10.9 github.com/prometheus/client_golang v1.17.0 - github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 + github.com/prometheus/client_model v0.5.0 github.com/prometheus/common v0.45.0 github.com/prometheus/exporter-toolkit v0.10.0 github.com/smartystreets/goconvey v1.8.1 diff --git a/go.sum b/go.sum index f438656ed..b54c147b6 100644 --- a/go.sum +++ b/go.sum @@ -50,8 +50,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= From f5b613aba78b73af4fa09609b22c781715e4d033 Mon Sep 17 00:00:00 2001 From: Jiri Sveceny Date: Tue, 28 Nov 2023 15:12:07 +0100 Subject: [PATCH 168/228] pg_stat_database: added support for `active_time` counter (#961) * feat(pg_stat_database): active time metric --------- Signed-off-by: Jiri Sveceny --- collector/pg_stat_database.go | 24 +++++++++++++++++++++++- collector/pg_stat_database_test.go | 17 +++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/collector/pg_stat_database.go b/collector/pg_stat_database.go index 328afee2c..ea7075303 100644 --- a/collector/pg_stat_database.go +++ b/collector/pg_stat_database.go @@ -206,6 +206,15 @@ var ( []string{"datid", "datname"}, prometheus.Labels{}, ) + statDatabaseActiveTime = prometheus.NewDesc(prometheus.BuildFQName( + namespace, + statDatabaseSubsystem, + "active_time_seconds_total", + ), + "Time spent executing SQL statements in this database, in seconds", + []string{"datid", "datname"}, + prometheus.Labels{}, + ) statDatabaseQuery = ` SELECT @@ -227,6 +236,7 @@ var ( ,deadlocks ,blk_read_time ,blk_write_time + ,active_time ,stats_reset FROM pg_stat_database; ` @@ -244,7 +254,7 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance for rows.Next() { var datid, datname sql.NullString - var numBackends, xactCommit, xactRollback, blksRead, blksHit, tupReturned, tupFetched, tupInserted, tupUpdated, tupDeleted, conflicts, tempFiles, tempBytes, deadlocks, blkReadTime, blkWriteTime sql.NullFloat64 + var numBackends, xactCommit, xactRollback, blksRead, blksHit, tupReturned, tupFetched, tupInserted, tupUpdated, tupDeleted, conflicts, tempFiles, tempBytes, deadlocks, blkReadTime, blkWriteTime, activeTime sql.NullFloat64 var statsReset sql.NullTime err := rows.Scan( @@ -266,6 +276,7 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance &deadlocks, &blkReadTime, &blkWriteTime, + &activeTime, &statsReset, ) if err != nil { @@ -344,6 +355,10 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blk_write_time") continue } + if !activeTime.Valid { + level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no active_time") + continue + } statsResetMetric := 0.0 if !statsReset.Valid { @@ -467,6 +482,13 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance labels..., ) + ch <- prometheus.MustNewConstMetric( + statDatabaseActiveTime, + prometheus.CounterValue, + activeTime.Float64/1000.0, + labels..., + ) + ch <- prometheus.MustNewConstMetric( statDatabaseStatsReset, prometheus.CounterValue, diff --git a/collector/pg_stat_database_test.go b/collector/pg_stat_database_test.go index fe1b17066..2d4c25cf4 100644 --- a/collector/pg_stat_database_test.go +++ b/collector/pg_stat_database_test.go @@ -52,6 +52,7 @@ func TestPGStatDatabaseCollector(t *testing.T) { "deadlocks", "blk_read_time", "blk_write_time", + "active_time", "stats_reset", } @@ -80,6 +81,7 @@ func TestPGStatDatabaseCollector(t *testing.T) { 925, 16, 823, + 33, srT) mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) @@ -113,6 +115,7 @@ func TestPGStatDatabaseCollector(t *testing.T) { {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.033}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, } @@ -159,6 +162,7 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { "deadlocks", "blk_read_time", "blk_write_time", + "active_time", "stats_reset", } @@ -182,6 +186,7 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { 925, 16, 823, + 32, srT). AddRow( "pid", @@ -202,6 +207,7 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { 925, 16, 823, + 32, srT) mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) @@ -234,6 +240,7 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.032}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, } @@ -275,6 +282,7 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { "deadlocks", "blk_read_time", "blk_write_time", + "active_time", "stats_reset", } @@ -303,6 +311,7 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { 925, 16, 823, + 14, srT). AddRow( nil, @@ -324,6 +333,7 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { nil, nil, nil, + nil, ). AddRow( "pid", @@ -344,6 +354,7 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { 926, 17, 824, + 15, srT) mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) @@ -376,7 +387,9 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.014}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_GAUGE, value: 355}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 4946}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 289097745}, @@ -393,6 +406,7 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 926}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 17}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 824}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.015}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, } @@ -435,6 +449,7 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) { "deadlocks", "blk_read_time", "blk_write_time", + "active_time", "stats_reset", } @@ -458,6 +473,7 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) { 925, 16, 823, + 7, nil) mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) @@ -491,6 +507,7 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) { {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.007}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0}, } From 825cc8af137ab882812dc20bb22e716f6a1623e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:10:42 -0500 Subject: [PATCH 169/228] Bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#988) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0. - [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index c6ef4f4c8..64d988fac 100644 --- a/go.mod +++ b/go.mod @@ -36,12 +36,12 @@ require ( github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.14.0 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.12.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/go.sum b/go.sum index b54c147b6..9ec365f73 100644 --- a/go.sum +++ b/go.sum @@ -71,8 +71,8 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= @@ -81,12 +81,12 @@ golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= From 9cfa1321158af0eb9f6b11d06eebd064e57c697b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 18:12:56 -0500 Subject: [PATCH 170/228] Bump github.com/prometheus/client_golang from 1.17.0 to 1.18.0 (#993) Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.17.0 to 1.18.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.17.0...v1.18.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 64d988fac..963ef770b 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 github.com/lib/pq v1.10.9 - github.com/prometheus/client_golang v1.17.0 + github.com/prometheus/client_golang v1.18.0 github.com/prometheus/client_model v0.5.0 github.com/prometheus/common v0.45.0 github.com/prometheus/exporter-toolkit v0.10.0 @@ -32,7 +32,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect diff --git a/go.sum b/go.sum index 9ec365f73..5322464b6 100644 --- a/go.sum +++ b/go.sum @@ -48,16 +48,16 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= -github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= From f98834a6782dc4d43c0d5b12a10f5f2292f02dc1 Mon Sep 17 00:00:00 2001 From: Keegan Carruthers-Smith Date: Wed, 14 Feb 2024 20:38:27 +0200 Subject: [PATCH 171/228] use Info level for excluded databases log message (#1003) This is the only log message which didn't specify a level in the postgres_exporter. I am unsure if this log message should be info or debug, but leaning towards the more important since previously it would just always log. The way I validated this was the only non-leveled logger was via grep. Both of these only returned this callsite previously: git grep 'logger\.Log' git grep '\.Log(' | grep -v level Signed-off-by: Keegan Carruthers-Smith --- cmd/postgres_exporter/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index 7d424b3d3..f4d454996 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -93,7 +93,7 @@ func main() { } excludedDatabases := strings.Split(*excludeDatabases, ",") - logger.Log("msg", "Excluded databases", "databases", fmt.Sprintf("%v", excludedDatabases)) + level.Info(logger).Log("msg", "Excluded databases", "databases", fmt.Sprintf("%v", excludedDatabases)) if *queriesPath != "" { level.Warn(logger).Log("msg", "The extended queries.yaml config is DEPRECATED", "file", *queriesPath) From 8f39f5b11424cc53bd26864d3630940a67e5ea27 Mon Sep 17 00:00:00 2001 From: Jocelyn Thode Date: Thu, 22 Feb 2024 03:10:17 +0100 Subject: [PATCH 172/228] Add connection limits metrics for pg_roles and pg_database (#997) * Add database connection limits metrics Signed-off-by: Jocelyn Thode * Add roles connection limits metrics Signed-off-by: Jocelyn Thode * Fix copyright year Co-authored-by: Joe Adams Signed-off-by: Jocelyn Thode * Fix spacing in pgDatabaseQuery Co-authored-by: Joe Adams Signed-off-by: Jocelyn Thode * Fix case on pgRolesConnectionLimitsQuery Co-authored-by: Joe Adams Signed-off-by: Jocelyn Thode * Do not add roleMetrics when row is not valid Signed-off-by: Jocelyn Thode --------- Signed-off-by: Jocelyn Thode Signed-off-by: Jocelyn Thode Co-authored-by: Joe Adams --- collector/pg_database.go | 31 ++++++++++-- collector/pg_database_test.go | 10 ++-- collector/pg_roles.go | 91 +++++++++++++++++++++++++++++++++++ collector/pg_roles_test.go | 58 ++++++++++++++++++++++ 4 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 collector/pg_roles.go create mode 100644 collector/pg_roles_test.go diff --git a/collector/pg_database.go b/collector/pg_database.go index d2c4b206a..30c4c8af0 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -53,12 +53,21 @@ var ( "Disk space used by the database", []string{"datname"}, nil, ) + pgDatabaseConnectionLimitsDesc = prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + databaseSubsystem, + "connection_limit", + ), + "Connection limit set for the database", + []string{"datname"}, nil, + ) - pgDatabaseQuery = "SELECT pg_database.datname FROM pg_database;" + pgDatabaseQuery = "SELECT pg_database.datname, pg_database.datconnlimit FROM pg_database;" pgDatabaseSizeQuery = "SELECT pg_database_size($1)" ) -// Update implements Collector and exposes database size. +// Update implements Collector and exposes database size and connection limits. // It is called by the Prometheus registry when collecting metrics. // The list of databases is retrieved from pg_database and filtered // by the excludeDatabase config parameter. The tradeoff here is that @@ -81,21 +90,32 @@ func (c PGDatabaseCollector) Update(ctx context.Context, instance *instance, ch for rows.Next() { var datname sql.NullString - if err := rows.Scan(&datname); err != nil { + var connLimit sql.NullInt64 + if err := rows.Scan(&datname, &connLimit); err != nil { return err } if !datname.Valid { continue } + database := datname.String // Ignore excluded databases // Filtering is done here instead of in the query to avoid // a complicated NOT IN query with a variable number of parameters - if sliceContains(c.excludedDatabases, datname.String) { + if sliceContains(c.excludedDatabases, database) { continue } - databases = append(databases, datname.String) + databases = append(databases, database) + + connLimitMetric := 0.0 + if connLimit.Valid { + connLimitMetric = float64(connLimit.Int64) + } + ch <- prometheus.MustNewConstMetric( + pgDatabaseConnectionLimitsDesc, + prometheus.GaugeValue, connLimitMetric, database, + ) } // Query the size of the databases @@ -114,6 +134,7 @@ func (c PGDatabaseCollector) Update(ctx context.Context, instance *instance, ch pgDatabaseSizeDesc, prometheus.GaugeValue, sizeMetric, datname, ) + } return rows.Err() } diff --git a/collector/pg_database_test.go b/collector/pg_database_test.go index b5052c5d1..fe94166e9 100644 --- a/collector/pg_database_test.go +++ b/collector/pg_database_test.go @@ -31,8 +31,8 @@ func TestPGDatabaseCollector(t *testing.T) { inst := &instance{db: db} - mock.ExpectQuery(sanitizeQuery(pgDatabaseQuery)).WillReturnRows(sqlmock.NewRows([]string{"datname"}). - AddRow("postgres")) + mock.ExpectQuery(sanitizeQuery(pgDatabaseQuery)).WillReturnRows(sqlmock.NewRows([]string{"datname", "datconnlimit"}). + AddRow("postgres", 15)) mock.ExpectQuery(sanitizeQuery(pgDatabaseSizeQuery)).WithArgs("postgres").WillReturnRows(sqlmock.NewRows([]string{"pg_database_size"}). AddRow(1024)) @@ -47,6 +47,7 @@ func TestPGDatabaseCollector(t *testing.T) { }() expected := []MetricResult{ + {labels: labelMap{"datname": "postgres"}, value: 15, metricType: dto.MetricType_GAUGE}, {labels: labelMap{"datname": "postgres"}, value: 1024, metricType: dto.MetricType_GAUGE}, } convey.Convey("Metrics comparison", t, func() { @@ -71,8 +72,8 @@ func TestPGDatabaseCollectorNullMetric(t *testing.T) { inst := &instance{db: db} - mock.ExpectQuery(sanitizeQuery(pgDatabaseQuery)).WillReturnRows(sqlmock.NewRows([]string{"datname"}). - AddRow("postgres")) + mock.ExpectQuery(sanitizeQuery(pgDatabaseQuery)).WillReturnRows(sqlmock.NewRows([]string{"datname", "datconnlimit"}). + AddRow("postgres", nil)) mock.ExpectQuery(sanitizeQuery(pgDatabaseSizeQuery)).WithArgs("postgres").WillReturnRows(sqlmock.NewRows([]string{"pg_database_size"}). AddRow(nil)) @@ -88,6 +89,7 @@ func TestPGDatabaseCollectorNullMetric(t *testing.T) { expected := []MetricResult{ {labels: labelMap{"datname": "postgres"}, value: 0, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"datname": "postgres"}, value: 0, metricType: dto.MetricType_GAUGE}, } convey.Convey("Metrics comparison", t, func() { for _, expect := range expected { diff --git a/collector/pg_roles.go b/collector/pg_roles.go new file mode 100644 index 000000000..609c34c33 --- /dev/null +++ b/collector/pg_roles.go @@ -0,0 +1,91 @@ +// Copyright 2024 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 collector + +import ( + "context" + "database/sql" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" +) + +const rolesSubsystem = "roles" + +func init() { + registerCollector(rolesSubsystem, defaultEnabled, NewPGRolesCollector) +} + +type PGRolesCollector struct { + log log.Logger +} + +func NewPGRolesCollector(config collectorConfig) (Collector, error) { + return &PGRolesCollector{ + log: config.logger, + }, nil +} + +var ( + pgRolesConnectionLimitsDesc = prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + rolesSubsystem, + "connection_limit", + ), + "Connection limit set for the role", + []string{"rolname"}, nil, + ) + + pgRolesConnectionLimitsQuery = "SELECT pg_roles.rolname, pg_roles.rolconnlimit FROM pg_roles" +) + +// Update implements Collector and exposes roles connection limits. +// It is called by the Prometheus registry when collecting metrics. +func (c PGRolesCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + // Query the list of databases + rows, err := db.QueryContext(ctx, + pgRolesConnectionLimitsQuery, + ) + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var rolname sql.NullString + var connLimit sql.NullInt64 + if err := rows.Scan(&rolname, &connLimit); err != nil { + return err + } + + if !rolname.Valid { + continue + } + rolnameLabel := rolname.String + + if !connLimit.Valid { + continue + } + connLimitMetric := float64(connLimit.Int64) + + ch <- prometheus.MustNewConstMetric( + pgRolesConnectionLimitsDesc, + prometheus.GaugeValue, connLimitMetric, rolnameLabel, + ) + } + + return rows.Err() +} diff --git a/collector/pg_roles_test.go b/collector/pg_roles_test.go new file mode 100644 index 000000000..182a120f9 --- /dev/null +++ b/collector/pg_roles_test.go @@ -0,0 +1,58 @@ +// Copyright 2023 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGRolesCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + mock.ExpectQuery(sanitizeQuery(pgRolesConnectionLimitsQuery)).WillReturnRows(sqlmock.NewRows([]string{"rolname", "rolconnlimit"}). + AddRow("postgres", 15)) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGRolesCollector{} + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGRolesCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"rolname": "postgres"}, value: 15, metricType: dto.MetricType_GAUGE}, + } + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From 838f09c97f35aaabace3d04c170bd449bda0099e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 22:03:36 -0500 Subject: [PATCH 173/228] Bump github.com/DATA-DOG/go-sqlmock from 1.5.0 to 1.5.2 (#1000) Bumps [github.com/DATA-DOG/go-sqlmock](https://github.com/DATA-DOG/go-sqlmock) from 1.5.0 to 1.5.2. - [Release notes](https://github.com/DATA-DOG/go-sqlmock/releases) - [Commits](https://github.com/DATA-DOG/go-sqlmock/compare/v1.5.0...v1.5.2) --- updated-dependencies: - dependency-name: github.com/DATA-DOG/go-sqlmock dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 963ef770b..2f8fb1a71 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/prometheus-community/postgres_exporter go 1.19 require ( - github.com/DATA-DOG/go-sqlmock v1.5.0 + github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/alecthomas/kingpin/v2 v2.3.2 github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 diff --git a/go.sum b/go.sum index 5322464b6..7b37e75e5 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU= github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= @@ -32,6 +32,7 @@ github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2E github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= From 89087f1744358ccb69336a0cac13f1a160c9e069 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 09:30:47 -0500 Subject: [PATCH 174/228] Bump github.com/prometheus/client_golang from 1.18.0 to 1.19.0 (#1011) Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.18.0 to 1.19.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/v1.19.0/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.18.0...v1.19.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 17 ++++++++--------- go.sum | 36 +++++++++++++++++------------------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 2f8fb1a71..5b729b5a9 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,13 @@ go 1.19 require ( github.com/DATA-DOG/go-sqlmock v1.5.2 - github.com/alecthomas/kingpin/v2 v2.3.2 + github.com/alecthomas/kingpin/v2 v2.4.0 github.com/blang/semver/v4 v4.0.0 github.com/go-kit/log v0.2.1 github.com/lib/pq v1.10.9 - github.com/prometheus/client_golang v1.18.0 + github.com/prometheus/client_golang v1.19.0 github.com/prometheus/client_model v0.5.0 - github.com/prometheus/common v0.45.0 + github.com/prometheus/common v0.48.0 github.com/prometheus/exporter-toolkit v0.10.0 github.com/smartystreets/goconvey v1.8.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c @@ -30,18 +30,17 @@ require ( github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.12.0 // indirect + golang.org/x/crypto v0.18.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/oauth2 v0.16.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect ) diff --git a/go.sum b/go.sum index 7b37e75e5..ac0315611 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= -github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU= -github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= +github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= 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= @@ -25,7 +25,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -42,19 +42,17 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= -github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= @@ -72,18 +70,18 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -94,8 +92,8 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From b126e621db083d4299120c02b157e0e13aafa7a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 10:36:40 -0500 Subject: [PATCH 175/228] Bump github.com/prometheus/client_model from 0.5.0 to 0.6.0 (#1010) Bumps [github.com/prometheus/client_model](https://github.com/prometheus/client_model) from 0.5.0 to 0.6.0. - [Release notes](https://github.com/prometheus/client_model/releases) - [Commits](https://github.com/prometheus/client_model/compare/v0.5.0...v0.6.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_model dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5b729b5a9..e22461dd0 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/go-kit/log v0.2.1 github.com/lib/pq v1.10.9 github.com/prometheus/client_golang v1.19.0 - github.com/prometheus/client_model v0.5.0 + github.com/prometheus/client_model v0.6.0 github.com/prometheus/common v0.48.0 github.com/prometheus/exporter-toolkit v0.10.0 github.com/smartystreets/goconvey v1.8.1 diff --git a/go.sum b/go.sum index ac0315611..da46c9d16 100644 --- a/go.sum +++ b/go.sum @@ -49,8 +49,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= From 5ffc58cd28fc9c3f0c8411e48b00db11735109ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 22:19:36 -0400 Subject: [PATCH 176/228] Bump google.golang.org/protobuf from 1.32.0 to 1.33.0 (#1014) Bumps google.golang.org/protobuf from 1.32.0 to 1.33.0. --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e22461dd0..d5a6a29e4 100644 --- a/go.mod +++ b/go.mod @@ -42,5 +42,5 @@ require ( golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect ) diff --git a/go.sum b/go.sum index da46c9d16..a2f1ed8f6 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,8 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From ddd51368a104112a355d2bde010ac5e2edf4ba6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 12:25:56 +0100 Subject: [PATCH 177/228] Bump github.com/prometheus/exporter-toolkit from 0.10.0 to 0.11.0 (#992) Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.10.0 to 0.11.0. - [Release notes](https://github.com/prometheus/exporter-toolkit/releases) - [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md) - [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.10.0...v0.11.0) --- updated-dependencies: - dependency-name: github.com/prometheus/exporter-toolkit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index d5a6a29e4..d45f3ba2e 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/prometheus/client_golang v1.19.0 github.com/prometheus/client_model v0.6.0 github.com/prometheus/common v0.48.0 - github.com/prometheus/exporter-toolkit v0.10.0 + github.com/prometheus/exporter-toolkit v0.11.0 github.com/smartystreets/goconvey v1.8.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 @@ -38,7 +38,7 @@ require ( golang.org/x/crypto v0.18.0 // indirect golang.org/x/net v0.20.0 // indirect golang.org/x/oauth2 v0.16.0 // indirect - golang.org/x/sync v0.3.0 // indirect + golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index a2f1ed8f6..7075a8f91 100644 --- a/go.sum +++ b/go.sum @@ -53,8 +53,8 @@ github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZ github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= -github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= -github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY= +github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g= +github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -77,8 +77,8 @@ golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= From cc0fd2eda512ab5885de6da18aff42adcd0e02b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Apr 2024 15:39:52 -0400 Subject: [PATCH 178/228] Bump golang.org/x/net from 0.20.0 to 0.23.0 (#1021) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.20.0 to 0.23.0. - [Commits](https://github.com/golang/net/compare/v0.20.0...v0.23.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index d45f3ba2e..e937de61d 100644 --- a/go.mod +++ b/go.mod @@ -35,11 +35,11 @@ require ( github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.18.0 // indirect - golang.org/x/net v0.20.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/oauth2 v0.16.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/go.sum b/go.sum index 7075a8f91..687657eaf 100644 --- a/go.sum +++ b/go.sum @@ -70,18 +70,18 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= From a4ac0e674769805a9b282edb9a7791e64cd977e3 Mon Sep 17 00:00:00 2001 From: Marc W <113890636+MarcWort@users.noreply.github.com> Date: Sat, 11 May 2024 14:59:55 +0200 Subject: [PATCH 179/228] feat: Add safe_wal_size and wal_status to replication_slot (#1027) * feat: Add safe_wal_size to replication_slot Signed-off-by: MarcWort <113890636+MarcWort@users.noreply.github.com> * feat: Add wal_status to replication_slot Signed-off-by: MarcWort <113890636+MarcWort@users.noreply.github.com> --------- Signed-off-by: MarcWort <113890636+MarcWort@users.noreply.github.com> --- collector/pg_replication_slot.go | 40 +++++++++++++++++++++++++-- collector/pg_replication_slot_test.go | 21 ++++++++------ 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/collector/pg_replication_slot.go b/collector/pg_replication_slot.go index 7f1ba003e..1d29f8498 100644 --- a/collector/pg_replication_slot.go +++ b/collector/pg_replication_slot.go @@ -63,6 +63,24 @@ var ( "whether the replication slot is active or not", []string{"slot_name", "slot_type"}, nil, ) + pgReplicationSlotSafeWal = prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + replicationSlotSubsystem, + "safe_wal_size_bytes", + ), + "number of bytes that can be written to WAL such that this slot is not in danger of getting in state lost", + []string{"slot_name", "slot_type"}, nil, + ) + pgReplicationSlotWalStatus = prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + replicationSlotSubsystem, + "wal_status", + ), + "availability of WAL files claimed by this slot", + []string{"slot_name", "slot_type", "wal_status"}, nil, + ) pgReplicationSlotQuery = `SELECT slot_name, @@ -73,7 +91,9 @@ var ( pg_current_wal_lsn() - '0/0' END AS current_wal_lsn, COALESCE(confirmed_flush_lsn, '0/0') - '0/0' AS confirmed_flush_lsn, - active + active, + safe_wal_size, + wal_status FROM pg_replication_slots;` ) @@ -92,7 +112,9 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance var walLSN sql.NullFloat64 var flushLSN sql.NullFloat64 var isActive sql.NullBool - if err := rows.Scan(&slotName, &slotType, &walLSN, &flushLSN, &isActive); err != nil { + var safeWalSize sql.NullInt64 + var walStatus sql.NullString + if err := rows.Scan(&slotName, &slotType, &walLSN, &flushLSN, &isActive, &safeWalSize, &walStatus); err != nil { return err } @@ -131,6 +153,20 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance pgReplicationSlotIsActiveDesc, prometheus.GaugeValue, isActiveValue, slotNameLabel, slotTypeLabel, ) + + if safeWalSize.Valid { + ch <- prometheus.MustNewConstMetric( + pgReplicationSlotSafeWal, + prometheus.GaugeValue, float64(safeWalSize.Int64), slotNameLabel, slotTypeLabel, + ) + } + + if walStatus.Valid { + ch <- prometheus.MustNewConstMetric( + pgReplicationSlotWalStatus, + prometheus.GaugeValue, 1, slotNameLabel, slotTypeLabel, walStatus.String, + ) + } } return rows.Err() } diff --git a/collector/pg_replication_slot_test.go b/collector/pg_replication_slot_test.go index 212050c46..174743ac3 100644 --- a/collector/pg_replication_slot_test.go +++ b/collector/pg_replication_slot_test.go @@ -31,9 +31,9 @@ func TestPgReplicationSlotCollectorActive(t *testing.T) { inst := &instance{db: db} - columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active"} + columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active", "safe_wal_size", "wal_status"} rows := sqlmock.NewRows(columns). - AddRow("test_slot", "physical", 5, 3, true) + AddRow("test_slot", "physical", 5, 3, true, 323906992, "reserved") mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -50,6 +50,8 @@ func TestPgReplicationSlotCollectorActive(t *testing.T) { {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 5, metricType: dto.MetricType_GAUGE}, {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 3, metricType: dto.MetricType_GAUGE}, {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 1, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 323906992, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical", "wal_status": "reserved"}, value: 1, metricType: dto.MetricType_GAUGE}, } convey.Convey("Metrics comparison", t, func() { @@ -72,9 +74,9 @@ func TestPgReplicationSlotCollectorInActive(t *testing.T) { inst := &instance{db: db} - columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active"} + columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active", "safe_wal_size", "wal_status"} rows := sqlmock.NewRows(columns). - AddRow("test_slot", "physical", 6, 12, false) + AddRow("test_slot", "physical", 6, 12, false, -4000, "extended") mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -90,6 +92,8 @@ func TestPgReplicationSlotCollectorInActive(t *testing.T) { expected := []MetricResult{ {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 6, metricType: dto.MetricType_GAUGE}, {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 0, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: -4000, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical", "wal_status": "extended"}, value: 1, metricType: dto.MetricType_GAUGE}, } convey.Convey("Metrics comparison", t, func() { @@ -113,9 +117,9 @@ func TestPgReplicationSlotCollectorActiveNil(t *testing.T) { inst := &instance{db: db} - columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active"} + columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active", "safe_wal_size", "wal_status"} rows := sqlmock.NewRows(columns). - AddRow("test_slot", "physical", 6, 12, nil) + AddRow("test_slot", "physical", 6, 12, nil, nil, "lost") mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -131,6 +135,7 @@ func TestPgReplicationSlotCollectorActiveNil(t *testing.T) { expected := []MetricResult{ {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 6, metricType: dto.MetricType_GAUGE}, {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical"}, value: 0, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{"slot_name": "test_slot", "slot_type": "physical", "wal_status": "lost"}, value: 1, metricType: dto.MetricType_GAUGE}, } convey.Convey("Metrics comparison", t, func() { @@ -153,9 +158,9 @@ func TestPgReplicationSlotCollectorTestNilValues(t *testing.T) { inst := &instance{db: db} - columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active"} + columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active", "safe_wal_size", "wal_status"} rows := sqlmock.NewRows(columns). - AddRow(nil, nil, nil, nil, true) + AddRow(nil, nil, nil, nil, true, nil, nil) mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) From 49f66e1bfb6aaab064b8a5bf861e22034d1d2b4b Mon Sep 17 00:00:00 2001 From: Marc W <113890636+MarcWort@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:15:21 +0200 Subject: [PATCH 180/228] fix: Only query active_time on pg>=14 (#1045) Signed-off-by: MarcWort <113890636+MarcWort@users.noreply.github.com> --- collector/pg_stat_database.go | 91 ++++++++++++++++++------------ collector/pg_stat_database_test.go | 53 +++++++++-------- 2 files changed, 84 insertions(+), 60 deletions(-) diff --git a/collector/pg_stat_database.go b/collector/pg_stat_database.go index ea7075303..b3cb59eb2 100644 --- a/collector/pg_stat_database.go +++ b/collector/pg_stat_database.go @@ -16,7 +16,10 @@ package collector import ( "context" "database/sql" + "fmt" + "strings" + "github.com/blang/semver/v4" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" @@ -215,37 +218,44 @@ var ( []string{"datid", "datname"}, prometheus.Labels{}, ) - - statDatabaseQuery = ` - SELECT - datid - ,datname - ,numbackends - ,xact_commit - ,xact_rollback - ,blks_read - ,blks_hit - ,tup_returned - ,tup_fetched - ,tup_inserted - ,tup_updated - ,tup_deleted - ,conflicts - ,temp_files - ,temp_bytes - ,deadlocks - ,blk_read_time - ,blk_write_time - ,active_time - ,stats_reset - FROM pg_stat_database; - ` ) +func statDatabaseQuery(columns []string) string { + return fmt.Sprintf("SELECT %s FROM pg_stat_database;", strings.Join(columns, ",")) +} + func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { db := instance.getDB() + + columns := []string{ + "datid", + "datname", + "numbackends", + "xact_commit", + "xact_rollback", + "blks_read", + "blks_hit", + "tup_returned", + "tup_fetched", + "tup_inserted", + "tup_updated", + "tup_deleted", + "conflicts", + "temp_files", + "temp_bytes", + "deadlocks", + "blk_read_time", + "blk_write_time", + "stats_reset", + } + + activeTimeAvail := instance.version.GTE(semver.MustParse("14.0.0")) + if activeTimeAvail { + columns = append(columns, "active_time") + } + rows, err := db.QueryContext(ctx, - statDatabaseQuery, + statDatabaseQuery(columns), ) if err != nil { return err @@ -257,7 +267,7 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance var numBackends, xactCommit, xactRollback, blksRead, blksHit, tupReturned, tupFetched, tupInserted, tupUpdated, tupDeleted, conflicts, tempFiles, tempBytes, deadlocks, blkReadTime, blkWriteTime, activeTime sql.NullFloat64 var statsReset sql.NullTime - err := rows.Scan( + r := []any{ &datid, &datname, &numBackends, @@ -276,9 +286,14 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance &deadlocks, &blkReadTime, &blkWriteTime, - &activeTime, &statsReset, - ) + } + + if activeTimeAvail { + r = append(r, &activeTime) + } + + err := rows.Scan(r...) if err != nil { return err } @@ -355,7 +370,7 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blk_write_time") continue } - if !activeTime.Valid { + if activeTimeAvail && !activeTime.Valid { level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no active_time") continue } @@ -482,19 +497,21 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance labels..., ) - ch <- prometheus.MustNewConstMetric( - statDatabaseActiveTime, - prometheus.CounterValue, - activeTime.Float64/1000.0, - labels..., - ) - ch <- prometheus.MustNewConstMetric( statDatabaseStatsReset, prometheus.CounterValue, statsResetMetric, labels..., ) + + if activeTimeAvail { + ch <- prometheus.MustNewConstMetric( + statDatabaseActiveTime, + prometheus.CounterValue, + activeTime.Float64/1000.0, + labels..., + ) + } } return nil } diff --git a/collector/pg_stat_database_test.go b/collector/pg_stat_database_test.go index 2d4c25cf4..924612082 100644 --- a/collector/pg_stat_database_test.go +++ b/collector/pg_stat_database_test.go @@ -18,6 +18,7 @@ import ( "time" "github.com/DATA-DOG/go-sqlmock" + "github.com/blang/semver/v4" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" @@ -31,7 +32,7 @@ func TestPGStatDatabaseCollector(t *testing.T) { } defer db.Close() - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("14.0.0")} columns := []string{ "datid", @@ -52,8 +53,8 @@ func TestPGStatDatabaseCollector(t *testing.T) { "deadlocks", "blk_read_time", "blk_write_time", - "active_time", "stats_reset", + "active_time", } srT, err := time.Parse("2006-01-02 15:04:05.00000-07", "2023-05-25 17:10:42.81132-07") @@ -81,10 +82,11 @@ func TestPGStatDatabaseCollector(t *testing.T) { 925, 16, 823, + srT, 33, - srT) + ) - mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(statDatabaseQuery(columns))).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -115,8 +117,8 @@ func TestPGStatDatabaseCollector(t *testing.T) { {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, - {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.033}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.033}, } convey.Convey("Metrics comparison", t, func() { @@ -141,7 +143,7 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { if err != nil { t.Fatalf("Error parsing time: %s", err) } - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("14.0.0")} columns := []string{ "datid", @@ -162,8 +164,8 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { "deadlocks", "blk_read_time", "blk_write_time", - "active_time", "stats_reset", + "active_time", } rows := sqlmock.NewRows(columns). @@ -186,8 +188,9 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { 925, 16, 823, + srT, 32, - srT). + ). AddRow( "pid", "postgres", @@ -207,9 +210,10 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { 925, 16, 823, + srT, 32, - srT) - mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) + ) + mock.ExpectQuery(sanitizeQuery(statDatabaseQuery(columns))).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -240,8 +244,8 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, - {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.032}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.032}, } convey.Convey("Metrics comparison", t, func() { @@ -261,7 +265,7 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { } defer db.Close() - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("14.0.0")} columns := []string{ "datid", @@ -282,8 +286,8 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { "deadlocks", "blk_read_time", "blk_write_time", - "active_time", "stats_reset", + "active_time", } srT, err := time.Parse("2006-01-02 15:04:05.00000-07", "2023-05-25 17:10:42.81132-07") @@ -311,8 +315,9 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { 925, 16, 823, + srT, 14, - srT). + ). AddRow( nil, nil, @@ -354,9 +359,10 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { 926, 17, 824, + srT, 15, - srT) - mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) + ) + mock.ExpectQuery(sanitizeQuery(statDatabaseQuery(columns))).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -387,8 +393,8 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, - {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.014}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.014}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_GAUGE, value: 355}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 4946}, @@ -406,8 +412,8 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 926}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 17}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 824}, - {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.015}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 1685059842}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.015}, } convey.Convey("Metrics comparison", t, func() { @@ -428,7 +434,7 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) { } defer db.Close() - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("14.0.0")} columns := []string{ "datid", @@ -449,8 +455,8 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) { "deadlocks", "blk_read_time", "blk_write_time", - "active_time", "stats_reset", + "active_time", } rows := sqlmock.NewRows(columns). @@ -473,10 +479,11 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) { 925, 16, 823, + nil, 7, - nil) + ) - mock.ExpectQuery(sanitizeQuery(statDatabaseQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(statDatabaseQuery(columns))).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -507,8 +514,8 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) { {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 925}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 16}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 823}, - {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.007}, {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datid": "pid", "datname": "postgres"}, metricType: dto.MetricType_COUNTER, value: 0.007}, } convey.Convey("Metrics comparison", t, func() { From 3c5ef40e2b3e44fc86bd8ed9cde3e921008c1b73 Mon Sep 17 00:00:00 2001 From: fhackenberger Date: Sat, 6 Jul 2024 18:36:52 +0200 Subject: [PATCH 181/228] Update README.md (#1038) Better example for the quick start with prometheus config and avoiding deprecated env variables. Signed-off-by: fhackenberger --- README.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 429058e6d..4c464e210 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,29 @@ docker run --net=host -it --rm -e POSTGRES_PASSWORD=password postgres # Connect to it docker run \ --net=host \ - -e DATA_SOURCE_NAME="postgresql://postgres:password@localhost:5432/postgres?sslmode=disable" \ + -e DATA_SOURCE_URI="localhost:5432/postgres?sslmode=disable" \ + -e DATA_SOURCE_USER=postgres \ + -e DATA_SOURCE_PASS=password \ quay.io/prometheuscommunity/postgres-exporter ``` +Test with: +```bash +curl "http://localhost:9187/metrics" +``` + +Example Prometheus config: +```yaml +scrape_configs: + - job_name: postgres + static_configs: + - targets: ["127.0.0.1:9187"] # Replace IP with the hostname of the docker container if you're running the container in a separate network +``` + +Now use the DATA_SOURCE_PASS_FILE with a mounted file containing the password to prevent having the password in an environment variable. + +The container process runs with uid/gid 65534 (important for file permissions). + ## Multi-Target Support (BETA) **This Feature is in beta and may require changes in future releases. Feedback is welcome.** @@ -208,7 +227,7 @@ The following environment variables configure the exporter: * `DATA_SOURCE_URI` an alternative to `DATA_SOURCE_NAME` which exclusively accepts the hostname without a username and password component. For example, `my_pg_hostname` or - `my_pg_hostname?sslmode=disable`. + `my_pg_hostname:5432/postgres?sslmode=disable`. * `DATA_SOURCE_URI_FILE` The same as above but reads the URI from a file. From 98f75c7e7ea3a02b974cfeda736cf7dbc091b18e Mon Sep 17 00:00:00 2001 From: Steffen Zieger Date: Thu, 5 Sep 2024 15:28:31 +0200 Subject: [PATCH 182/228] stop logging errors on replicas, fixes #547 (#1048) Signed-off-by: Steffen Zieger --- cmd/postgres_exporter/queries.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/cmd/postgres_exporter/queries.go b/cmd/postgres_exporter/queries.go index fa0b5c272..9ca91e287 100644 --- a/cmd/postgres_exporter/queries.go +++ b/cmd/postgres_exporter/queries.go @@ -51,9 +51,9 @@ var queryOverrides = map[string][]OverrideQuery{ semver.MustParseRange(">=10.0.0"), ` SELECT *, - (case pg_is_in_recovery() when 't' then null else pg_current_wal_lsn() end) AS pg_current_wal_lsn, - (case pg_is_in_recovery() when 't' then null else pg_wal_lsn_diff(pg_current_wal_lsn(), pg_lsn('0/0'))::float end) AS pg_current_wal_lsn_bytes, - (case pg_is_in_recovery() when 't' then null else pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)::float end) AS pg_wal_lsn_diff + (case pg_is_in_recovery() when 't' then pg_last_wal_receive_lsn() else pg_current_wal_lsn() end) AS pg_current_wal_lsn, + (case pg_is_in_recovery() when 't' then pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_lsn('0/0'))::float else pg_wal_lsn_diff(pg_current_wal_lsn(), pg_lsn('0/0'))::float end) AS pg_current_wal_lsn_bytes, + (case pg_is_in_recovery() when 't' then pg_wal_lsn_diff(pg_last_wal_receive_lsn(), replay_lsn)::float else pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)::float end) AS pg_wal_lsn_diff FROM pg_stat_replication `, }, @@ -61,8 +61,8 @@ var queryOverrides = map[string][]OverrideQuery{ semver.MustParseRange(">=9.2.0 <10.0.0"), ` SELECT *, - (case pg_is_in_recovery() when 't' then null else pg_current_xlog_location() end) AS pg_current_xlog_location, - (case pg_is_in_recovery() when 't' then null else pg_xlog_location_diff(pg_current_xlog_location(), replay_location)::float end) AS pg_xlog_location_diff + (case pg_is_in_recovery() when 't' then pg_last_xlog_receive_location() else pg_current_xlog_location() end) AS pg_current_xlog_location, + (case pg_is_in_recovery() when 't' then pg_xlog_location_diff(pg_last_xlog_receive_location(), replay_location)::float else pg_xlog_location_diff(pg_current_xlog_location(), replay_location)::float end) AS pg_xlog_location_diff FROM pg_stat_replication `, }, @@ -70,7 +70,7 @@ var queryOverrides = map[string][]OverrideQuery{ semver.MustParseRange("<9.2.0"), ` SELECT *, - (case pg_is_in_recovery() when 't' then null else pg_current_xlog_location() end) AS pg_current_xlog_location + (case pg_is_in_recovery() when 't' then pg_last_xlog_receive_location() else pg_current_xlog_location() end) AS pg_current_xlog_location FROM pg_stat_replication `, }, @@ -80,14 +80,16 @@ var queryOverrides = map[string][]OverrideQuery{ { semver.MustParseRange(">=9.4.0 <10.0.0"), ` - SELECT slot_name, database, active, pg_xlog_location_diff(pg_current_xlog_location(), restart_lsn) + SELECT slot_name, database, active, + (case pg_is_in_recovery() when 't' then pg_xlog_location_diff(pg_last_xlog_receive_location(), restart_lsn) else pg_xlog_location_diff(pg_current_xlog_location(), restart_lsn) end) as pg_xlog_location_diff FROM pg_replication_slots `, }, { semver.MustParseRange(">=10.0.0"), ` - SELECT slot_name, database, active, pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) + SELECT slot_name, database, active, + (case pg_is_in_recovery() when 't' then pg_wal_lsn_diff(pg_last_wal_receive_lsn(), restart_lsn) else pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) end) as pg_wal_lsn_diff FROM pg_replication_slots `, }, From 3be4edccd4df8f73c4692049d7785e69498f9296 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Thu, 17 Oct 2024 17:47:21 +0200 Subject: [PATCH 183/228] Update common Prometheus files (#983) Signed-off-by: prombot --- Makefile.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.common b/Makefile.common index 062a28185..bc2a07d72 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.54.2 +GOLANGCI_LINT_VERSION ?= v1.55.2 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) From 3743987494352bba3739339952a9f62b87f40315 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Sat, 26 Oct 2024 16:37:52 +0200 Subject: [PATCH 184/228] Update common Prometheus files (#1076) Signed-off-by: prombot --- .github/workflows/container_description.yml | 57 +++++++++++++++++++++ .github/workflows/golangci-lint.yml | 19 ++++--- .yamllint | 2 + Makefile.common | 32 ++++++++---- 4 files changed, 95 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/container_description.yml diff --git a/.github/workflows/container_description.yml b/.github/workflows/container_description.yml new file mode 100644 index 000000000..144859486 --- /dev/null +++ b/.github/workflows/container_description.yml @@ -0,0 +1,57 @@ +--- +name: Push README to Docker Hub +on: + push: + paths: + - "README.md" + - "README-containers.md" + - ".github/workflows/container_description.yml" + branches: [ main, master ] + +permissions: + contents: read + +jobs: + PushDockerHubReadme: + runs-on: ubuntu-latest + name: Push README to Docker Hub + if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks. + steps: + - name: git checkout + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - name: Set docker hub repo name + run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV + - name: Push README to Dockerhub + uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1 + env: + DOCKER_USER: ${{ secrets.DOCKER_HUB_LOGIN }} + DOCKER_PASS: ${{ secrets.DOCKER_HUB_PASSWORD }} + with: + destination_container_repo: ${{ env.DOCKER_REPO_NAME }} + provider: dockerhub + short_description: ${{ env.DOCKER_REPO_NAME }} + # Empty string results in README-containers.md being pushed if it + # exists. Otherwise, README.md is pushed. + readme_file: '' + + PushQuayIoReadme: + runs-on: ubuntu-latest + name: Push README to quay.io + if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks. + steps: + - name: git checkout + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - name: Set quay.io org name + run: echo "DOCKER_REPO=$(echo quay.io/${GITHUB_REPOSITORY_OWNER} | tr -d '-')" >> $GITHUB_ENV + - name: Set quay.io repo name + run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV + - name: Push README to quay.io + uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1 + env: + DOCKER_APIKEY: ${{ secrets.QUAY_IO_API_TOKEN }} + with: + destination_container_repo: ${{ env.DOCKER_REPO_NAME }} + provider: quay + # Empty string results in README-containers.md being pushed if it + # exists. Otherwise, README.md is pushed. + readme_file: '' diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index ffa6b3090..1c099932b 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -12,21 +12,28 @@ on: - ".golangci.yml" pull_request: +permissions: # added using https://github.com/step-security/secure-repo + contents: read + jobs: golangci: + permissions: + contents: read # for actions/checkout to fetch code + pull-requests: read # for golangci/golangci-lint-action to fetch pull requests name: lint runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: install Go - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + - name: Install Go + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: - go-version: 1.21.x + go-version: 1.23.x - name: Install snmp_exporter/generator dependencies run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 + uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0 with: - version: v1.54.2 + args: --verbose + version: v1.60.2 diff --git a/.yamllint b/.yamllint index 955a5a627..1859cb624 100644 --- a/.yamllint +++ b/.yamllint @@ -1,5 +1,7 @@ --- extends: default +ignore: | + ui/react-app/node_modules rules: braces: diff --git a/Makefile.common b/Makefile.common index bc2a07d72..cbb5d8638 100644 --- a/Makefile.common +++ b/Makefile.common @@ -49,23 +49,23 @@ endif GOTEST := $(GO) test GOTEST_DIR := ifneq ($(CIRCLE_JOB),) -ifneq ($(shell command -v gotestsum > /dev/null),) +ifneq ($(shell command -v gotestsum 2> /dev/null),) GOTEST_DIR := test-results GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml -- endif endif -PROMU_VERSION ?= 0.15.0 +PROMU_VERSION ?= 0.17.0 PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.55.2 -# golangci-lint only supports linux, darwin and windows platforms on i386/amd64. +GOLANGCI_LINT_VERSION ?= v1.60.2 +# golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) - ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) + ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386 arm64)) # If we're in CI and there is an Actions file, that means the linter # is being run in Actions, so we don't need to run it here. ifneq (,$(SKIP_GOLANGCI_LINT)) @@ -169,16 +169,20 @@ common-vet: common-lint: $(GOLANGCI_LINT) ifdef GOLANGCI_LINT @echo ">> running golangci-lint" -# 'go list' needs to be executed before staticcheck to prepopulate the modules cache. -# Otherwise staticcheck might fail randomly for some reason not yet explained. - $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) endif +.PHONY: common-lint-fix +common-lint-fix: $(GOLANGCI_LINT) +ifdef GOLANGCI_LINT + @echo ">> running golangci-lint fix" + $(GOLANGCI_LINT) run --fix $(GOLANGCI_LINT_OPTS) $(pkgs) +endif + .PHONY: common-yamllint common-yamllint: @echo ">> running yamllint on all YAML files in the repository" -ifeq (, $(shell command -v yamllint > /dev/null)) +ifeq (, $(shell command -v yamllint 2> /dev/null)) @echo "yamllint not installed so skipping" else yamllint . @@ -204,6 +208,10 @@ common-tarball: promu @echo ">> building release tarball" $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) +.PHONY: common-docker-repo-name +common-docker-repo-name: + @echo "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)" + .PHONY: common-docker $(BUILD_DOCKER_ARCHS) common-docker: $(BUILD_DOCKER_ARCHS) $(BUILD_DOCKER_ARCHS): common-docker-%: @@ -267,3 +275,9 @@ $(1)_precheck: exit 1; \ fi endef + +govulncheck: install-govulncheck + govulncheck ./... + +install-govulncheck: + command -v govulncheck > /dev/null || go install golang.org/x/vuln/cmd/govulncheck@latest From e8540767e4de423ca03eeb3b6e633cf3a95bbd42 Mon Sep 17 00:00:00 2001 From: TJ Hoplock <33664289+tjhop@users.noreply.github.com> Date: Sat, 26 Oct 2024 15:44:17 -0400 Subject: [PATCH 185/228] chore!: adopt log/slog, drop go-kit/log (#1073) * ci: update go to version 1.23 Signed-off-by: TJ Hoplock * build(deps): bump prometheus/{client_golang,common,exporter-toolkit} Signed-off-by: TJ Hoplock * chore!: adopt log/slog, drop go-kit/log The bulk of this change set was automated by the following script which is being used to aid in converting the various exporters/projects to use slog: https://gist.github.com/tjhop/49f96fb7ebbe55b12deee0b0312d8434 Signed-off-by: TJ Hoplock --------- Signed-off-by: TJ Hoplock Co-authored-by: Ben Kochie --- .circleci/config.yml | 4 +- .promu.yml | 2 +- cmd/postgres_exporter/datasource.go | 11 ++- cmd/postgres_exporter/main.go | 35 +++++---- cmd/postgres_exporter/namespace.go | 11 ++- cmd/postgres_exporter/pg_setting.go | 3 +- cmd/postgres_exporter/postgres_exporter.go | 21 +++--- cmd/postgres_exporter/probe.go | 13 ++-- cmd/postgres_exporter/queries.go | 13 ++-- cmd/postgres_exporter/server.go | 7 +- cmd/postgres_exporter/util.go | 9 +-- collector/collector.go | 21 +++--- collector/pg_database.go | 4 +- collector/pg_database_wraparound.go | 11 ++- collector/pg_locks.go | 4 +- collector/pg_long_running_transactions.go | 4 +- collector/pg_process_idle.go | 4 +- collector/pg_replication_slot.go | 4 +- collector/pg_roles.go | 4 +- collector/pg_stat_activity_autovacuum.go | 4 +- collector/pg_stat_database.go | 45 ++++++----- collector/pg_stat_database_test.go | 10 +-- collector/pg_stat_statements.go | 4 +- collector/pg_stat_user_tables.go | 4 +- collector/pg_stat_walreceiver.go | 29 ++++---- collector/pg_statio_user_indexes.go | 4 +- collector/pg_statio_user_tables.go | 4 +- collector/pg_xlog_location.go | 7 +- collector/probe.go | 11 ++- config/config.go | 4 +- go.mod | 36 ++++----- go.sum | 87 ++++++++++------------ 32 files changed, 206 insertions(+), 228 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 98099e295..d745e30f2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,7 +8,7 @@ executors: # This must match .promu.yml. golang: docker: - - image: cimg/go:1.21 + - image: cimg/go:1.23 jobs: test: @@ -23,7 +23,7 @@ jobs: integration: docker: - - image: cimg/go:1.20 + - image: cimg/go:1.23 - image: << parameters.postgres_image >> environment: POSTGRES_DB: circle_test diff --git a/.promu.yml b/.promu.yml index dbad0ba95..c2b361240 100644 --- a/.promu.yml +++ b/.promu.yml @@ -1,6 +1,6 @@ go: # This must match .circle/config.yml. - version: 1.21 + version: 1.23 repository: path: github.com/prometheus-community/postgres_exporter build: diff --git a/cmd/postgres_exporter/datasource.go b/cmd/postgres_exporter/datasource.go index 0b8cef04a..7a22e177c 100644 --- a/cmd/postgres_exporter/datasource.go +++ b/cmd/postgres_exporter/datasource.go @@ -20,7 +20,6 @@ import ( "regexp" "strings" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) @@ -39,19 +38,19 @@ func (e *Exporter) discoverDatabaseDSNs() []string { var err error dsnURI, err = url.Parse(dsn) if err != nil { - level.Error(logger).Log("msg", "Unable to parse DSN as URI", "dsn", loggableDSN(dsn), "err", err) + logger.Error("Unable to parse DSN as URI", "dsn", loggableDSN(dsn), "err", err) continue } } else if connstringRe.MatchString(dsn) { dsnConnstring = dsn } else { - level.Error(logger).Log("msg", "Unable to parse DSN as either URI or connstring", "dsn", loggableDSN(dsn)) + logger.Error("Unable to parse DSN as either URI or connstring", "dsn", loggableDSN(dsn)) continue } server, err := e.servers.GetServer(dsn) if err != nil { - level.Error(logger).Log("msg", "Error opening connection to database", "dsn", loggableDSN(dsn), "err", err) + logger.Error("Error opening connection to database", "dsn", loggableDSN(dsn), "err", err) continue } dsns[dsn] = struct{}{} @@ -61,7 +60,7 @@ func (e *Exporter) discoverDatabaseDSNs() []string { databaseNames, err := queryDatabases(server) if err != nil { - level.Error(logger).Log("msg", "Error querying databases", "dsn", loggableDSN(dsn), "err", err) + logger.Error("Error querying databases", "dsn", loggableDSN(dsn), "err", err) continue } for _, databaseName := range databaseNames { @@ -109,7 +108,7 @@ func (e *Exporter) scrapeDSN(ch chan<- prometheus.Metric, dsn string) error { // Check if map versions need to be updated if err := e.checkMapVersions(ch, server); err != nil { - level.Warn(logger).Log("msg", "Proceeding with outdated query maps, as the Postgres version could not be determined", "err", err) + logger.Warn("Proceeding with outdated query maps, as the Postgres version could not be determined", "err", err) } return server.Scrape(ch, e.disableSettingsMetrics) diff --git a/cmd/postgres_exporter/main.go b/cmd/postgres_exporter/main.go index f4d454996..093ddd301 100644 --- a/cmd/postgres_exporter/main.go +++ b/cmd/postgres_exporter/main.go @@ -20,14 +20,13 @@ import ( "strings" "github.com/alecthomas/kingpin/v2" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus-community/postgres_exporter/collector" "github.com/prometheus-community/postgres_exporter/config" "github.com/prometheus/client_golang/prometheus" + versioncollector "github.com/prometheus/client_golang/prometheus/collectors/version" "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/prometheus/common/promlog" - "github.com/prometheus/common/promlog/flag" + "github.com/prometheus/common/promslog" + "github.com/prometheus/common/promslog/flag" "github.com/prometheus/common/version" "github.com/prometheus/exporter-toolkit/web" "github.com/prometheus/exporter-toolkit/web/kingpinflag" @@ -50,7 +49,7 @@ var ( excludeDatabases = kingpin.Flag("exclude-databases", "A list of databases to remove when autoDiscoverDatabases is enabled (DEPRECATED)").Default("").Envar("PG_EXPORTER_EXCLUDE_DATABASES").String() includeDatabases = kingpin.Flag("include-databases", "A list of databases to include when autoDiscoverDatabases is enabled (DEPRECATED)").Default("").Envar("PG_EXPORTER_INCLUDE_DATABASES").String() metricPrefix = 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() - logger = log.NewNopLogger() + logger = promslog.NewNopLogger() ) // Metric name parts. @@ -70,11 +69,11 @@ const ( func main() { kingpin.Version(version.Print(exporterName)) - promlogConfig := &promlog.Config{} - flag.AddFlags(kingpin.CommandLine, promlogConfig) + promslogConfig := &promslog.Config{} + flag.AddFlags(kingpin.CommandLine, promslogConfig) kingpin.HelpFlag.Short('h') kingpin.Parse() - logger = promlog.New(promlogConfig) + logger = promslog.New(promslogConfig) if *onlyDumpMaps { dumpMaps() @@ -83,28 +82,28 @@ func main() { if err := c.ReloadConfig(*configFile, logger); err != nil { // This is not fatal, but it means that auth must be provided for every dsn. - level.Warn(logger).Log("msg", "Error loading config", "err", err) + logger.Warn("Error loading config", "err", err) } dsns, err := getDataSources() if err != nil { - level.Error(logger).Log("msg", "Failed reading data sources", "err", err.Error()) + logger.Error("Failed reading data sources", "err", err.Error()) os.Exit(1) } excludedDatabases := strings.Split(*excludeDatabases, ",") - level.Info(logger).Log("msg", "Excluded databases", "databases", fmt.Sprintf("%v", excludedDatabases)) + logger.Info("Excluded databases", "databases", fmt.Sprintf("%v", excludedDatabases)) if *queriesPath != "" { - level.Warn(logger).Log("msg", "The extended queries.yaml config is DEPRECATED", "file", *queriesPath) + logger.Warn("The extended queries.yaml config is DEPRECATED", "file", *queriesPath) } if *autoDiscoverDatabases || *excludeDatabases != "" || *includeDatabases != "" { - level.Warn(logger).Log("msg", "Scraping additional databases via auto discovery is DEPRECATED") + logger.Warn("Scraping additional databases via auto discovery is DEPRECATED") } if *constantLabelsList != "" { - level.Warn(logger).Log("msg", "Constant labels on all metrics is DEPRECATED") + logger.Warn("Constant labels on all metrics is DEPRECATED") } opts := []ExporterOpt{ @@ -122,7 +121,7 @@ func main() { exporter.servers.Close() }() - prometheus.MustRegister(version.NewCollector(exporterName)) + prometheus.MustRegister(versioncollector.NewCollector(exporterName)) prometheus.MustRegister(exporter) @@ -139,7 +138,7 @@ func main() { []string{}, ) if err != nil { - level.Warn(logger).Log("msg", "Failed to create PostgresCollector", "err", err.Error()) + logger.Warn("Failed to create PostgresCollector", "err", err.Error()) } else { prometheus.MustRegister(pe) } @@ -160,7 +159,7 @@ func main() { } landingPage, err := web.NewLandingPage(landingConfig) if err != nil { - level.Error(logger).Log("err", err) + logger.Error("error creating landing page", "err", err) os.Exit(1) } http.Handle("/", landingPage) @@ -170,7 +169,7 @@ func main() { srv := &http.Server{} if err := web.ListenAndServe(srv, webConfig, logger); err != nil { - level.Error(logger).Log("msg", "Error running HTTP server", "err", err) + logger.Error("Error running HTTP server", "err", err) os.Exit(1) } } diff --git a/cmd/postgres_exporter/namespace.go b/cmd/postgres_exporter/namespace.go index 41674007d..ac7a23739 100644 --- a/cmd/postgres_exporter/namespace.go +++ b/cmd/postgres_exporter/namespace.go @@ -20,7 +20,6 @@ import ( "time" "github.com/blang/semver/v4" - "github.com/go-kit/log/level" "github.com/lib/pq" "github.com/prometheus/client_golang/prometheus" ) @@ -190,10 +189,10 @@ func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[str scrapeStart := time.Now() for namespace, mapping := range server.metricMap { - level.Debug(logger).Log("msg", "Querying namespace", "namespace", namespace) + logger.Debug("Querying namespace", "namespace", namespace) if mapping.master && !server.master { - level.Debug(logger).Log("msg", "Query skipped...") + logger.Debug("Query skipped...") continue } @@ -202,7 +201,7 @@ func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[str serVersion, _ := semver.Parse(server.lastMapVersion.String()) runServerRange, _ := semver.ParseRange(server.runonserver) if !runServerRange(serVersion) { - level.Debug(logger).Log("msg", "Query skipped for this database version", "version", server.lastMapVersion.String(), "target_version", server.runonserver) + logger.Debug("Query skipped for this database version", "version", server.lastMapVersion.String(), "target_version", server.runonserver) continue } } @@ -233,12 +232,12 @@ func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[str // Serious error - a namespace disappeared if err != nil { namespaceErrors[namespace] = err - level.Info(logger).Log("err", err) + logger.Info("error finding namespace", "err", err) } // Non-serious errors - likely version or parsing problems. if len(nonFatalErrors) > 0 { for _, err := range nonFatalErrors { - level.Info(logger).Log("err", err) + logger.Info("error querying namespace", "err", err) } } diff --git a/cmd/postgres_exporter/pg_setting.go b/cmd/postgres_exporter/pg_setting.go index f162c354a..b02416a7c 100644 --- a/cmd/postgres_exporter/pg_setting.go +++ b/cmd/postgres_exporter/pg_setting.go @@ -19,7 +19,6 @@ import ( "strconv" "strings" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) @@ -32,7 +31,7 @@ var ( // Query the pg_settings view containing runtime variables func querySettings(ch chan<- prometheus.Metric, server *Server) error { - level.Debug(logger).Log("msg", "Querying pg_setting view", "server", server) + logger.Debug("Querying pg_setting view", "server", server) // pg_settings docs: https://www.postgresql.org/docs/current/static/view-pg-settings.html // diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index fa34eecc5..90f26beb0 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -25,7 +25,6 @@ import ( "time" "github.com/blang/semver/v4" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) @@ -284,7 +283,7 @@ func makeDescMap(pgVersion semver.Version, serverLabels prometheus.Labels, metri if !columnMapping.supportedVersions(pgVersion) { // It's very useful to be able to see what columns are being // rejected. - level.Debug(logger).Log("msg", "Column is being forced to discard due to version incompatibility", "column", columnName) + logger.Debug("Column is being forced to discard due to version incompatibility", "column", columnName) thisMap[columnName] = MetricMap{ discard: true, conversion: func(_ interface{}) (float64, bool) { @@ -371,7 +370,7 @@ func makeDescMap(pgVersion semver.Version, serverLabels prometheus.Labels, metri case string: durationString = t default: - level.Error(logger).Log("msg", "Duration conversion metric was not a string") + logger.Error("Duration conversion metric was not a string") return math.NaN(), false } @@ -381,7 +380,7 @@ func makeDescMap(pgVersion semver.Version, serverLabels prometheus.Labels, metri d, err := time.ParseDuration(durationString) if err != nil { - level.Error(logger).Log("msg", "Failed converting result to metric", "column", columnName, "in", in, "err", err) + logger.Error("Failed converting result to metric", "column", columnName, "in", in, "err", err) return math.NaN(), false } return float64(d / time.Millisecond), true @@ -491,7 +490,7 @@ func parseConstLabels(s string) prometheus.Labels { for _, p := range parts { keyValue := strings.Split(strings.TrimSpace(p), "=") if len(keyValue) != 2 { - level.Error(logger).Log(`Wrong constant labels format, should be "key=value"`, "input", p) + logger.Error(`Wrong constant labels format, should be "key=value"`, "input", p) continue } key := strings.TrimSpace(keyValue[0]) @@ -582,7 +581,7 @@ func newDesc(subsystem, name, help string, labels prometheus.Labels) *prometheus } func checkPostgresVersion(db *sql.DB, server string) (semver.Version, string, error) { - level.Debug(logger).Log("msg", "Querying PostgreSQL version", "server", server) + logger.Debug("Querying PostgreSQL version", "server", server) versionRow := db.QueryRow("SELECT version();") var versionString string err := versionRow.Scan(&versionString) @@ -605,12 +604,12 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, server *Server) } if !e.disableDefaultMetrics && semanticVersion.LT(lowestSupportedVersion) { - level.Warn(logger).Log("msg", "PostgreSQL version is lower than our lowest supported version", "server", server, "version", semanticVersion, "lowest_supported_version", lowestSupportedVersion) + logger.Warn("PostgreSQL version is lower than our lowest supported version", "server", server, "version", semanticVersion, "lowest_supported_version", lowestSupportedVersion) } // Check if semantic version changed and recalculate maps if needed. if semanticVersion.NE(server.lastMapVersion) || server.metricMap == nil { - level.Info(logger).Log("msg", "Semantic version changed", "server", server, "from", server.lastMapVersion, "to", semanticVersion) + logger.Info("Semantic version changed", "server", server, "from", server.lastMapVersion, "to", semanticVersion) server.mappingMtx.Lock() // Get Default Metrics only for master database @@ -631,13 +630,13 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, server *Server) // Calculate the hashsum of the useQueries userQueriesData, err := os.ReadFile(e.userQueriesPath) if err != nil { - level.Error(logger).Log("msg", "Failed to reload user queries", "path", e.userQueriesPath, "err", err) + logger.Error("Failed to reload user queries", "path", e.userQueriesPath, "err", err) e.userQueriesError.WithLabelValues(e.userQueriesPath, "").Set(1) } else { hashsumStr := fmt.Sprintf("%x", sha256.Sum256(userQueriesData)) if err := addQueries(userQueriesData, semanticVersion, server); err != nil { - level.Error(logger).Log("msg", "Failed to reload user queries", "path", e.userQueriesPath, "err", err) + logger.Error("Failed to reload user queries", "path", e.userQueriesPath, "err", err) e.userQueriesError.WithLabelValues(e.userQueriesPath, hashsumStr).Set(1) } else { // Mark user queries as successfully loaded @@ -679,7 +678,7 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) { if err := e.scrapeDSN(ch, dsn); err != nil { errorsCount++ - level.Error(logger).Log("err", err) + logger.Error("error scraping dsn", "err", err, "dsn", dsn) if _, ok := err.(*ErrorConnectToServer); ok { connectionErrorsCount++ diff --git a/cmd/postgres_exporter/probe.go b/cmd/postgres_exporter/probe.go index 5945e07b8..2c8c7652e 100644 --- a/cmd/postgres_exporter/probe.go +++ b/cmd/postgres_exporter/probe.go @@ -15,17 +15,16 @@ package main import ( "fmt" + "log/slog" "net/http" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus-community/postgres_exporter/collector" "github.com/prometheus-community/postgres_exporter/config" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) -func handleProbe(logger log.Logger, excludeDatabases []string) http.HandlerFunc { +func handleProbe(logger *slog.Logger, excludeDatabases []string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() conf := c.GetConfig() @@ -38,7 +37,7 @@ func handleProbe(logger log.Logger, excludeDatabases []string) http.HandlerFunc var authModule config.AuthModule authModuleName := params.Get("auth_module") if authModuleName == "" { - level.Info(logger).Log("msg", "no auth_module specified, using default") + logger.Info("no auth_module specified, using default") } else { var ok bool authModule, ok = conf.AuthModules[authModuleName] @@ -54,14 +53,14 @@ func handleProbe(logger log.Logger, excludeDatabases []string) http.HandlerFunc dsn, err := authModule.ConfigureTarget(target) if err != nil { - level.Error(logger).Log("msg", "failed to configure target", "err", err) + logger.Error("failed to configure target", "err", err) http.Error(w, fmt.Sprintf("could not configure dsn for target: %v", err), http.StatusBadRequest) return } // TODO(@sysadmind): Timeout - tl := log.With(logger, "target", target) + tl := logger.With("target", target) registry := prometheus.NewRegistry() @@ -85,7 +84,7 @@ func handleProbe(logger log.Logger, excludeDatabases []string) http.HandlerFunc // Run the probe pc, err := collector.NewProbeCollector(tl, excludeDatabases, registry, dsn) if err != nil { - level.Error(logger).Log("msg", "Error creating probe collector", "err", err) + logger.Error("Error creating probe collector", "err", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } diff --git a/cmd/postgres_exporter/queries.go b/cmd/postgres_exporter/queries.go index 9ca91e287..7090606e1 100644 --- a/cmd/postgres_exporter/queries.go +++ b/cmd/postgres_exporter/queries.go @@ -18,7 +18,6 @@ import ( "fmt" "github.com/blang/semver/v4" - "github.com/go-kit/log/level" "gopkg.in/yaml.v2" ) @@ -172,7 +171,7 @@ func makeQueryOverrideMap(pgVersion semver.Version, queryOverrides map[string][] } } if !matched { - level.Warn(logger).Log("msg", "No query matched override, disabling metric space", "name", name) + logger.Warn("No query matched override, disabling metric space", "name", name) resultMap[name] = "" } } @@ -193,7 +192,7 @@ func parseUserQueries(content []byte) (map[string]intermediateMetricMap, map[str newQueryOverrides := make(map[string]string) for metric, specs := range userQueries { - level.Debug(logger).Log("msg", "New user metric namespace from YAML metric", "metric", metric, "cache_seconds", specs.CacheSeconds) + logger.Debug("New user metric namespace from YAML metric", "metric", metric, "cache_seconds", specs.CacheSeconds) newQueryOverrides[metric] = specs.Query metricMap, ok := metricMaps[metric] if !ok { @@ -245,9 +244,9 @@ func addQueries(content []byte, pgVersion semver.Version, server *Server) error for k, v := range partialExporterMap { _, found := server.metricMap[k] if found { - level.Debug(logger).Log("msg", "Overriding metric from user YAML file", "metric", k) + logger.Debug("Overriding metric from user YAML file", "metric", k) } else { - level.Debug(logger).Log("msg", "Adding new metric from user YAML file", "metric", k) + logger.Debug("Adding new metric from user YAML file", "metric", k) } server.metricMap[k] = v } @@ -256,9 +255,9 @@ func addQueries(content []byte, pgVersion semver.Version, server *Server) error for k, v := range newQueryOverrides { _, found := server.queryOverrides[k] if found { - level.Debug(logger).Log("msg", "Overriding query override from user YAML file", "query_override", k) + logger.Debug("Overriding query override from user YAML file", "query_override", k) } else { - level.Debug(logger).Log("msg", "Adding new query override from user YAML file", "query_override", k) + logger.Debug("Adding new query override from user YAML file", "query_override", k) } server.queryOverrides[k] = v } diff --git a/cmd/postgres_exporter/server.go b/cmd/postgres_exporter/server.go index bcfee6812..bd4e76e10 100644 --- a/cmd/postgres_exporter/server.go +++ b/cmd/postgres_exporter/server.go @@ -20,7 +20,6 @@ import ( "time" "github.com/blang/semver/v4" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) @@ -71,7 +70,7 @@ func NewServer(dsn string, opts ...ServerOpt) (*Server, error) { db.SetMaxOpenConns(1) db.SetMaxIdleConns(1) - level.Info(logger).Log("msg", "Established new database connection", "fingerprint", fingerprint) + logger.Info("Established new database connection", "fingerprint", fingerprint) s := &Server{ db: db, @@ -98,7 +97,7 @@ func (s *Server) Close() error { func (s *Server) Ping() error { if err := s.db.Ping(); err != nil { if cerr := s.Close(); cerr != nil { - level.Error(logger).Log("msg", "Error while closing non-pinging DB connection", "server", s, "err", cerr) + logger.Error("Error while closing non-pinging DB connection", "server", s, "err", cerr) } return err } @@ -184,7 +183,7 @@ func (s *Servers) Close() { defer s.m.Unlock() for _, server := range s.servers { if err := server.Close(); err != nil { - level.Error(logger).Log("msg", "Failed to close connection", "server", server, "err", err) + logger.Error("Failed to close connection", "server", server, "err", err) } } } diff --git a/cmd/postgres_exporter/util.go b/cmd/postgres_exporter/util.go index 3a125f1d3..3baa6f4be 100644 --- a/cmd/postgres_exporter/util.go +++ b/cmd/postgres_exporter/util.go @@ -21,7 +21,6 @@ import ( "strings" "time" - "github.com/go-kit/log/level" "github.com/lib/pq" ) @@ -82,14 +81,14 @@ func dbToFloat64(t interface{}) (float64, bool) { strV := string(v) result, err := strconv.ParseFloat(strV, 64) if err != nil { - level.Info(logger).Log("msg", "Could not parse []byte", "err", err) + logger.Info("Could not parse []byte", "err", err) return math.NaN(), false } return result, true case string: result, err := strconv.ParseFloat(v, 64) if err != nil { - level.Info(logger).Log("msg", "Could not parse string", "err", err) + logger.Info("Could not parse string", "err", err) return math.NaN(), false } return result, true @@ -122,14 +121,14 @@ func dbToUint64(t interface{}) (uint64, bool) { strV := string(v) result, err := strconv.ParseUint(strV, 10, 64) if err != nil { - level.Info(logger).Log("msg", "Could not parse []byte", "err", err) + logger.Info("Could not parse []byte", "err", err) return 0, false } return result, true case string: result, err := strconv.ParseUint(v, 10, 64) if err != nil { - level.Info(logger).Log("msg", "Could not parse string", "err", err) + logger.Info("Could not parse string", "err", err) return 0, false } return result, true diff --git a/collector/collector.go b/collector/collector.go index 121129871..f2102d5ef 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -17,12 +17,11 @@ import ( "context" "errors" "fmt" + "log/slog" "sync" "time" "github.com/alecthomas/kingpin/v2" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) @@ -62,7 +61,7 @@ type Collector interface { } type collectorConfig struct { - logger log.Logger + logger *slog.Logger excludeDatabases []string } @@ -89,7 +88,7 @@ func registerCollector(name string, isDefaultEnabled bool, createFunc func(colle // PostgresCollector implements the prometheus.Collector interface. type PostgresCollector struct { Collectors map[string]Collector - logger log.Logger + logger *slog.Logger instance *instance } @@ -97,7 +96,7 @@ type PostgresCollector struct { type Option func(*PostgresCollector) error // NewPostgresCollector creates a new PostgresCollector. -func NewPostgresCollector(logger log.Logger, excludeDatabases []string, dsn string, filters []string, options ...Option) (*PostgresCollector, error) { +func NewPostgresCollector(logger *slog.Logger, excludeDatabases []string, dsn string, filters []string, options ...Option) (*PostgresCollector, error) { p := &PostgresCollector{ logger: logger, } @@ -131,7 +130,7 @@ func NewPostgresCollector(logger log.Logger, excludeDatabases []string, dsn stri collectors[key] = collector } else { collector, err := factories[key](collectorConfig{ - logger: log.With(logger, "collector", key), + logger: logger.With("collector", key), excludeDatabases: excludeDatabases, }) if err != nil { @@ -173,7 +172,7 @@ func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) { // Set up the database connection for the collector. err := inst.setup() if err != nil { - level.Error(p.logger).Log("msg", "Error opening connection to database", "err", err) + p.logger.Error("Error opening connection to database", "err", err) return } defer inst.Close() @@ -189,7 +188,7 @@ func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) { wg.Wait() } -func execute(ctx context.Context, name string, c Collector, instance *instance, ch chan<- prometheus.Metric, logger log.Logger) { +func execute(ctx context.Context, name string, c Collector, instance *instance, ch chan<- prometheus.Metric, logger *slog.Logger) { begin := time.Now() err := c.Update(ctx, instance, ch) duration := time.Since(begin) @@ -197,13 +196,13 @@ func execute(ctx context.Context, name string, c Collector, instance *instance, if err != nil { if IsNoDataError(err) { - level.Debug(logger).Log("msg", "collector returned no data", "name", name, "duration_seconds", duration.Seconds(), "err", err) + logger.Debug("collector returned no data", "name", name, "duration_seconds", duration.Seconds(), "err", err) } else { - level.Error(logger).Log("msg", "collector failed", "name", name, "duration_seconds", duration.Seconds(), "err", err) + logger.Error("collector failed", "name", name, "duration_seconds", duration.Seconds(), "err", err) } success = 0 } else { - level.Debug(logger).Log("msg", "collector succeeded", "name", name, "duration_seconds", duration.Seconds()) + logger.Debug("collector succeeded", "name", name, "duration_seconds", duration.Seconds()) success = 1 } ch <- prometheus.MustNewConstMetric(scrapeDurationDesc, prometheus.GaugeValue, duration.Seconds(), name) diff --git a/collector/pg_database.go b/collector/pg_database.go index 30c4c8af0..4c0972080 100644 --- a/collector/pg_database.go +++ b/collector/pg_database.go @@ -16,8 +16,8 @@ package collector import ( "context" "database/sql" + "log/slog" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -28,7 +28,7 @@ func init() { } type PGDatabaseCollector struct { - log log.Logger + log *slog.Logger excludedDatabases []string } diff --git a/collector/pg_database_wraparound.go b/collector/pg_database_wraparound.go index d46270637..d170821b5 100644 --- a/collector/pg_database_wraparound.go +++ b/collector/pg_database_wraparound.go @@ -16,9 +16,8 @@ package collector import ( "context" "database/sql" + "log/slog" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) @@ -29,7 +28,7 @@ func init() { } type PGDatabaseWraparoundCollector struct { - log log.Logger + log *slog.Logger } func NewPGDatabaseWraparoundCollector(config collectorConfig) (Collector, error) { @@ -81,15 +80,15 @@ func (c *PGDatabaseWraparoundCollector) Update(ctx context.Context, instance *in } if !datname.Valid { - level.Debug(c.log).Log("msg", "Skipping database with NULL name") + c.log.Debug("Skipping database with NULL name") continue } if !ageDatfrozenxid.Valid { - level.Debug(c.log).Log("msg", "Skipping stat emission with NULL age_datfrozenxid") + c.log.Debug("Skipping stat emission with NULL age_datfrozenxid") continue } if !ageDatminmxid.Valid { - level.Debug(c.log).Log("msg", "Skipping stat emission with NULL age_datminmxid") + c.log.Debug("Skipping stat emission with NULL age_datminmxid") continue } diff --git a/collector/pg_locks.go b/collector/pg_locks.go index d2c77ccd5..add3e6d42 100644 --- a/collector/pg_locks.go +++ b/collector/pg_locks.go @@ -16,8 +16,8 @@ package collector import ( "context" "database/sql" + "log/slog" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -28,7 +28,7 @@ func init() { } type PGLocksCollector struct { - log log.Logger + log *slog.Logger } func NewPGLocksCollector(config collectorConfig) (Collector, error) { diff --git a/collector/pg_long_running_transactions.go b/collector/pg_long_running_transactions.go index ffd89d5f0..846feaeed 100644 --- a/collector/pg_long_running_transactions.go +++ b/collector/pg_long_running_transactions.go @@ -15,8 +15,8 @@ package collector import ( "context" + "log/slog" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -27,7 +27,7 @@ func init() { } type PGLongRunningTransactionsCollector struct { - log log.Logger + log *slog.Logger } func NewPGLongRunningTransactionsCollector(config collectorConfig) (Collector, error) { diff --git a/collector/pg_process_idle.go b/collector/pg_process_idle.go index c401ab56f..7f3ff6f0f 100644 --- a/collector/pg_process_idle.go +++ b/collector/pg_process_idle.go @@ -16,8 +16,8 @@ package collector import ( "context" "database/sql" + "log/slog" - "github.com/go-kit/log" "github.com/lib/pq" "github.com/prometheus/client_golang/prometheus" ) @@ -28,7 +28,7 @@ func init() { } type PGProcessIdleCollector struct { - log log.Logger + log *slog.Logger } const processIdleSubsystem = "process_idle" diff --git a/collector/pg_replication_slot.go b/collector/pg_replication_slot.go index 1d29f8498..27ccddefd 100644 --- a/collector/pg_replication_slot.go +++ b/collector/pg_replication_slot.go @@ -16,8 +16,8 @@ package collector import ( "context" "database/sql" + "log/slog" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -28,7 +28,7 @@ func init() { } type PGReplicationSlotCollector struct { - log log.Logger + log *slog.Logger } func NewPGReplicationSlotCollector(config collectorConfig) (Collector, error) { diff --git a/collector/pg_roles.go b/collector/pg_roles.go index 609c34c33..626dbb44f 100644 --- a/collector/pg_roles.go +++ b/collector/pg_roles.go @@ -16,8 +16,8 @@ package collector import ( "context" "database/sql" + "log/slog" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -28,7 +28,7 @@ func init() { } type PGRolesCollector struct { - log log.Logger + log *slog.Logger } func NewPGRolesCollector(config collectorConfig) (Collector, error) { diff --git a/collector/pg_stat_activity_autovacuum.go b/collector/pg_stat_activity_autovacuum.go index 6cf8cdcec..f08029d18 100644 --- a/collector/pg_stat_activity_autovacuum.go +++ b/collector/pg_stat_activity_autovacuum.go @@ -15,8 +15,8 @@ package collector import ( "context" + "log/slog" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -27,7 +27,7 @@ func init() { } type PGStatActivityAutovacuumCollector struct { - log log.Logger + log *slog.Logger } func NewPGStatActivityAutovacuumCollector(config collectorConfig) (Collector, error) { diff --git a/collector/pg_stat_database.go b/collector/pg_stat_database.go index b3cb59eb2..b9210740f 100644 --- a/collector/pg_stat_database.go +++ b/collector/pg_stat_database.go @@ -17,11 +17,10 @@ import ( "context" "database/sql" "fmt" + "log/slog" "strings" "github.com/blang/semver/v4" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) @@ -32,7 +31,7 @@ func init() { } type PGStatDatabaseCollector struct { - log log.Logger + log *slog.Logger } func NewPGStatDatabaseCollector(config collectorConfig) (Collector, error) { @@ -299,85 +298,85 @@ func (c *PGStatDatabaseCollector) Update(ctx context.Context, instance *instance } if !datid.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no datid") + c.log.Debug("Skipping collecting metric because it has no datid") continue } if !datname.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no datname") + c.log.Debug("Skipping collecting metric because it has no datname") continue } if !numBackends.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no numbackends") + c.log.Debug("Skipping collecting metric because it has no numbackends") continue } if !xactCommit.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no xact_commit") + c.log.Debug("Skipping collecting metric because it has no xact_commit") continue } if !xactRollback.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no xact_rollback") + c.log.Debug("Skipping collecting metric because it has no xact_rollback") continue } if !blksRead.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blks_read") + c.log.Debug("Skipping collecting metric because it has no blks_read") continue } if !blksHit.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blks_hit") + c.log.Debug("Skipping collecting metric because it has no blks_hit") continue } if !tupReturned.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no tup_returned") + c.log.Debug("Skipping collecting metric because it has no tup_returned") continue } if !tupFetched.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no tup_fetched") + c.log.Debug("Skipping collecting metric because it has no tup_fetched") continue } if !tupInserted.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no tup_inserted") + c.log.Debug("Skipping collecting metric because it has no tup_inserted") continue } if !tupUpdated.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no tup_updated") + c.log.Debug("Skipping collecting metric because it has no tup_updated") continue } if !tupDeleted.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no tup_deleted") + c.log.Debug("Skipping collecting metric because it has no tup_deleted") continue } if !conflicts.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no conflicts") + c.log.Debug("Skipping collecting metric because it has no conflicts") continue } if !tempFiles.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no temp_files") + c.log.Debug("Skipping collecting metric because it has no temp_files") continue } if !tempBytes.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no temp_bytes") + c.log.Debug("Skipping collecting metric because it has no temp_bytes") continue } if !deadlocks.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no deadlocks") + c.log.Debug("Skipping collecting metric because it has no deadlocks") continue } if !blkReadTime.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blk_read_time") + c.log.Debug("Skipping collecting metric because it has no blk_read_time") continue } if !blkWriteTime.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no blk_write_time") + c.log.Debug("Skipping collecting metric because it has no blk_write_time") continue } if activeTimeAvail && !activeTime.Valid { - level.Debug(c.log).Log("msg", "Skipping collecting metric because it has no active_time") + c.log.Debug("Skipping collecting metric because it has no active_time") continue } statsResetMetric := 0.0 if !statsReset.Valid { - level.Debug(c.log).Log("msg", "No metric for stats_reset, will collect 0 instead") + c.log.Debug("No metric for stats_reset, will collect 0 instead") } if statsReset.Valid { statsResetMetric = float64(statsReset.Time.Unix()) diff --git a/collector/pg_stat_database_test.go b/collector/pg_stat_database_test.go index 924612082..e6194ca2e 100644 --- a/collector/pg_stat_database_test.go +++ b/collector/pg_stat_database_test.go @@ -19,9 +19,9 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/blang/semver/v4" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" + "github.com/prometheus/common/promslog" "github.com/smartystreets/goconvey/convey" ) @@ -92,7 +92,7 @@ func TestPGStatDatabaseCollector(t *testing.T) { go func() { defer close(ch) c := PGStatDatabaseCollector{ - log: log.With(log.NewNopLogger(), "collector", "pg_stat_database"), + log: promslog.NewNopLogger().With("collector", "pg_stat_database"), } if err := c.Update(context.Background(), inst, ch); err != nil { @@ -219,7 +219,7 @@ func TestPGStatDatabaseCollectorNullValues(t *testing.T) { go func() { defer close(ch) c := PGStatDatabaseCollector{ - log: log.With(log.NewNopLogger(), "collector", "pg_stat_database"), + log: promslog.NewNopLogger().With("collector", "pg_stat_database"), } if err := c.Update(context.Background(), inst, ch); err != nil { @@ -368,7 +368,7 @@ func TestPGStatDatabaseCollectorRowLeakTest(t *testing.T) { go func() { defer close(ch) c := PGStatDatabaseCollector{ - log: log.With(log.NewNopLogger(), "collector", "pg_stat_database"), + log: promslog.NewNopLogger().With("collector", "pg_stat_database"), } if err := c.Update(context.Background(), inst, ch); err != nil { @@ -489,7 +489,7 @@ func TestPGStatDatabaseCollectorTestNilStatReset(t *testing.T) { go func() { defer close(ch) c := PGStatDatabaseCollector{ - log: log.With(log.NewNopLogger(), "collector", "pg_stat_database"), + log: promslog.NewNopLogger().With("collector", "pg_stat_database"), } if err := c.Update(context.Background(), inst, ch); err != nil { diff --git a/collector/pg_stat_statements.go b/collector/pg_stat_statements.go index c03e78b92..7926f533e 100644 --- a/collector/pg_stat_statements.go +++ b/collector/pg_stat_statements.go @@ -16,9 +16,9 @@ package collector import ( "context" "database/sql" + "log/slog" "github.com/blang/semver/v4" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -32,7 +32,7 @@ func init() { } type PGStatStatementsCollector struct { - log log.Logger + log *slog.Logger } func NewPGStatStatementsCollector(config collectorConfig) (Collector, error) { diff --git a/collector/pg_stat_user_tables.go b/collector/pg_stat_user_tables.go index af3822ca8..254d76a66 100644 --- a/collector/pg_stat_user_tables.go +++ b/collector/pg_stat_user_tables.go @@ -16,8 +16,8 @@ package collector import ( "context" "database/sql" + "log/slog" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -28,7 +28,7 @@ func init() { } type PGStatUserTablesCollector struct { - log log.Logger + log *slog.Logger } func NewPGStatUserTablesCollector(config collectorConfig) (Collector, error) { diff --git a/collector/pg_stat_walreceiver.go b/collector/pg_stat_walreceiver.go index db533ab55..0c9f3f83f 100644 --- a/collector/pg_stat_walreceiver.go +++ b/collector/pg_stat_walreceiver.go @@ -16,9 +16,8 @@ import ( "context" "database/sql" "fmt" + "log/slog" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) @@ -27,7 +26,7 @@ func init() { } type PGStatWalReceiverCollector struct { - log log.Logger + log *slog.Logger } const statWalReceiverSubsystem = "stat_wal_receiver" @@ -157,55 +156,55 @@ func (c *PGStatWalReceiverCollector) Update(ctx context.Context, instance *insta } } if !upstreamHost.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because upstream host is null") + c.log.Debug("Skipping wal receiver stats because upstream host is null") continue } if !slotName.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because slotname host is null") + c.log.Debug("Skipping wal receiver stats because slotname host is null") continue } if !status.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because status is null") + c.log.Debug("Skipping wal receiver stats because status is null") continue } labels := []string{upstreamHost.String, slotName.String, status.String} if !receiveStartLsn.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because receive_start_lsn is null") + c.log.Debug("Skipping wal receiver stats because receive_start_lsn is null") continue } if !receiveStartTli.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because receive_start_tli is null") + c.log.Debug("Skipping wal receiver stats because receive_start_tli is null") continue } if hasFlushedLSN && !flushedLsn.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because flushed_lsn is null") + c.log.Debug("Skipping wal receiver stats because flushed_lsn is null") continue } if !receivedTli.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because received_tli is null") + c.log.Debug("Skipping wal receiver stats because received_tli is null") continue } if !lastMsgSendTime.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because last_msg_send_time is null") + c.log.Debug("Skipping wal receiver stats because last_msg_send_time is null") continue } if !lastMsgReceiptTime.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because last_msg_receipt_time is null") + c.log.Debug("Skipping wal receiver stats because last_msg_receipt_time is null") continue } if !latestEndLsn.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because latest_end_lsn is null") + c.log.Debug("Skipping wal receiver stats because latest_end_lsn is null") continue } if !latestEndTime.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because latest_end_time is null") + c.log.Debug("Skipping wal receiver stats because latest_end_time is null") continue } if !upstreamNode.Valid { - level.Debug(c.log).Log("msg", "Skipping wal receiver stats because upstream_node is null") + c.log.Debug("Skipping wal receiver stats because upstream_node is null") continue } ch <- prometheus.MustNewConstMetric( diff --git a/collector/pg_statio_user_indexes.go b/collector/pg_statio_user_indexes.go index b5516338d..c53f52185 100644 --- a/collector/pg_statio_user_indexes.go +++ b/collector/pg_statio_user_indexes.go @@ -15,8 +15,8 @@ package collector import ( "context" "database/sql" + "log/slog" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -25,7 +25,7 @@ func init() { } type PGStatioUserIndexesCollector struct { - log log.Logger + log *slog.Logger } const statioUserIndexesSubsystem = "statio_user_indexes" diff --git a/collector/pg_statio_user_tables.go b/collector/pg_statio_user_tables.go index 4315fda0a..48f6438f2 100644 --- a/collector/pg_statio_user_tables.go +++ b/collector/pg_statio_user_tables.go @@ -16,8 +16,8 @@ package collector import ( "context" "database/sql" + "log/slog" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -28,7 +28,7 @@ func init() { } type PGStatIOUserTablesCollector struct { - log log.Logger + log *slog.Logger } func NewPGStatIOUserTablesCollector(config collectorConfig) (Collector, error) { diff --git a/collector/pg_xlog_location.go b/collector/pg_xlog_location.go index 237204f7d..5f091471f 100644 --- a/collector/pg_xlog_location.go +++ b/collector/pg_xlog_location.go @@ -15,10 +15,9 @@ package collector import ( "context" + "log/slog" "github.com/blang/semver/v4" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" ) @@ -29,7 +28,7 @@ func init() { } type PGXlogLocationCollector struct { - log log.Logger + log *slog.Logger } func NewPGXlogLocationCollector(config collectorConfig) (Collector, error) { @@ -59,7 +58,7 @@ func (c PGXlogLocationCollector) Update(ctx context.Context, instance *instance, // https://wiki.postgresql.org/wiki/New_in_postgres_10#Renaming_of_.22xlog.22_to_.22wal.22_Globally_.28and_location.2Flsn.29 after10 := instance.version.Compare(semver.MustParse("10.0.0")) if after10 >= 0 { - level.Warn(c.log).Log("msg", "xlog_location collector is not available on PostgreSQL >= 10.0.0, skipping") + c.log.Warn("xlog_location collector is not available on PostgreSQL >= 10.0.0, skipping") return nil } diff --git a/collector/probe.go b/collector/probe.go index 4c0f0419b..54a06261f 100644 --- a/collector/probe.go +++ b/collector/probe.go @@ -15,10 +15,9 @@ package collector import ( "context" + "log/slog" "sync" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus-community/postgres_exporter/config" "github.com/prometheus/client_golang/prometheus" ) @@ -26,11 +25,11 @@ import ( type ProbeCollector struct { registry *prometheus.Registry collectors map[string]Collector - logger log.Logger + logger *slog.Logger instance *instance } -func NewProbeCollector(logger log.Logger, excludeDatabases []string, registry *prometheus.Registry, dsn config.DSN) (*ProbeCollector, error) { +func NewProbeCollector(logger *slog.Logger, excludeDatabases []string, registry *prometheus.Registry, dsn config.DSN) (*ProbeCollector, error) { collectors := make(map[string]Collector) initiatedCollectorsMtx.Lock() defer initiatedCollectorsMtx.Unlock() @@ -47,7 +46,7 @@ func NewProbeCollector(logger log.Logger, excludeDatabases []string, registry *p } else { collector, err := factories[key]( collectorConfig{ - logger: log.With(logger, "collector", key), + logger: logger.With("collector", key), excludeDatabases: excludeDatabases, }) if err != nil { @@ -78,7 +77,7 @@ func (pc *ProbeCollector) Collect(ch chan<- prometheus.Metric) { // Set up the database connection for the collector. err := pc.instance.setup() if err != nil { - level.Error(pc.logger).Log("msg", "Error opening connection to database", "err", err) + pc.logger.Error("Error opening connection to database", "err", err) return } defer pc.instance.Close() diff --git a/config/config.go b/config/config.go index f67969725..7cdc08f7b 100644 --- a/config/config.go +++ b/config/config.go @@ -15,10 +15,10 @@ package config import ( "fmt" + "log/slog" "os" "sync" - "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "gopkg.in/yaml.v3" @@ -65,7 +65,7 @@ func (ch *Handler) GetConfig() *Config { return ch.Config } -func (ch *Handler) ReloadConfig(f string, logger log.Logger) error { +func (ch *Handler) ReloadConfig(f string, logger *slog.Logger) error { config := &Config{} var err error defer func() { diff --git a/go.mod b/go.mod index e937de61d..01758f1e6 100644 --- a/go.mod +++ b/go.mod @@ -1,17 +1,16 @@ module github.com/prometheus-community/postgres_exporter -go 1.19 +go 1.23.0 require ( github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/alecthomas/kingpin/v2 v2.4.0 github.com/blang/semver/v4 v4.0.0 - github.com/go-kit/log v0.2.1 github.com/lib/pq v1.10.9 - github.com/prometheus/client_golang v1.19.0 - github.com/prometheus/client_model v0.6.0 - github.com/prometheus/common v0.48.0 - github.com/prometheus/exporter-toolkit v0.11.0 + github.com/prometheus/client_golang v1.20.4 + github.com/prometheus/client_model v0.6.1 + github.com/prometheus/common v0.60.0 + github.com/prometheus/exporter-toolkit v0.13.0 github.com/smartystreets/goconvey v1.8.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 @@ -21,26 +20,27 @@ require ( require ( github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/golang/protobuf v1.5.3 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + github.com/mdlayher/vsock v1.2.1 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/oauth2 v0.16.0 // indirect - golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.33.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/go.sum b/go.sum index 687657eaf..705201d25 100644 --- a/go.sum +++ b/go.sum @@ -8,24 +8,17 @@ 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/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -33,6 +26,8 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -40,23 +35,31 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= +github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= -github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= -github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= -github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= -github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g= -github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= +github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= +github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= +github.com/prometheus/exporter-toolkit v0.13.0 h1:lmA0Q+8IaXgmFRKw09RldZmZdnvu9wwcDLIXGmTPw1c= +github.com/prometheus/exporter-toolkit v0.13.0/go.mod h1:2uop99EZl80KdXhv/MxVI2181fMcwlsumFOqBecGkG0= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= @@ -66,34 +69,24 @@ github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sS github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From 071ebb6244d554fddc92aed481add9bb2c84e082 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 22:28:29 +0200 Subject: [PATCH 186/228] Bump github.com/prometheus/client_golang from 1.20.4 to 1.20.5 (#1079) Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.4 to 1.20.5. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.20.4...v1.20.5) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 01758f1e6..9aa0aabae 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/alecthomas/kingpin/v2 v2.4.0 github.com/blang/semver/v4 v4.0.0 github.com/lib/pq v1.10.9 - github.com/prometheus/client_golang v1.20.4 + github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.60.0 github.com/prometheus/exporter-toolkit v0.13.0 diff --git a/go.sum b/go.sum index 705201d25..75090d804 100644 --- a/go.sum +++ b/go.sum @@ -50,8 +50,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= -github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= From f9c74570ed80d1a67c4a70e155cdb8d9689825eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 27 Oct 2024 21:28:26 +0100 Subject: [PATCH 187/228] Bump github.com/prometheus/common from 0.60.0 to 0.60.1 (#1080) Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.60.0 to 0.60.1. - [Release notes](https://github.com/prometheus/common/releases) - [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md) - [Commits](https://github.com/prometheus/common/compare/v0.60.0...v0.60.1) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9aa0aabae..401b62077 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/lib/pq v1.10.9 github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_model v0.6.1 - github.com/prometheus/common v0.60.0 + github.com/prometheus/common v0.60.1 github.com/prometheus/exporter-toolkit v0.13.0 github.com/smartystreets/goconvey v1.8.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c diff --git a/go.sum b/go.sum index 75090d804..4c3159375 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+ github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= -github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= +github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= +github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= github.com/prometheus/exporter-toolkit v0.13.0 h1:lmA0Q+8IaXgmFRKw09RldZmZdnvu9wwcDLIXGmTPw1c= github.com/prometheus/exporter-toolkit v0.13.0/go.mod h1:2uop99EZl80KdXhv/MxVI2181fMcwlsumFOqBecGkG0= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= From 552ff92f8b3e3c87dff3e126f4c007478808eae9 Mon Sep 17 00:00:00 2001 From: Conrad Hoffmann <1226676+bitfehler@users.noreply.github.com> Date: Wed, 6 Nov 2024 18:47:30 +0100 Subject: [PATCH 188/228] Make walreceiver collector useful w/o repmgr (#1086) In a streaming replication setup that was created without replication manager (`repmgr`), the `stat_wal_receiver` collector does not return any metrics, because one value it wants to export is not present. This is rather overly opinionated. The missing metric is comparatively uninteresting and does not justify discarding all the others. And replication setups created without `repmgr` are not exactly rare. This commit makes the one relevant metric optional and simply skips it if the respective value cannot be determined. Signed-off-by: Conrad Hoffmann --- collector/pg_stat_walreceiver.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/collector/pg_stat_walreceiver.go b/collector/pg_stat_walreceiver.go index 0c9f3f83f..ea0db4558 100644 --- a/collector/pg_stat_walreceiver.go +++ b/collector/pg_stat_walreceiver.go @@ -203,10 +203,6 @@ func (c *PGStatWalReceiverCollector) Update(ctx context.Context, instance *insta c.log.Debug("Skipping wal receiver stats because latest_end_time is null") continue } - if !upstreamNode.Valid { - c.log.Debug("Skipping wal receiver stats because upstream_node is null") - continue - } ch <- prometheus.MustNewConstMetric( statWalReceiverReceiveStartLsn, prometheus.CounterValue, @@ -257,11 +253,15 @@ func (c *PGStatWalReceiverCollector) Update(ctx context.Context, instance *insta latestEndTime.Float64, labels...) - ch <- prometheus.MustNewConstMetric( - statWalReceiverUpstreamNode, - prometheus.GaugeValue, - float64(upstreamNode.Int64), - labels...) + if !upstreamNode.Valid { + c.log.Debug("Skipping wal receiver stats upstream_node because it is null") + } else { + ch <- prometheus.MustNewConstMetric( + statWalReceiverUpstreamNode, + prometheus.GaugeValue, + float64(upstreamNode.Int64), + labels...) + } } if err := rows.Err(); err != nil { return err From c52405ab4883f3f56672c226f8bf25e302c23aef Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Wed, 6 Nov 2024 18:47:57 +0100 Subject: [PATCH 189/228] Update common Prometheus files (#1083) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 1c099932b..7183091ac 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -26,14 +26,14 @@ jobs: - name: Checkout repository uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Install Go - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: 1.23.x - name: Install snmp_exporter/generator dependencies run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0 + uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1 with: args: --verbose version: v1.60.2 From 340a104d253481398837669eb7d3a02dd7aedb15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Nov 2024 18:48:19 +0100 Subject: [PATCH 190/228] Bump github.com/prometheus/exporter-toolkit from 0.13.0 to 0.13.1 (#1081) Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.13.0 to 0.13.1. - [Release notes](https://github.com/prometheus/exporter-toolkit/releases) - [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md) - [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.13.0...v0.13.1) --- updated-dependencies: - dependency-name: github.com/prometheus/exporter-toolkit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 401b62077..bc854c3aa 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.60.1 - github.com/prometheus/exporter-toolkit v0.13.0 + github.com/prometheus/exporter-toolkit v0.13.1 github.com/smartystreets/goconvey v1.8.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 @@ -36,11 +36,11 @@ require ( github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.27.0 // indirect + golang.org/x/crypto v0.28.0 // indirect golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/go.sum b/go.sum index 4c3159375..044805aa2 100644 --- a/go.sum +++ b/go.sum @@ -56,8 +56,8 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= -github.com/prometheus/exporter-toolkit v0.13.0 h1:lmA0Q+8IaXgmFRKw09RldZmZdnvu9wwcDLIXGmTPw1c= -github.com/prometheus/exporter-toolkit v0.13.0/go.mod h1:2uop99EZl80KdXhv/MxVI2181fMcwlsumFOqBecGkG0= +github.com/prometheus/exporter-toolkit v0.13.1 h1:Evsh0gWQo2bdOHlnz9+0Nm7/OFfIwhE2Ws4A2jIlR04= +github.com/prometheus/exporter-toolkit v0.13.1/go.mod h1:ujdv2YIOxtdFxxqtloLpbqmxd5J0Le6IITUvIRSWjj0= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -73,18 +73,18 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 0045c4f93ea94c113ccb3b2aab1918dd47161288 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Fri, 8 Nov 2024 19:51:27 +0100 Subject: [PATCH 191/228] Update common Prometheus files (#1087) Signed-off-by: prombot --- .github/workflows/container_description.yml | 4 ++-- .github/workflows/golangci-lint.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/container_description.yml b/.github/workflows/container_description.yml index 144859486..dcca16ff3 100644 --- a/.github/workflows/container_description.yml +++ b/.github/workflows/container_description.yml @@ -18,7 +18,7 @@ jobs: if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks. steps: - name: git checkout - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set docker hub repo name run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV - name: Push README to Dockerhub @@ -40,7 +40,7 @@ jobs: if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks. steps: - name: git checkout - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set quay.io org name run: echo "DOCKER_REPO=$(echo quay.io/${GITHUB_REPOSITORY_OWNER} | tr -d '-')" >> $GITHUB_ENV - name: Set quay.io repo name diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 7183091ac..305146993 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install Go uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: @@ -36,4 +36,4 @@ jobs: uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1 with: args: --verbose - version: v1.60.2 + version: v1.61.0 From 4abdfa5bfde1fc53adac7f980eabc3a54df3890f Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Sun, 10 Nov 2024 15:55:46 -0500 Subject: [PATCH 192/228] Update changelog and version for a v0.16.0 release (#1088) Signed-off-by: Joe Adams --- CHANGELOG.md | 16 ++++++++++++++++ VERSION | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d17f536b..bf2b78bb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## Next + +BREAKING CHANGES: + +The logging system has been replaced with log/slog from the stdlib. This change is being made across the prometheus ecosystem. The logging output has changed, but the messages and levels remain the same. The `ts` label for the timestamp has bewen replaced with `time`, the accuracy is less, and the timezone is not forced to UTC. The `caller` field has been replaced by the `source` field, which now includes the full path to the source file. The `level` field now exposes the log level in capital letters. + +* [CHANGE] Replace logging system #1073 +* [ENHANCEMENT] Add save_wal_size and wal_status to replication_slot collector #1027 +* [ENHANCEMENT] Add roles collector and connection limit metrics to database collector #997 +* [ENHANCEMENT] Excluded databases log messgae is now info level #1003 +* [ENHANCEMENT] Add active_time to stat_database collector #961 +* [ENHANCEMENT] Add slot_type label to replication_slot collector #960 +* [BUGFIX] Fix walreceiver collectore when no repmgr #1086 +* [BUGFIX] Remove logging errors on replicas #1048 +* [BUGFIX] Fix active_time query on postgres>=14 #1045 + ## 0.15.0 / 2023-10-27 * [ENHANCEMENT] Add 1kB and 2kB units #915 diff --git a/VERSION b/VERSION index a55105169..04a373efe 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.15.0 +0.16.0 From a324fe37bca5193a293118b940b3df7ab3a8505c Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Sun, 10 Nov 2024 16:05:34 -0500 Subject: [PATCH 193/228] Fix version header in changelog (#1089) Signed-off-by: Joe Adams --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf2b78bb6..790a109c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Next +## 0.16.0 / 2024-11-10 BREAKING CHANGES: From 6f36adfadfcc51f8e1b92f8cd5fceb0289d73ccc Mon Sep 17 00:00:00 2001 From: Jyothi Kiran Thammana <147131742+jyothikirant-sayukth@users.noreply.github.com> Date: Mon, 23 Dec 2024 01:39:35 +0530 Subject: [PATCH 194/228] Update pg_long_running_transactions.go (#1092) To extract time in seconds for pg_long_running_transactions_oldest_timestamp_seconds query which currently return epoch time. Signed-off-by: Jyothi Kiran Thammana <147131742+jyothikirant-sayukth@users.noreply.github.com> --- collector/pg_long_running_transactions.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/collector/pg_long_running_transactions.go b/collector/pg_long_running_transactions.go index 846feaeed..d7d1e6d30 100644 --- a/collector/pg_long_running_transactions.go +++ b/collector/pg_long_running_transactions.go @@ -50,11 +50,13 @@ var ( ) longRunningTransactionsQuery = ` - SELECT - COUNT(*) as transactions, - MAX(EXTRACT(EPOCH FROM clock_timestamp())) AS oldest_timestamp_seconds - FROM pg_catalog.pg_stat_activity - WHERE state is distinct from 'idle' AND query not like 'autovacuum:%' + SELECT + COUNT(*) as transactions, + MAX(EXTRACT(EPOCH FROM clock_timestamp() - pg_stat_activity.xact_start)) AS oldest_timestamp_seconds +FROM pg_catalog.pg_stat_activity +WHERE state IS DISTINCT FROM 'idle' +AND query NOT LIKE 'autovacuum:%' +AND pg_stat_activity.xact_start IS NOT NULL; ` ) From 5bb170232162b2d9232d1e1d7340eeee1cafdf41 Mon Sep 17 00:00:00 2001 From: aagarwalla-fx Date: Mon, 23 Dec 2024 02:44:19 +0530 Subject: [PATCH 195/228] Fix to replace dashes with underscore in the metric names (#1103) * Fix to replace dashes with underscore in the metric names Signed-off-by: aagarwalla-fx * Code style fix Signed-off-by: aagarwalla-fx --------- Signed-off-by: aagarwalla-fx --- cmd/postgres_exporter/pg_setting.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/pg_setting.go b/cmd/postgres_exporter/pg_setting.go index b02416a7c..02e65dd2a 100644 --- a/cmd/postgres_exporter/pg_setting.go +++ b/cmd/postgres_exporter/pg_setting.go @@ -67,7 +67,7 @@ type pgSetting struct { func (s *pgSetting) metric(labels prometheus.Labels) prometheus.Metric { var ( err error - name = strings.Replace(s.name, ".", "_", -1) + name = strings.Replace(strings.Replace(s.name, ".", "_", -1), "-", "_", -1) unit = s.unit // nolint: ineffassign shortDesc = fmt.Sprintf("Server Parameter: %s", s.name) subsystem = "settings" From 5145620988a075c8f4c08ab045145510e3ddf1df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jan 2025 18:36:32 +0100 Subject: [PATCH 196/228] Bump github.com/prometheus/exporter-toolkit from 0.13.1 to 0.13.2 (#1108) Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.13.1 to 0.13.2. - [Release notes](https://github.com/prometheus/exporter-toolkit/releases) - [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md) - [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.13.1...v0.13.2) --- updated-dependencies: - dependency-name: github.com/prometheus/exporter-toolkit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 18 +++++++++--------- go.sum | 40 ++++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index bc854c3aa..9cdf3cbec 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,8 @@ require ( github.com/lib/pq v1.10.9 github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_model v0.6.1 - github.com/prometheus/common v0.60.1 - github.com/prometheus/exporter-toolkit v0.13.1 + github.com/prometheus/common v0.61.0 + github.com/prometheus/exporter-toolkit v0.13.2 github.com/smartystreets/goconvey v1.8.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 @@ -36,11 +36,11 @@ require ( github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.28.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/text v0.19.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.32.0 // indirect + golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/protobuf v1.35.2 // indirect ) diff --git a/go.sum b/go.sum index 044805aa2..e20b36f15 100644 --- a/go.sum +++ b/go.sum @@ -54,10 +54,10 @@ github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+ github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= -github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= -github.com/prometheus/exporter-toolkit v0.13.1 h1:Evsh0gWQo2bdOHlnz9+0Nm7/OFfIwhE2Ws4A2jIlR04= -github.com/prometheus/exporter-toolkit v0.13.1/go.mod h1:ujdv2YIOxtdFxxqtloLpbqmxd5J0Le6IITUvIRSWjj0= +github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ= +github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s= +github.com/prometheus/exporter-toolkit v0.13.2 h1:Z02fYtbqTMy2i/f+xZ+UK5jy/bl1Ex3ndzh06T/Q9DQ= +github.com/prometheus/exporter-toolkit v0.13.2/go.mod h1:tCqnfx21q6qN1KA4U3Bfb8uWzXfijIrJz3/kTIqMV7g= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -69,24 +69,24 @@ github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sS github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From bea260951948d8fbf5fdd4059cce9f385aaced36 Mon Sep 17 00:00:00 2001 From: Nicolas Rodriguez Date: Wed, 1 Jan 2025 22:03:43 +0100 Subject: [PATCH 197/228] Checkpoint related columns in PG 17 have been moved from pg_stat_bgwriter to pg_stat_checkpointer (#1072) * Checkpoint related columns in PG 17 have been moved from pg_stat_bgwriter to pg_stat_checkpointer Fix https://github.com/prometheus-community/postgres_exporter/issues/1060 See: https://www.dbi-services.com/blog/postgresql-17-new-catalog-view-pg_stat_checkpointer/ Signed-off-by: Nicolas Rodriguez * Add support for pg_stat_checkpointer See: https://www.dbi-services.com/blog/postgresql-17-new-catalog-view-pg_stat_checkpointer/ Signed-off-by: Nicolas Rodriguez * Run integration tests with Postgres 17 Signed-off-by: Nicolas Rodriguez * Update date in file header Signed-off-by: Nicolas Rodriguez --------- Signed-off-by: Nicolas Rodriguez --- .circleci/config.yml | 1 + collector/pg_stat_bgwriter.go | 275 +++++++++++++++---------- collector/pg_stat_bgwriter_test.go | 4 +- collector/pg_stat_checkpointer.go | 221 ++++++++++++++++++++ collector/pg_stat_checkpointer_test.go | 143 +++++++++++++ 5 files changed, 533 insertions(+), 111 deletions(-) create mode 100644 collector/pg_stat_checkpointer.go create mode 100644 collector/pg_stat_checkpointer_test.go diff --git a/.circleci/config.yml b/.circleci/config.yml index d745e30f2..6cfc880d2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -63,6 +63,7 @@ workflows: - cimg/postgres:14.9 - cimg/postgres:15.4 - cimg/postgres:16.0 + - cimg/postgres:17.0 - prometheus/build: name: build parallelism: 3 diff --git a/collector/pg_stat_bgwriter.go b/collector/pg_stat_bgwriter.go index ec446d58c..6e3bd09cb 100644 --- a/collector/pg_stat_bgwriter.go +++ b/collector/pg_stat_bgwriter.go @@ -17,6 +17,7 @@ import ( "context" "database/sql" + "github.com/blang/semver/v4" "github.com/prometheus/client_golang/prometheus" ) @@ -101,7 +102,7 @@ var ( prometheus.Labels{}, ) - statBGWriterQuery = `SELECT + statBGWriterQueryBefore17 = `SELECT checkpoints_timed ,checkpoints_req ,checkpoint_write_time @@ -114,121 +115,177 @@ var ( ,buffers_alloc ,stats_reset FROM pg_stat_bgwriter;` + + statBGWriterQueryAfter17 = `SELECT + buffers_clean + ,maxwritten_clean + ,buffers_alloc + ,stats_reset + FROM pg_stat_bgwriter;` ) func (PGStatBGWriterCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { - db := instance.getDB() - row := db.QueryRowContext(ctx, - statBGWriterQuery) + if instance.version.GE(semver.MustParse("17.0.0")) { + db := instance.getDB() + row := db.QueryRowContext(ctx, statBGWriterQueryAfter17) - var cpt, cpr, bcp, bc, mwc, bb, bbf, ba sql.NullInt64 - var cpwt, cpst sql.NullFloat64 - var sr sql.NullTime + var bc, mwc, ba sql.NullInt64 + var sr sql.NullTime - err := row.Scan(&cpt, &cpr, &cpwt, &cpst, &bcp, &bc, &mwc, &bb, &bbf, &ba, &sr) - if err != nil { - return err - } + err := row.Scan(&bc, &mwc, &ba, &sr) + if err != nil { + return err + } - cptMetric := 0.0 - if cpt.Valid { - cptMetric = float64(cpt.Int64) - } - ch <- prometheus.MustNewConstMetric( - statBGWriterCheckpointsTimedDesc, - prometheus.CounterValue, - cptMetric, - ) - cprMetric := 0.0 - if cpr.Valid { - cprMetric = float64(cpr.Int64) - } - ch <- prometheus.MustNewConstMetric( - statBGWriterCheckpointsReqDesc, - prometheus.CounterValue, - cprMetric, - ) - cpwtMetric := 0.0 - if cpwt.Valid { - cpwtMetric = float64(cpwt.Float64) - } - ch <- prometheus.MustNewConstMetric( - statBGWriterCheckpointsReqTimeDesc, - prometheus.CounterValue, - cpwtMetric, - ) - cpstMetric := 0.0 - if cpst.Valid { - cpstMetric = float64(cpst.Float64) - } - ch <- prometheus.MustNewConstMetric( - statBGWriterCheckpointsSyncTimeDesc, - prometheus.CounterValue, - cpstMetric, - ) - bcpMetric := 0.0 - if bcp.Valid { - bcpMetric = float64(bcp.Int64) - } - ch <- prometheus.MustNewConstMetric( - statBGWriterBuffersCheckpointDesc, - prometheus.CounterValue, - bcpMetric, - ) - bcMetric := 0.0 - if bc.Valid { - bcMetric = float64(bc.Int64) - } - ch <- prometheus.MustNewConstMetric( - statBGWriterBuffersCleanDesc, - prometheus.CounterValue, - bcMetric, - ) - mwcMetric := 0.0 - if mwc.Valid { - mwcMetric = float64(mwc.Int64) - } - ch <- prometheus.MustNewConstMetric( - statBGWriterMaxwrittenCleanDesc, - prometheus.CounterValue, - mwcMetric, - ) - bbMetric := 0.0 - if bb.Valid { - bbMetric = float64(bb.Int64) - } - ch <- prometheus.MustNewConstMetric( - statBGWriterBuffersBackendDesc, - prometheus.CounterValue, - bbMetric, - ) - bbfMetric := 0.0 - if bbf.Valid { - bbfMetric = float64(bbf.Int64) - } - ch <- prometheus.MustNewConstMetric( - statBGWriterBuffersBackendFsyncDesc, - prometheus.CounterValue, - bbfMetric, - ) - baMetric := 0.0 - if ba.Valid { - baMetric = float64(ba.Int64) - } - ch <- prometheus.MustNewConstMetric( - statBGWriterBuffersAllocDesc, - prometheus.CounterValue, - baMetric, - ) - srMetric := 0.0 - if sr.Valid { - srMetric = float64(sr.Time.Unix()) + bcMetric := 0.0 + if bc.Valid { + bcMetric = float64(bc.Int64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterBuffersCleanDesc, + prometheus.CounterValue, + bcMetric, + ) + mwcMetric := 0.0 + if mwc.Valid { + mwcMetric = float64(mwc.Int64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterMaxwrittenCleanDesc, + prometheus.CounterValue, + mwcMetric, + ) + baMetric := 0.0 + if ba.Valid { + baMetric = float64(ba.Int64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterBuffersAllocDesc, + prometheus.CounterValue, + baMetric, + ) + srMetric := 0.0 + if sr.Valid { + srMetric = float64(sr.Time.Unix()) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterStatsResetDesc, + prometheus.CounterValue, + srMetric, + ) + } else { + db := instance.getDB() + row := db.QueryRowContext(ctx, statBGWriterQueryBefore17) + + var cpt, cpr, bcp, bc, mwc, bb, bbf, ba sql.NullInt64 + var cpwt, cpst sql.NullFloat64 + var sr sql.NullTime + + err := row.Scan(&cpt, &cpr, &cpwt, &cpst, &bcp, &bc, &mwc, &bb, &bbf, &ba, &sr) + if err != nil { + return err + } + + cptMetric := 0.0 + if cpt.Valid { + cptMetric = float64(cpt.Int64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterCheckpointsTimedDesc, + prometheus.CounterValue, + cptMetric, + ) + cprMetric := 0.0 + if cpr.Valid { + cprMetric = float64(cpr.Int64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterCheckpointsReqDesc, + prometheus.CounterValue, + cprMetric, + ) + cpwtMetric := 0.0 + if cpwt.Valid { + cpwtMetric = float64(cpwt.Float64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterCheckpointsReqTimeDesc, + prometheus.CounterValue, + cpwtMetric, + ) + cpstMetric := 0.0 + if cpst.Valid { + cpstMetric = float64(cpst.Float64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterCheckpointsSyncTimeDesc, + prometheus.CounterValue, + cpstMetric, + ) + bcpMetric := 0.0 + if bcp.Valid { + bcpMetric = float64(bcp.Int64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterBuffersCheckpointDesc, + prometheus.CounterValue, + bcpMetric, + ) + bcMetric := 0.0 + if bc.Valid { + bcMetric = float64(bc.Int64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterBuffersCleanDesc, + prometheus.CounterValue, + bcMetric, + ) + mwcMetric := 0.0 + if mwc.Valid { + mwcMetric = float64(mwc.Int64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterMaxwrittenCleanDesc, + prometheus.CounterValue, + mwcMetric, + ) + bbMetric := 0.0 + if bb.Valid { + bbMetric = float64(bb.Int64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterBuffersBackendDesc, + prometheus.CounterValue, + bbMetric, + ) + bbfMetric := 0.0 + if bbf.Valid { + bbfMetric = float64(bbf.Int64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterBuffersBackendFsyncDesc, + prometheus.CounterValue, + bbfMetric, + ) + baMetric := 0.0 + if ba.Valid { + baMetric = float64(ba.Int64) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterBuffersAllocDesc, + prometheus.CounterValue, + baMetric, + ) + srMetric := 0.0 + if sr.Valid { + srMetric = float64(sr.Time.Unix()) + } + ch <- prometheus.MustNewConstMetric( + statBGWriterStatsResetDesc, + prometheus.CounterValue, + srMetric, + ) } - ch <- prometheus.MustNewConstMetric( - statBGWriterStatsResetDesc, - prometheus.CounterValue, - srMetric, - ) return nil } diff --git a/collector/pg_stat_bgwriter_test.go b/collector/pg_stat_bgwriter_test.go index 1c2cf98de..6fde2fb6a 100644 --- a/collector/pg_stat_bgwriter_test.go +++ b/collector/pg_stat_bgwriter_test.go @@ -52,7 +52,7 @@ func TestPGStatBGWriterCollector(t *testing.T) { rows := sqlmock.NewRows(columns). AddRow(354, 4945, 289097744, 1242257, int64(3275602074), 89320867, 450139, 2034563757, 0, int64(2725688749), srT) - mock.ExpectQuery(sanitizeQuery(statBGWriterQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(statBGWriterQueryBefore17)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -113,7 +113,7 @@ func TestPGStatBGWriterCollectorNullValues(t *testing.T) { rows := sqlmock.NewRows(columns). AddRow(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) - mock.ExpectQuery(sanitizeQuery(statBGWriterQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(statBGWriterQueryBefore17)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { diff --git a/collector/pg_stat_checkpointer.go b/collector/pg_stat_checkpointer.go new file mode 100644 index 000000000..284cf650c --- /dev/null +++ b/collector/pg_stat_checkpointer.go @@ -0,0 +1,221 @@ +// Copyright 2024 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 collector + +import ( + "context" + "database/sql" + + "github.com/prometheus/client_golang/prometheus" +) + +const statCheckpointerSubsystem = "stat_checkpointer" + +func init() { + // WARNING: + // Disabled by default because this set of metrics is only available from Postgres 17 + registerCollector(statCheckpointerSubsystem, defaultDisabled, NewPGStatCheckpointerCollector) +} + +type PGStatCheckpointerCollector struct { +} + +func NewPGStatCheckpointerCollector(collectorConfig) (Collector, error) { + return &PGStatCheckpointerCollector{}, nil +} + +var ( + statCheckpointerNumTimedDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statCheckpointerSubsystem, "num_timed_total"), + "Number of scheduled checkpoints due to timeout", + []string{}, + prometheus.Labels{}, + ) + statCheckpointerNumRequestedDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statCheckpointerSubsystem, "num_requested_total"), + "Number of requested checkpoints that have been performed", + []string{}, + prometheus.Labels{}, + ) + statCheckpointerRestartpointsTimedDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statCheckpointerSubsystem, "restartpoints_timed_total"), + "Number of scheduled restartpoints due to timeout or after a failed attempt to perform it", + []string{}, + prometheus.Labels{}, + ) + statCheckpointerRestartpointsReqDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statCheckpointerSubsystem, "restartpoints_req_total"), + "Number of requested restartpoints", + []string{}, + prometheus.Labels{}, + ) + statCheckpointerRestartpointsDoneDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statCheckpointerSubsystem, "restartpoints_done_total"), + "Number of restartpoints that have been performed", + []string{}, + prometheus.Labels{}, + ) + statCheckpointerWriteTimeDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statCheckpointerSubsystem, "write_time_total"), + "Total amount of time that has been spent in the portion of processing checkpoints and restartpoints where files are written to disk, in milliseconds", + []string{}, + prometheus.Labels{}, + ) + statCheckpointerSyncTimeDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statCheckpointerSubsystem, "sync_time_total"), + "Total amount of time that has been spent in the portion of processing checkpoints and restartpoints where files are synchronized to disk, in milliseconds", + []string{}, + prometheus.Labels{}, + ) + statCheckpointerBuffersWrittenDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statCheckpointerSubsystem, "buffers_written_total"), + "Number of buffers written during checkpoints and restartpoints", + []string{}, + prometheus.Labels{}, + ) + statCheckpointerStatsResetDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statCheckpointerSubsystem, "stats_reset_total"), + "Time at which these statistics were last reset", + []string{}, + prometheus.Labels{}, + ) + + statCheckpointerQuery = `SELECT + num_timed + ,num_requested + ,restartpoints_timed + ,restartpoints_req + ,restartpoints_done + ,write_time + ,sync_time + ,buffers_written + ,stats_reset + FROM pg_stat_checkpointer;` +) + +func (PGStatCheckpointerCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + row := db.QueryRowContext(ctx, statCheckpointerQuery) + + // num_timed = nt = bigint + // num_requested = nr = bigint + // restartpoints_timed = rpt = bigint + // restartpoints_req = rpr = bigint + // restartpoints_done = rpd = bigint + // write_time = wt = double precision + // sync_time = st = double precision + // buffers_written = bw = bigint + // stats_reset = sr = timestamp + + var nt, nr, rpt, rpr, rpd, bw sql.NullInt64 + var wt, st sql.NullFloat64 + var sr sql.NullTime + + err := row.Scan(&nt, &nr, &rpt, &rpr, &rpd, &wt, &st, &bw, &sr) + if err != nil { + return err + } + + ntMetric := 0.0 + if nt.Valid { + ntMetric = float64(nt.Int64) + } + ch <- prometheus.MustNewConstMetric( + statCheckpointerNumTimedDesc, + prometheus.CounterValue, + ntMetric, + ) + + nrMetric := 0.0 + if nr.Valid { + nrMetric = float64(nr.Int64) + } + ch <- prometheus.MustNewConstMetric( + statCheckpointerNumRequestedDesc, + prometheus.CounterValue, + nrMetric, + ) + + rptMetric := 0.0 + if rpt.Valid { + rptMetric = float64(rpt.Int64) + } + ch <- prometheus.MustNewConstMetric( + statCheckpointerRestartpointsTimedDesc, + prometheus.CounterValue, + rptMetric, + ) + + rprMetric := 0.0 + if rpr.Valid { + rprMetric = float64(rpr.Int64) + } + ch <- prometheus.MustNewConstMetric( + statCheckpointerRestartpointsReqDesc, + prometheus.CounterValue, + rprMetric, + ) + + rpdMetric := 0.0 + if rpd.Valid { + rpdMetric = float64(rpd.Int64) + } + ch <- prometheus.MustNewConstMetric( + statCheckpointerRestartpointsDoneDesc, + prometheus.CounterValue, + rpdMetric, + ) + + wtMetric := 0.0 + if wt.Valid { + wtMetric = float64(wt.Float64) + } + ch <- prometheus.MustNewConstMetric( + statCheckpointerWriteTimeDesc, + prometheus.CounterValue, + wtMetric, + ) + + stMetric := 0.0 + if st.Valid { + stMetric = float64(st.Float64) + } + ch <- prometheus.MustNewConstMetric( + statCheckpointerSyncTimeDesc, + prometheus.CounterValue, + stMetric, + ) + + bwMetric := 0.0 + if bw.Valid { + bwMetric = float64(bw.Int64) + } + ch <- prometheus.MustNewConstMetric( + statCheckpointerBuffersWrittenDesc, + prometheus.CounterValue, + bwMetric, + ) + + srMetric := 0.0 + if sr.Valid { + srMetric = float64(sr.Time.Unix()) + } + ch <- prometheus.MustNewConstMetric( + statCheckpointerStatsResetDesc, + prometheus.CounterValue, + srMetric, + ) + + return nil +} diff --git a/collector/pg_stat_checkpointer_test.go b/collector/pg_stat_checkpointer_test.go new file mode 100644 index 000000000..2f59343bb --- /dev/null +++ b/collector/pg_stat_checkpointer_test.go @@ -0,0 +1,143 @@ +// Copyright 2024 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 collector + +import ( + "context" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGStatCheckpointerCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{ + "num_timed", + "num_requested", + "restartpoints_timed", + "restartpoints_req", + "restartpoints_done", + "write_time", + "sync_time", + "buffers_written", + "stats_reset"} + + srT, err := time.Parse("2006-01-02 15:04:05.00000-07", "2023-05-25 17:10:42.81132-07") + if err != nil { + t.Fatalf("Error parsing time: %s", err) + } + + rows := sqlmock.NewRows(columns). + AddRow(354, 4945, 289097744, 1242257, int64(3275602074), 89320867, 450139, 2034563757, srT) + mock.ExpectQuery(sanitizeQuery(statCheckpointerQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatCheckpointerCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatCheckpointerCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 354}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 4945}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 289097744}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 1242257}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 3275602074}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 89320867}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 450139}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 2034563757}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 1685059842}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} + +func TestPGStatCheckpointerCollectorNullValues(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{ + "num_timed", + "num_requested", + "restartpoints_timed", + "restartpoints_req", + "restartpoints_done", + "write_time", + "sync_time", + "buffers_written", + "stats_reset"} + + rows := sqlmock.NewRows(columns). + AddRow(nil, nil, nil, nil, nil, nil, nil, nil, nil) + mock.ExpectQuery(sanitizeQuery(statCheckpointerQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatCheckpointerCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatCheckpointerCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{}, metricType: dto.MetricType_COUNTER, value: 0}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From ecb5ec5dff0cf2b3eb3668a7fee30d8ad11c82fa Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Tue, 7 Jan 2025 09:28:42 +0100 Subject: [PATCH 198/228] Update common Prometheus files (#1090) Signed-off-by: prombot --- .yamllint | 2 +- Makefile.common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.yamllint b/.yamllint index 1859cb624..8d09c375f 100644 --- a/.yamllint +++ b/.yamllint @@ -1,7 +1,7 @@ --- extends: default ignore: | - ui/react-app/node_modules + **/node_modules rules: braces: diff --git a/Makefile.common b/Makefile.common index cbb5d8638..09e5bff85 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.60.2 +GOLANGCI_LINT_VERSION ?= v1.61.0 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) From 9de4f19d43427c24947ba7db7d82127141bd5fa4 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Tue, 7 Jan 2025 21:20:19 +0100 Subject: [PATCH 199/228] Update common Prometheus files (#1110) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 4 ++-- Makefile.common | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 305146993..01b943b9b 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -26,7 +26,7 @@ jobs: - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install Go - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 with: go-version: 1.23.x - name: Install snmp_exporter/generator dependencies @@ -36,4 +36,4 @@ jobs: uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1 with: args: --verbose - version: v1.61.0 + version: v1.62.0 diff --git a/Makefile.common b/Makefile.common index 09e5bff85..fc47bdbb2 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.61.0 +GOLANGCI_LINT_VERSION ?= v1.62.0 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) From 7d4c278221e95ddbc62108973e5828a3ffaa2eb8 Mon Sep 17 00:00:00 2001 From: Khiem Doan Date: Mon, 13 Jan 2025 09:24:15 +0700 Subject: [PATCH 200/228] Add Postgres 17 for CI test (#1105) Signed-off-by: Khiem Doan --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c464e210..9494acb24 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Prometheus exporter for PostgreSQL server metrics. -CI Tested PostgreSQL versions: `11`, `12`, `13`, `14`, `15`, `16` +CI Tested PostgreSQL versions: `11`, `12`, `13`, `14`, `15`, `16`, `17`. ## Quick Start This package is available for Docker: From 3acc4793fc63ffb3088668f285ba658429c8806c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Feb 2025 03:35:38 +0100 Subject: [PATCH 201/228] Bump github.com/prometheus/common from 0.61.0 to 0.62.0 (#1118) Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.61.0 to 0.62.0. - [Release notes](https://github.com/prometheus/common/releases) - [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md) - [Commits](https://github.com/prometheus/common/compare/v0.61.0...v0.62.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 9cdf3cbec..b2c9500d0 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/lib/pq v1.10.9 github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_model v0.6.1 - github.com/prometheus/common v0.61.0 + github.com/prometheus/common v0.62.0 github.com/prometheus/exporter-toolkit v0.13.2 github.com/smartystreets/goconvey v1.8.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c @@ -37,10 +37,10 @@ require ( github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/net v0.32.0 // indirect + golang.org/x/net v0.33.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect - google.golang.org/protobuf v1.35.2 // indirect + google.golang.org/protobuf v1.36.1 // indirect ) diff --git a/go.sum b/go.sum index e20b36f15..a6dd72407 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+ github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ= -github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/exporter-toolkit v0.13.2 h1:Z02fYtbqTMy2i/f+xZ+UK5jy/bl1Ex3ndzh06T/Q9DQ= github.com/prometheus/exporter-toolkit v0.13.2/go.mod h1:tCqnfx21q6qN1KA4U3Bfb8uWzXfijIrJz3/kTIqMV7g= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= @@ -75,8 +75,8 @@ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8 github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= -golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= @@ -85,8 +85,8 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From d85a7710bf084309413986c577ee03d09fb8d2ef Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Fri, 14 Feb 2025 09:36:03 +0100 Subject: [PATCH 202/228] Update common Prometheus files (#1124) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 6 +++--- Makefile.common | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 01b943b9b..def9007ac 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -26,14 +26,14 @@ jobs: - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install Go - uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 + uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 with: go-version: 1.23.x - name: Install snmp_exporter/generator dependencies run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1 + uses: golangci/golangci-lint-action@ec5d18412c0aeab7936cb16880d708ba2a64e1ae # v6.2.0 with: args: --verbose - version: v1.62.0 + version: v1.63.4 diff --git a/Makefile.common b/Makefile.common index fc47bdbb2..d1576bb31 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.62.0 +GOLANGCI_LINT_VERSION ?= v1.63.4 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) From 072864d179de04327840bc32fa0b1765f250b1f3 Mon Sep 17 00:00:00 2001 From: Nevermind <79126473+NevermindZ4@users.noreply.github.com> Date: Sat, 15 Feb 2025 14:54:12 +0100 Subject: [PATCH 203/228] pg_stat_statements PG17 (#1114) Signed-off-by: Nevermind <79126473+NevermindZ4@users.noreply.github.com> --- collector/pg_stat_statements.go | 30 +++++++++++++++++-- collector/pg_stat_statements_test.go | 43 ++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/collector/pg_stat_statements.go b/collector/pg_stat_statements.go index 7926f533e..cabdc3619 100644 --- a/collector/pg_stat_statements.go +++ b/collector/pg_stat_statements.go @@ -112,12 +112,38 @@ var ( ) ORDER BY seconds_total DESC LIMIT 100;` + + pgStatStatementsQuery_PG17 = `SELECT + pg_get_userbyid(userid) as user, + pg_database.datname, + pg_stat_statements.queryid, + pg_stat_statements.calls as calls_total, + pg_stat_statements.total_exec_time / 1000.0 as seconds_total, + pg_stat_statements.rows as rows_total, + pg_stat_statements.shared_blk_read_time / 1000.0 as block_read_seconds_total, + pg_stat_statements.shared_blk_write_time / 1000.0 as block_write_seconds_total + FROM pg_stat_statements + JOIN pg_database + ON pg_database.oid = pg_stat_statements.dbid + WHERE + total_exec_time > ( + SELECT percentile_cont(0.1) + WITHIN GROUP (ORDER BY total_exec_time) + FROM pg_stat_statements + ) + ORDER BY seconds_total DESC + LIMIT 100;` ) func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { - query := pgStatStatementsQuery - if instance.version.GE(semver.MustParse("13.0.0")) { + var query string + switch { + case instance.version.GE(semver.MustParse("17.0.0")): + query = pgStatStatementsQuery_PG17 + case instance.version.GE(semver.MustParse("13.0.0")): query = pgStatStatementsNewQuery + default: + query = pgStatStatementsQuery } db := instance.getDB() diff --git a/collector/pg_stat_statements_test.go b/collector/pg_stat_statements_test.go index 08aba34c2..ea035f557 100644 --- a/collector/pg_stat_statements_test.go +++ b/collector/pg_stat_statements_test.go @@ -151,3 +151,46 @@ func TestPGStateStatementsCollectorNewPG(t *testing.T) { t.Errorf("there were unfulfilled exceptions: %s", err) } } + +func TestPGStateStatementsCollector_PG17(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db, version: semver.MustParse("17.0.0")} + + columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} + rows := sqlmock.NewRows(columns). + AddRow("postgres", "postgres", 1500, 5, 0.4, 100, 0.1, 0.2) + mock.ExpectQuery(sanitizeQuery(pgStatStatementsQuery_PG17)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatStatementsCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatStatementsCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 5}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.4}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 100}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.1}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.2}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From 9e42fc0145a9d780d824d961afb7b70867558424 Mon Sep 17 00:00:00 2001 From: Michael Todorovic Date: Sat, 15 Feb 2025 15:00:48 +0100 Subject: [PATCH 204/228] fix: handle pg_replication_slots on pg<13 (#1098) * fix: handle pg_replication_slots on pg<13 Signed-off-by: Michael Todorovic * fix: tests Signed-off-by: Michael Todorovic --------- Signed-off-by: Michael Todorovic --- collector/pg_replication_slot.go | 38 ++++++++++++++++++++++++--- collector/pg_replication_slot_test.go | 17 ++++++------ 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/collector/pg_replication_slot.go b/collector/pg_replication_slot.go index 27ccddefd..e6c9773eb 100644 --- a/collector/pg_replication_slot.go +++ b/collector/pg_replication_slot.go @@ -18,6 +18,7 @@ import ( "database/sql" "log/slog" + "github.com/blang/semver/v4" "github.com/prometheus/client_golang/prometheus" ) @@ -81,8 +82,18 @@ var ( "availability of WAL files claimed by this slot", []string{"slot_name", "slot_type", "wal_status"}, nil, ) - pgReplicationSlotQuery = `SELECT + slot_name, + slot_type, + CASE WHEN pg_is_in_recovery() THEN + pg_last_wal_receive_lsn() - '0/0' + ELSE + pg_current_wal_lsn() - '0/0' + END AS current_wal_lsn, + COALESCE(confirmed_flush_lsn, '0/0') - '0/0' AS confirmed_flush_lsn, + active + FROM pg_replication_slots;` + pgReplicationSlotNewQuery = `SELECT slot_name, slot_type, CASE WHEN pg_is_in_recovery() THEN @@ -98,9 +109,15 @@ var ( ) func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + query := pgReplicationSlotQuery + abovePG13 := instance.version.GTE(semver.MustParse("13.0.0")) + if abovePG13 { + query = pgReplicationSlotNewQuery + } + db := instance.getDB() rows, err := db.QueryContext(ctx, - pgReplicationSlotQuery) + query) if err != nil { return err } @@ -114,7 +131,22 @@ func (PGReplicationSlotCollector) Update(ctx context.Context, instance *instance var isActive sql.NullBool var safeWalSize sql.NullInt64 var walStatus sql.NullString - if err := rows.Scan(&slotName, &slotType, &walLSN, &flushLSN, &isActive, &safeWalSize, &walStatus); err != nil { + + r := []any{ + &slotName, + &slotType, + &walLSN, + &flushLSN, + &isActive, + } + + if abovePG13 { + r = append(r, &safeWalSize) + r = append(r, &walStatus) + } + + err := rows.Scan(r...) + if err != nil { return err } diff --git a/collector/pg_replication_slot_test.go b/collector/pg_replication_slot_test.go index 174743ac3..981b5db62 100644 --- a/collector/pg_replication_slot_test.go +++ b/collector/pg_replication_slot_test.go @@ -17,6 +17,7 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + "github.com/blang/semver/v4" "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" "github.com/smartystreets/goconvey/convey" @@ -29,12 +30,12 @@ func TestPgReplicationSlotCollectorActive(t *testing.T) { } defer db.Close() - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("13.3.7")} columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active", "safe_wal_size", "wal_status"} rows := sqlmock.NewRows(columns). AddRow("test_slot", "physical", 5, 3, true, 323906992, "reserved") - mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(pgReplicationSlotNewQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -72,12 +73,12 @@ func TestPgReplicationSlotCollectorInActive(t *testing.T) { } defer db.Close() - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("13.3.7")} columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active", "safe_wal_size", "wal_status"} rows := sqlmock.NewRows(columns). AddRow("test_slot", "physical", 6, 12, false, -4000, "extended") - mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(pgReplicationSlotNewQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -115,12 +116,12 @@ func TestPgReplicationSlotCollectorActiveNil(t *testing.T) { } defer db.Close() - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("13.3.7")} columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active", "safe_wal_size", "wal_status"} rows := sqlmock.NewRows(columns). AddRow("test_slot", "physical", 6, 12, nil, nil, "lost") - mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(pgReplicationSlotNewQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -156,12 +157,12 @@ func TestPgReplicationSlotCollectorTestNilValues(t *testing.T) { } defer db.Close() - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("13.3.7")} columns := []string{"slot_name", "slot_type", "current_wal_lsn", "confirmed_flush_lsn", "active", "safe_wal_size", "wal_status"} rows := sqlmock.NewRows(columns). AddRow(nil, nil, nil, nil, true, nil, nil) - mock.ExpectQuery(sanitizeQuery(pgReplicationSlotQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(pgReplicationSlotNewQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { From 2ee2a8fa7cbd7b07c58a5e40998d6e1f469dd1af Mon Sep 17 00:00:00 2001 From: Felipe Galindo Sanchez Date: Sat, 15 Feb 2025 06:08:24 -0800 Subject: [PATCH 205/228] feat: add wait/backend to pg_stat_activity (#1106) Signed-off-by: Felipe Galindo Sanchez --- cmd/postgres_exporter/postgres_exporter.go | 3 +++ cmd/postgres_exporter/queries.go | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index 90f26beb0..d76e2baed 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -251,6 +251,9 @@ var builtinMetricMaps = map[string]intermediateMetricMap{ "state": {LABEL, "connection state", nil, semver.MustParseRange(">=9.2.0")}, "usename": {LABEL, "connection usename", nil, nil}, "application_name": {LABEL, "connection application_name", nil, nil}, + "backend_type": {LABEL, "connection backend_type", nil, nil}, + "wait_event_type": {LABEL, "connection wait_event_type", nil, nil}, + "wait_event": {LABEL, "connection wait_event", nil, nil}, "count": {GAUGE, "number of connections in this state", nil, nil}, "max_tx_duration": {GAUGE, "max duration in seconds any active transaction has been running", nil, nil}, }, diff --git a/cmd/postgres_exporter/queries.go b/cmd/postgres_exporter/queries.go index 7090606e1..80be72d54 100644 --- a/cmd/postgres_exporter/queries.go +++ b/cmd/postgres_exporter/queries.go @@ -115,6 +115,9 @@ var queryOverrides = map[string][]OverrideQuery{ tmp.state, tmp2.usename, tmp2.application_name, + tmp2.backend_type, + tmp2.wait_event_type, + tmp2.wait_event, COALESCE(count,0) as count, COALESCE(max_tx_duration,0) as max_tx_duration FROM @@ -133,9 +136,13 @@ var queryOverrides = map[string][]OverrideQuery{ state, usename, application_name, + backend_type, + wait_event_type, + wait_event, count(*) AS count, MAX(EXTRACT(EPOCH FROM now() - xact_start))::float AS max_tx_duration - FROM pg_stat_activity GROUP BY datname,state,usename,application_name) AS tmp2 + FROM pg_stat_activity + GROUP BY datname,state,usename,application_name,backend_type,wait_event_type,wait_event) AS tmp2 ON tmp.state = tmp2.state AND pg_database.datname = tmp2.datname `, }, From c3885e840a1dd8eea2a878c044a92088c1820f0e Mon Sep 17 00:00:00 2001 From: Conrad Hoffmann <1226676+bitfehler@users.noreply.github.com> Date: Sat, 15 Feb 2025 15:15:44 +0100 Subject: [PATCH 206/228] Export last replay age in replication collector (#1085) The exported replication lag does not handle all failure modes, and can report 0 for replicas that are out of sync and incapable of recovery. A proper replacement for that metric would require a different approach (see e.g. #1007), but for a lot of folks, simply exporting the age of the last replay can provide a pretty strong signal for something being amiss. I think this solution might be preferable to #977, though the lag metric needs to be fixed or abandoned eventually. Signed-off-by: Conrad Hoffmann --- collector/pg_replication.go | 19 +++++++++++++++++-- collector/pg_replication_test.go | 5 +++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/collector/pg_replication.go b/collector/pg_replication.go index 6067cc9b1..7f8b2fbd7 100644 --- a/collector/pg_replication.go +++ b/collector/pg_replication.go @@ -51,6 +51,15 @@ var ( "Indicates if the server is a replica", []string{}, nil, ) + pgReplicationLastReplay = prometheus.NewDesc( + prometheus.BuildFQName( + namespace, + replicationSubsystem, + "last_replay_seconds", + ), + "Age of last replay in seconds", + []string{}, nil, + ) pgReplicationQuery = `SELECT CASE @@ -61,7 +70,8 @@ var ( CASE WHEN pg_is_in_recovery() THEN 1 ELSE 0 - END as is_replica` + END as is_replica, + GREATEST (0, EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))) as last_replay` ) func (c *PGReplicationCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { @@ -72,7 +82,8 @@ func (c *PGReplicationCollector) Update(ctx context.Context, instance *instance, var lag float64 var isReplica int64 - err := row.Scan(&lag, &isReplica) + var replayAge float64 + err := row.Scan(&lag, &isReplica, &replayAge) if err != nil { return err } @@ -84,5 +95,9 @@ func (c *PGReplicationCollector) Update(ctx context.Context, instance *instance, pgReplicationIsReplica, prometheus.GaugeValue, float64(isReplica), ) + ch <- prometheus.MustNewConstMetric( + pgReplicationLastReplay, + prometheus.GaugeValue, replayAge, + ) return nil } diff --git a/collector/pg_replication_test.go b/collector/pg_replication_test.go index b6df698e3..a48e9fd69 100644 --- a/collector/pg_replication_test.go +++ b/collector/pg_replication_test.go @@ -31,9 +31,9 @@ func TestPgReplicationCollector(t *testing.T) { inst := &instance{db: db} - columns := []string{"lag", "is_replica"} + columns := []string{"lag", "is_replica", "last_replay"} rows := sqlmock.NewRows(columns). - AddRow(1000, 1) + AddRow(1000, 1, 3) mock.ExpectQuery(sanitizeQuery(pgReplicationQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -49,6 +49,7 @@ func TestPgReplicationCollector(t *testing.T) { expected := []MetricResult{ {labels: labelMap{}, value: 1000, metricType: dto.MetricType_GAUGE}, {labels: labelMap{}, value: 1, metricType: dto.MetricType_GAUGE}, + {labels: labelMap{}, value: 3, metricType: dto.MetricType_GAUGE}, } convey.Convey("Metrics comparison", t, func() { From 99e1b5118caf5094ed69bd7e11cd601e0431bfb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2025 10:01:47 -0500 Subject: [PATCH 207/228] Bump github.com/prometheus/exporter-toolkit from 0.13.2 to 0.14.0 (#1126) Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.13.2 to 0.14.0. - [Release notes](https://github.com/prometheus/exporter-toolkit/releases) - [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md) - [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.13.2...v0.14.0) --- updated-dependencies: - dependency-name: github.com/prometheus/exporter-toolkit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index b2c9500d0..a7b376b4e 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.62.0 - github.com/prometheus/exporter-toolkit v0.13.2 + github.com/prometheus/exporter-toolkit v0.14.0 github.com/smartystreets/goconvey v1.8.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 @@ -36,11 +36,11 @@ require ( github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.31.0 // indirect + golang.org/x/crypto v0.32.0 // indirect golang.org/x/net v0.33.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect + golang.org/x/sys v0.29.0 // indirect golang.org/x/text v0.21.0 // indirect google.golang.org/protobuf v1.36.1 // indirect ) diff --git a/go.sum b/go.sum index a6dd72407..a57fc83c1 100644 --- a/go.sum +++ b/go.sum @@ -56,8 +56,8 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= -github.com/prometheus/exporter-toolkit v0.13.2 h1:Z02fYtbqTMy2i/f+xZ+UK5jy/bl1Ex3ndzh06T/Q9DQ= -github.com/prometheus/exporter-toolkit v0.13.2/go.mod h1:tCqnfx21q6qN1KA4U3Bfb8uWzXfijIrJz3/kTIqMV7g= +github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg= +github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -73,16 +73,16 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= From 4c170ed56460028f5c02d16a5576250312eecf89 Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Sat, 15 Feb 2025 10:35:04 -0500 Subject: [PATCH 208/228] Fix missing dsn sanitization for logging (#1104) This log line was not sanitized previously which could result in logging sensitive information. I have scanned the rest of the files and I don't see anywhere else that DSN is used in a log line without this filter. Resolves #1042 Signed-off-by: Joe Adams --- cmd/postgres_exporter/postgres_exporter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index d76e2baed..a76479611 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -681,7 +681,7 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) { if err := e.scrapeDSN(ch, dsn); err != nil { errorsCount++ - logger.Error("error scraping dsn", "err", err, "dsn", dsn) + logger.Error("error scraping dsn", "err", err, "dsn", loggableDSN(dsn)) if _, ok := err.(*ErrorConnectToServer); ok { connectionErrorsCount++ From 8bb1a41abf0cfc6baf1bf272a7cf8989d1958dde Mon Sep 17 00:00:00 2001 From: Nicolas Rodriguez Date: Thu, 20 Feb 2025 03:49:11 +0100 Subject: [PATCH 209/228] Skip pg_stat_checkpointer collector if pg<17 (#1112) * fix: skip collector if pg<17 Signed-off-by: Michael Todorovic * fix: better condition Signed-off-by: Michael Todorovic * fix: fix PGStatCheckpointerCollector tests Signed-off-by: Nicolas Rodriguez --------- Signed-off-by: Michael Todorovic Signed-off-by: Nicolas Rodriguez Co-authored-by: Michael Todorovic --- collector/pg_stat_checkpointer.go | 16 +++++++++++++--- collector/pg_stat_checkpointer_test.go | 5 +++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/collector/pg_stat_checkpointer.go b/collector/pg_stat_checkpointer.go index 284cf650c..31e9c5d62 100644 --- a/collector/pg_stat_checkpointer.go +++ b/collector/pg_stat_checkpointer.go @@ -16,7 +16,9 @@ package collector import ( "context" "database/sql" + "log/slog" + "github.com/blang/semver/v4" "github.com/prometheus/client_golang/prometheus" ) @@ -29,10 +31,11 @@ func init() { } type PGStatCheckpointerCollector struct { + log *slog.Logger } -func NewPGStatCheckpointerCollector(collectorConfig) (Collector, error) { - return &PGStatCheckpointerCollector{}, nil +func NewPGStatCheckpointerCollector(config collectorConfig) (Collector, error) { + return &PGStatCheckpointerCollector{log: config.logger}, nil } var ( @@ -104,8 +107,15 @@ var ( FROM pg_stat_checkpointer;` ) -func (PGStatCheckpointerCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { +func (c PGStatCheckpointerCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { db := instance.getDB() + + before17 := instance.version.LT(semver.MustParse("17.0.0")) + if before17 { + c.log.Warn("pg_stat_checkpointer collector is not available on PostgreSQL < 17.0.0, skipping") + return nil + } + row := db.QueryRowContext(ctx, statCheckpointerQuery) // num_timed = nt = bigint diff --git a/collector/pg_stat_checkpointer_test.go b/collector/pg_stat_checkpointer_test.go index 2f59343bb..9a8dd7f21 100644 --- a/collector/pg_stat_checkpointer_test.go +++ b/collector/pg_stat_checkpointer_test.go @@ -18,6 +18,7 @@ import ( "time" "github.com/DATA-DOG/go-sqlmock" + "github.com/blang/semver/v4" "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" "github.com/smartystreets/goconvey/convey" @@ -30,7 +31,7 @@ func TestPGStatCheckpointerCollector(t *testing.T) { } defer db.Close() - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("17.0.0")} columns := []string{ "num_timed", @@ -92,7 +93,7 @@ func TestPGStatCheckpointerCollectorNullValues(t *testing.T) { } defer db.Close() - inst := &instance{db: db} + inst := &instance{db: db, version: semver.MustParse("17.0.0")} columns := []string{ "num_timed", From 51006aba2f695d318d52b6f5842f18bb52e54b9f Mon Sep 17 00:00:00 2001 From: Joe Adams Date: Fri, 21 Feb 2025 17:38:46 -0500 Subject: [PATCH 210/228] Prep for v0.17 (#1127) Signed-off-by: Joe Adams --- CHANGELOG.md | 22 ++++++++++++++++++++++ VERSION | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 790a109c5..49b6b4101 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +## 0.17.0 / 2025-02-16 + +## What's Changed +* [ENHANCEMENT] Add Postgres 17 for CI test by @khiemdoan in https://github.com/prometheus-community/postgres_exporter/pull/1105 +* [ENHANCEMENT] Add wait/backend to pg_stat_activity by @fgalind1 in https://github.com/prometheus-community/postgres_exporter/pull/1106 +* [ENHANCEMENT] Export last replay age in replication collector by @bitfehler in https://github.com/prometheus-community/postgres_exporter/pull/1085 +* [BUGFIX] Fix pg_long_running_transactions time by @jyothikirant-sayukth in https://github.com/prometheus-community/postgres_exporter/pull/1092 +* [BUGFIX] Fix to replace dashes with underscore in the metric names by @aagarwalla-fx in https://github.com/prometheus-community/postgres_exporter/pull/1103 +* [BIGFIX] Checkpoint related columns in PG 17 have been moved from pg_stat_bgwriter to pg_stat_checkpointer by @n-rodriguez in https://github.com/prometheus-community/postgres_exporter/pull/1072 +* [BUGFIX] Fix pg_stat_statements for PG17 by @NevermindZ4 in https://github.com/prometheus-community/postgres_exporter/pull/1114 +* [BUGFIX] Handle pg_replication_slots on pg<13 by @michael-todorovic in https://github.com/prometheus-community/postgres_exporter/pull/1098 +* [BUGFIX] Fix missing dsn sanitization for logging by @sysadmind in https://github.com/prometheus-community/postgres_exporter/pull/1104 + +## New Contributors +* @jyothikirant-sayukth made their first contribution in https://github.com/prometheus-community/postgres_exporter/pull/1092 +* @aagarwalla-fx made their first contribution in https://github.com/prometheus-community/postgres_exporter/pull/1103 +* @NevermindZ4 made their first contribution in https://github.com/prometheus-community/postgres_exporter/pull/1114 +* @michael-todorovic made their first contribution in https://github.com/prometheus-community/postgres_exporter/pull/1098 +* @fgalind1 made their first contribution in https://github.com/prometheus-community/postgres_exporter/pull/1106 + +**Full Changelog**: https://github.com/prometheus-community/postgres_exporter/compare/v0.16.0...v0.17.0 + ## 0.16.0 / 2024-11-10 BREAKING CHANGES: diff --git a/VERSION b/VERSION index 04a373efe..c5523bd09 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.16.0 +0.17.0 From 2869087f3cec1b2096f33ed9d182b0452f9b8d11 Mon Sep 17 00:00:00 2001 From: vancwo Date: Wed, 26 Feb 2025 05:21:39 -0800 Subject: [PATCH 211/228] Fix: Handle incoming labels with invalid UTF-8 (#1131) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's possible that incoming labels will contain invalid UTF-8 characters. This results in a panic. This fix sanitizes the label's string to ensure only valid UTF-8 characters are included, by replacing invalid characters with � (REPLACEMENT CHARACTER) Signed-off-by: Cooper Worobetz --- cmd/postgres_exporter/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/postgres_exporter/util.go b/cmd/postgres_exporter/util.go index 3baa6f4be..8907e7c5f 100644 --- a/cmd/postgres_exporter/util.go +++ b/cmd/postgres_exporter/util.go @@ -159,7 +159,7 @@ func dbToString(t interface{}) (string, bool) { // Try and convert to string return string(v), true case string: - return v, true + return strings.ToValidUTF8(v, "�"), true case bool: if v { return "true", true From 1e574cf4fd2a75a8a707d424eafcaa0b88cb7af4 Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Wed, 26 Feb 2025 14:41:27 +0100 Subject: [PATCH 212/228] Release v0.17.1 (#1132) * [BUGFIX] Fix: Handle incoming labels with invalid UTF-8 #1131 Signed-off-by: SuperQ --- CHANGELOG.md | 4 ++++ VERSION | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49b6b4101..d01ceb504 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.17.1 / 2025-02-26 + +* [BUGFIX] Fix: Handle incoming labels with invalid UTF-8 #1131 + ## 0.17.0 / 2025-02-16 ## What's Changed diff --git a/VERSION b/VERSION index c5523bd09..7cca7711a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.17.0 +0.17.1 From 457b6fa8cd89b34417a95911d7985d93a1b5c32d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 18:26:29 +0100 Subject: [PATCH 213/228] Bump github.com/prometheus/client_golang from 1.20.5 to 1.21.0 (#1133) Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.5 to 1.21.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.20.5...v1.21.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index a7b376b4e..422c3241b 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/alecthomas/kingpin/v2 v2.4.0 github.com/blang/semver/v4 v4.0.0 github.com/lib/pq v1.10.9 - github.com/prometheus/client_golang v1.20.5 + github.com/prometheus/client_golang v1.21.0 github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.62.0 github.com/prometheus/exporter-toolkit v0.14.0 @@ -25,7 +25,7 @@ require ( github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/mdlayher/socket v0.4.1 // indirect diff --git a/go.sum b/go.sum index a57fc83c1..7d4217fa1 100644 --- a/go.sum +++ b/go.sum @@ -26,8 +26,8 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -50,8 +50,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA= +github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= From 602302ffe22485c4e15f3101a705e588a849d1d5 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Sat, 8 Mar 2025 15:00:54 +0100 Subject: [PATCH 214/228] Update common Prometheus files (#1137) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 6 +++--- Makefile.common | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index def9007ac..e36a9f1a4 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -28,12 +28,12 @@ jobs: - name: Install Go uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 with: - go-version: 1.23.x + go-version: 1.24.x - name: Install snmp_exporter/generator dependencies run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@ec5d18412c0aeab7936cb16880d708ba2a64e1ae # v6.2.0 + uses: golangci/golangci-lint-action@2226d7cb06a077cd73e56eedd38eecad18e5d837 # v6.5.0 with: args: --verbose - version: v1.63.4 + version: v1.64.6 diff --git a/Makefile.common b/Makefile.common index d1576bb31..8cb383859 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.63.4 +GOLANGCI_LINT_VERSION ?= v1.64.6 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) From b0e61bf263fffeefc5d5b84fea8b8b0714958862 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Mar 2025 22:34:30 +0100 Subject: [PATCH 215/228] Bump golang.org/x/net from 0.33.0 to 0.36.0 (#1138) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.36.0. - [Commits](https://github.com/golang/net/compare/v0.33.0...v0.36.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 422c3241b..1d585cd23 100644 --- a/go.mod +++ b/go.mod @@ -36,11 +36,11 @@ require ( github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.32.0 // indirect - golang.org/x/net v0.33.0 // indirect + golang.org/x/crypto v0.35.0 // indirect + golang.org/x/net v0.36.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect google.golang.org/protobuf v1.36.1 // indirect ) diff --git a/go.sum b/go.sum index 7d4217fa1..09262cf79 100644 --- a/go.sum +++ b/go.sum @@ -73,18 +73,18 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= +golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 2ce65c324c58dceedd832583f196987f2c13b011 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Sun, 23 Mar 2025 16:54:21 +0100 Subject: [PATCH 216/228] Update common Prometheus files (#1140) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index e36a9f1a4..b404ce7c7 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -33,7 +33,7 @@ jobs: run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@2226d7cb06a077cd73e56eedd38eecad18e5d837 # v6.5.0 + uses: golangci/golangci-lint-action@55c2c1448f86e01eaae002a5a3a9624417608d84 # v6.5.2 with: args: --verbose version: v1.64.6 From fca2ad84cd79fea6b414a2ce21fe8ee5b8d5a5a4 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Sun, 30 Mar 2025 20:49:06 +0200 Subject: [PATCH 217/228] Update common Prometheus files (#1142) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index b404ce7c7..5342cbe08 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -26,7 +26,7 @@ jobs: - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install Go - uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version: 1.24.x - name: Install snmp_exporter/generator dependencies From 9e86f1ee380a4c3e4607991cd79e54713c1f3197 Mon Sep 17 00:00:00 2001 From: Ian Bibby <470816+ianbibby@users.noreply.github.com> Date: Thu, 3 Apr 2025 07:45:29 -0700 Subject: [PATCH 218/228] Adds pg_stat_progress_vacuum collector (#1141) Signed-off-by: Ian Bibby Co-authored-by: Ben Kochie --- README.md | 3 + collector/pg_stat_progress_vacuum.go | 222 ++++++++++++++++++++++ collector/pg_stat_progress_vacuum_test.go | 135 +++++++++++++ 3 files changed, 360 insertions(+) create mode 100644 collector/pg_stat_progress_vacuum.go create mode 100644 collector/pg_stat_progress_vacuum_test.go diff --git a/README.md b/README.md index 9494acb24..dedc5aa55 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,9 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra * `[no-]collector.stat_database` Enable the `stat_database` collector (default: enabled). +* `[no-]collector.stat_progress_vacuum` + Enable the `stat_progress_vacuum` collector (default: enabled). + * `[no-]collector.stat_statements` Enable the `stat_statements` collector (default: disabled). diff --git a/collector/pg_stat_progress_vacuum.go b/collector/pg_stat_progress_vacuum.go new file mode 100644 index 000000000..f8083a49f --- /dev/null +++ b/collector/pg_stat_progress_vacuum.go @@ -0,0 +1,222 @@ +// Copyright 2025 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 collector + +import ( + "context" + "database/sql" + "log/slog" + + "github.com/prometheus/client_golang/prometheus" +) + +const progressVacuumSubsystem = "stat_progress_vacuum" + +func init() { + registerCollector(progressVacuumSubsystem, defaultEnabled, NewPGStatProgressVacuumCollector) +} + +type PGStatProgressVacuumCollector struct { + log *slog.Logger +} + +func NewPGStatProgressVacuumCollector(config collectorConfig) (Collector, error) { + return &PGStatProgressVacuumCollector{log: config.logger}, nil +} + +var vacuumPhases = []string{ + "initializing", + "scanning heap", + "vacuuming indexes", + "vacuuming heap", + "cleaning up indexes", + "truncating heap", + "performing final cleanup", +} + +var ( + statProgressVacuumPhase = prometheus.NewDesc( + prometheus.BuildFQName(namespace, progressVacuumSubsystem, "phase"), + "Current vacuum phase (1 = active, 0 = inactive). Label 'phase' is human-readable.", + []string{"datname", "relname", "phase"}, + nil, + ) + + statProgressVacuumHeapBlksTotal = prometheus.NewDesc( + prometheus.BuildFQName(namespace, progressVacuumSubsystem, "heap_blks"), + "Total number of heap blocks in the table being vacuumed.", + []string{"datname", "relname"}, + nil, + ) + + statProgressVacuumHeapBlksScanned = prometheus.NewDesc( + prometheus.BuildFQName(namespace, progressVacuumSubsystem, "heap_blks_scanned"), + "Number of heap blocks scanned so far.", + []string{"datname", "relname"}, + nil, + ) + + statProgressVacuumHeapBlksVacuumed = prometheus.NewDesc( + prometheus.BuildFQName(namespace, progressVacuumSubsystem, "heap_blks_vacuumed"), + "Number of heap blocks vacuumed so far.", + []string{"datname", "relname"}, + nil, + ) + + statProgressVacuumIndexVacuumCount = prometheus.NewDesc( + prometheus.BuildFQName(namespace, progressVacuumSubsystem, "index_vacuums"), + "Number of completed index vacuum cycles.", + []string{"datname", "relname"}, + nil, + ) + + statProgressVacuumMaxDeadTuples = prometheus.NewDesc( + prometheus.BuildFQName(namespace, progressVacuumSubsystem, "max_dead_tuples"), + "Maximum number of dead tuples that can be stored before cleanup is performed.", + []string{"datname", "relname"}, + nil, + ) + + statProgressVacuumNumDeadTuples = prometheus.NewDesc( + prometheus.BuildFQName(namespace, progressVacuumSubsystem, "num_dead_tuples"), + "Current number of dead tuples found so far.", + []string{"datname", "relname"}, + nil, + ) + + // This is the view definition of pg_stat_progress_vacuum, albeit without the conversion + // of "phase" to a human-readable string. We will prefer the numeric representation. + statProgressVacuumQuery = `SELECT + d.datname, + s.relid::regclass::text AS relname, + s.param1 AS phase, + s.param2 AS heap_blks_total, + s.param3 AS heap_blks_scanned, + s.param4 AS heap_blks_vacuumed, + s.param5 AS index_vacuum_count, + s.param6 AS max_dead_tuples, + s.param7 AS num_dead_tuples + FROM + pg_stat_get_progress_info('VACUUM'::text) + s(pid, datid, relid, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16, param17, param18, param19, param20) + LEFT JOIN + pg_database d ON s.datid = d.oid` +) + +func (c *PGStatProgressVacuumCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + db := instance.getDB() + rows, err := db.QueryContext(ctx, + statProgressVacuumQuery) + + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var ( + datname sql.NullString + relname sql.NullString + phase sql.NullInt64 + heapBlksTotal sql.NullInt64 + heapBlksScanned sql.NullInt64 + heapBlksVacuumed sql.NullInt64 + indexVacuumCount sql.NullInt64 + maxDeadTuples sql.NullInt64 + numDeadTuples sql.NullInt64 + ) + + if err := rows.Scan( + &datname, + &relname, + &phase, + &heapBlksTotal, + &heapBlksScanned, + &heapBlksVacuumed, + &indexVacuumCount, + &maxDeadTuples, + &numDeadTuples, + ); err != nil { + return err + } + + datnameLabel := "unknown" + if datname.Valid { + datnameLabel = datname.String + } + relnameLabel := "unknown" + if relname.Valid { + relnameLabel = relname.String + } + + labels := []string{datnameLabel, relnameLabel} + + var phaseMetric *float64 + if phase.Valid { + v := float64(phase.Int64) + phaseMetric = &v + } + + for i, label := range vacuumPhases { + v := 0.0 + // Only the current phase should be 1.0. + if phaseMetric != nil && float64(i) == *phaseMetric { + v = 1.0 + } + labelsCopy := append(labels, label) + ch <- prometheus.MustNewConstMetric(statProgressVacuumPhase, prometheus.GaugeValue, v, labelsCopy...) + } + + heapTotal := 0.0 + if heapBlksTotal.Valid { + heapTotal = float64(heapBlksTotal.Int64) + } + ch <- prometheus.MustNewConstMetric(statProgressVacuumHeapBlksTotal, prometheus.GaugeValue, heapTotal, labels...) + + heapScanned := 0.0 + if heapBlksScanned.Valid { + heapScanned = float64(heapBlksScanned.Int64) + } + ch <- prometheus.MustNewConstMetric(statProgressVacuumHeapBlksScanned, prometheus.GaugeValue, heapScanned, labels...) + + heapVacuumed := 0.0 + if heapBlksVacuumed.Valid { + heapVacuumed = float64(heapBlksVacuumed.Int64) + } + ch <- prometheus.MustNewConstMetric(statProgressVacuumHeapBlksVacuumed, prometheus.GaugeValue, heapVacuumed, labels...) + + indexCount := 0.0 + if indexVacuumCount.Valid { + indexCount = float64(indexVacuumCount.Int64) + } + ch <- prometheus.MustNewConstMetric(statProgressVacuumIndexVacuumCount, prometheus.GaugeValue, indexCount, labels...) + + maxDead := 0.0 + if maxDeadTuples.Valid { + maxDead = float64(maxDeadTuples.Int64) + } + ch <- prometheus.MustNewConstMetric(statProgressVacuumMaxDeadTuples, prometheus.GaugeValue, maxDead, labels...) + + numDead := 0.0 + if numDeadTuples.Valid { + numDead = float64(numDeadTuples.Int64) + } + ch <- prometheus.MustNewConstMetric(statProgressVacuumNumDeadTuples, prometheus.GaugeValue, numDead, labels...) + } + + if err := rows.Err(); err != nil { + return err + } + return nil +} diff --git a/collector/pg_stat_progress_vacuum_test.go b/collector/pg_stat_progress_vacuum_test.go new file mode 100644 index 000000000..80572feb8 --- /dev/null +++ b/collector/pg_stat_progress_vacuum_test.go @@ -0,0 +1,135 @@ +// Copyright 2025 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 collector + +import ( + "context" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/smartystreets/goconvey/convey" +) + +func TestPGStatProgressVacuumCollector(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{ + "datname", "relname", "phase", "heap_blks_total", "heap_blks_scanned", + "heap_blks_vacuumed", "index_vacuum_count", "max_dead_tuples", "num_dead_tuples", + } + + rows := sqlmock.NewRows(columns).AddRow( + "postgres", "a_table", 3, 3000, 400, 200, 2, 500, 123) + + mock.ExpectQuery(sanitizeQuery(statProgressVacuumQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatProgressVacuumCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatProgressVacuumCollector.Update; %+v", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datname": "postgres", "relname": "a_table", "phase": "initializing"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "a_table", "phase": "scanning heap"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "a_table", "phase": "vacuuming indexes"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "a_table", "phase": "vacuuming heap"}, metricType: dto.MetricType_GAUGE, value: 1}, + {labels: labelMap{"datname": "postgres", "relname": "a_table", "phase": "cleaning up indexes"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "a_table", "phase": "truncating heap"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "a_table", "phase": "performing final cleanup"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 3000}, + {labels: labelMap{"datname": "postgres", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 400}, + {labels: labelMap{"datname": "postgres", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 200}, + {labels: labelMap{"datname": "postgres", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 2}, + {labels: labelMap{"datname": "postgres", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 500}, + {labels: labelMap{"datname": "postgres", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 123}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(m, convey.ShouldResemble, expect) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("There were unfulfilled exceptions: %+v", err) + } +} + +func TestPGStatProgressVacuumCollectorNullValues(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db} + + columns := []string{ + "datname", "relname", "phase", "heap_blks_total", "heap_blks_scanned", + "heap_blks_vacuumed", "index_vacuum_count", "max_dead_tuples", "num_dead_tuples", + } + + rows := sqlmock.NewRows(columns).AddRow( + "postgres", nil, nil, nil, nil, nil, nil, nil, nil) + + mock.ExpectQuery(sanitizeQuery(statProgressVacuumQuery)).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatProgressVacuumCollector{} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatProgressVacuumCollector.Update; %+v", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"datname": "postgres", "relname": "unknown", "phase": "initializing"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown", "phase": "scanning heap"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown", "phase": "vacuuming indexes"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown", "phase": "vacuuming heap"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown", "phase": "cleaning up indexes"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown", "phase": "truncating heap"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown", "phase": "performing final cleanup"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("There were unfulfilled exceptions: %+v", err) + } +} From 8d5ec4b3ea77033d5d2b50fad1bb8df3f495265e Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Thu, 3 Apr 2025 16:23:40 +0100 Subject: [PATCH 219/228] Update Go (#1147) * Update Go to 1.24. * Update golangci-lint to v2. * Fixup linting issues. Signed-off-by: SuperQ --- .circleci/config.yml | 4 +- .github/workflows/golangci-lint.yml | 4 +- .golangci.yml | 53 +++++++++++++++--------- .promu.yml | 2 +- Makefile.common | 2 +- cmd/postgres_exporter/pg_setting.go | 4 +- cmd/postgres_exporter/pg_setting_test.go | 4 +- collector/collector_test.go | 20 ++++----- config/config.go | 4 +- config/config_test.go | 6 +-- 10 files changed, 58 insertions(+), 45 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6cfc880d2..ee03ff8d2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,7 +8,7 @@ executors: # This must match .promu.yml. golang: docker: - - image: cimg/go:1.23 + - image: cimg/go:1.24 jobs: test: @@ -23,7 +23,7 @@ jobs: integration: docker: - - image: cimg/go:1.23 + - image: cimg/go:1.24 - image: << parameters.postgres_image >> environment: POSTGRES_DB: circle_test diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 5342cbe08..3893ef86b 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -33,7 +33,7 @@ jobs: run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@55c2c1448f86e01eaae002a5a3a9624417608d84 # v6.5.2 + uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0 with: args: --verbose - version: v1.64.6 + version: v2.0.2 diff --git a/.golangci.yml b/.golangci.yml index 96487c898..4b58b08b6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,23 +1,36 @@ ---- +version: "2" linters: enable: - - misspell - - revive - -issues: - exclude-rules: - - path: _test.go - linters: - - errcheck - -linters-settings: - errcheck: - exclude-functions: - # Never check for logger errors. - - (github.com/go-kit/log.Logger).Log - revive: + - misspell + - revive + settings: + errcheck: + exclude-functions: + - (github.com/go-kit/log.Logger).Log + revive: + rules: + - name: unused-parameter + severity: warning + disabled: true + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling rules: - # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter - - name: unused-parameter - severity: warning - disabled: true + - linters: + - errcheck + path: _test.go + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/.promu.yml b/.promu.yml index c2b361240..5f915289f 100644 --- a/.promu.yml +++ b/.promu.yml @@ -1,6 +1,6 @@ go: # This must match .circle/config.yml. - version: 1.23 + version: 1.24 repository: path: github.com/prometheus-community/postgres_exporter build: diff --git a/Makefile.common b/Makefile.common index 8cb383859..81bad5f42 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.64.6 +GOLANGCI_LINT_VERSION ?= v2.0.2 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) diff --git a/cmd/postgres_exporter/pg_setting.go b/cmd/postgres_exporter/pg_setting.go index 02e65dd2a..5b13e160f 100644 --- a/cmd/postgres_exporter/pg_setting.go +++ b/cmd/postgres_exporter/pg_setting.go @@ -67,7 +67,7 @@ type pgSetting struct { func (s *pgSetting) metric(labels prometheus.Labels) prometheus.Metric { var ( err error - name = strings.Replace(strings.Replace(s.name, ".", "_", -1), "-", "_", -1) + name = strings.ReplaceAll(strings.ReplaceAll(s.name, ".", "_"), "-", "_") unit = s.unit // nolint: ineffassign shortDesc = fmt.Sprintf("Server Parameter: %s", s.name) subsystem = "settings" @@ -131,7 +131,7 @@ func (s *pgSetting) normaliseUnit() (val float64, unit string, err error) { case "B", "kB", "MB", "GB", "TB", "1kB", "2kB", "4kB", "8kB", "16kB", "32kB", "64kB", "16MB", "32MB", "64MB": unit = "bytes" default: - err = fmt.Errorf("Unknown unit for runtime variable: %q", s.unit) + err = fmt.Errorf("unknown unit for runtime variable: %q", s.unit) return } diff --git a/cmd/postgres_exporter/pg_setting_test.go b/cmd/postgres_exporter/pg_setting_test.go index 0e010444d..6923da630 100644 --- a/cmd/postgres_exporter/pg_setting_test.go +++ b/cmd/postgres_exporter/pg_setting_test.go @@ -214,7 +214,7 @@ var fixtures = []fixture{ n: normalised{ val: 10, unit: "", - err: `Unknown unit for runtime variable: "nonexistent"`, + err: `unknown unit for runtime variable: "nonexistent"`, }, }, } @@ -240,7 +240,7 @@ func (s *PgSettingSuite) TestNormaliseUnit(c *C) { func (s *PgSettingSuite) TestMetric(c *C) { defer func() { if r := recover(); r != nil { - if r.(error).Error() != `Unknown unit for runtime variable: "nonexistent"` { + if r.(error).Error() != `unknown unit for runtime variable: "nonexistent"` { panic(r) } } diff --git a/collector/collector_test.go b/collector/collector_test.go index 18101f00e..d3b473b43 100644 --- a/collector/collector_test.go +++ b/collector/collector_test.go @@ -48,15 +48,15 @@ func readMetric(m prometheus.Metric) MetricResult { func sanitizeQuery(q string) string { q = strings.Join(strings.Fields(q), " ") - q = strings.Replace(q, "(", "\\(", -1) - q = strings.Replace(q, "?", "\\?", -1) - q = strings.Replace(q, ")", "\\)", -1) - q = strings.Replace(q, "[", "\\[", -1) - q = strings.Replace(q, "]", "\\]", -1) - q = strings.Replace(q, "{", "\\{", -1) - q = strings.Replace(q, "}", "\\}", -1) - q = strings.Replace(q, "*", "\\*", -1) - q = strings.Replace(q, "^", "\\^", -1) - q = strings.Replace(q, "$", "\\$", -1) + q = strings.ReplaceAll(q, "(", "\\(") + q = strings.ReplaceAll(q, "?", "\\?") + q = strings.ReplaceAll(q, ")", "\\)") + q = strings.ReplaceAll(q, "[", "\\[") + q = strings.ReplaceAll(q, "]", "\\]") + q = strings.ReplaceAll(q, "{", "\\{") + q = strings.ReplaceAll(q, "}", "\\}") + q = strings.ReplaceAll(q, "*", "\\*") + q = strings.ReplaceAll(q, "^", "\\^") + q = strings.ReplaceAll(q, "$", "\\$") return q } diff --git a/config/config.go b/config/config.go index 7cdc08f7b..52c66513a 100644 --- a/config/config.go +++ b/config/config.go @@ -79,14 +79,14 @@ func (ch *Handler) ReloadConfig(f string, logger *slog.Logger) error { yamlReader, err := os.Open(f) if err != nil { - return fmt.Errorf("Error opening config file %q: %s", f, err) + return fmt.Errorf("error opening config file %q: %s", f, err) } defer yamlReader.Close() decoder := yaml.NewDecoder(yamlReader) decoder.KnownFields(true) if err = decoder.Decode(config); err != nil { - return fmt.Errorf("Error parsing config file %q: %s", f, err) + return fmt.Errorf("error parsing config file %q: %s", f, err) } ch.Lock() diff --git a/config/config_test.go b/config/config_test.go index d5d23d3ba..fa59c9b40 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -24,7 +24,7 @@ func TestLoadConfig(t *testing.T) { err := ch.ReloadConfig("testdata/config-good.yaml", nil) if err != nil { - t.Errorf("Error loading config: %s", err) + t.Errorf("error loading config: %s", err) } } @@ -39,11 +39,11 @@ func TestLoadBadConfigs(t *testing.T) { }{ { input: "testdata/config-bad-auth-module.yaml", - want: "Error parsing config file \"testdata/config-bad-auth-module.yaml\": yaml: unmarshal errors:\n line 3: field pretendauth not found in type config.AuthModule", + want: "error parsing config file \"testdata/config-bad-auth-module.yaml\": yaml: unmarshal errors:\n line 3: field pretendauth not found in type config.AuthModule", }, { input: "testdata/config-bad-extra-field.yaml", - want: "Error parsing config file \"testdata/config-bad-extra-field.yaml\": yaml: unmarshal errors:\n line 8: field doesNotExist not found in type config.AuthModule", + want: "error parsing config file \"testdata/config-bad-extra-field.yaml\": yaml: unmarshal errors:\n line 8: field doesNotExist not found in type config.AuthModule", }, } From 43576acc7642f5cb97d3d1f6bbe0f9e514ed9301 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 18:17:55 +0200 Subject: [PATCH 220/228] Bump github.com/prometheus/client_golang from 1.21.0 to 1.21.1 (#1144) Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.21.0 to 1.21.1. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.21.0...v1.21.1) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-version: 1.21.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 +++- go.sum | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1d585cd23..889893b5e 100644 --- a/go.mod +++ b/go.mod @@ -2,12 +2,14 @@ module github.com/prometheus-community/postgres_exporter go 1.23.0 +toolchain go1.24.1 + require ( github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/alecthomas/kingpin/v2 v2.4.0 github.com/blang/semver/v4 v4.0.0 github.com/lib/pq v1.10.9 - github.com/prometheus/client_golang v1.21.0 + github.com/prometheus/client_golang v1.21.1 github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.62.0 github.com/prometheus/exporter-toolkit v0.14.0 diff --git a/go.sum b/go.sum index 09262cf79..5f7a25e95 100644 --- a/go.sum +++ b/go.sum @@ -50,8 +50,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA= -github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= +github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= From f8b7139174317e3df6d756a02c99b4d8de649d0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 18:18:17 +0200 Subject: [PATCH 221/228] Bump github.com/prometheus/common from 0.62.0 to 0.63.0 (#1143) Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.62.0 to 0.63.0. - [Release notes](https://github.com/prometheus/common/releases) - [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md) - [Commits](https://github.com/prometheus/common/compare/v0.62.0...v0.63.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-version: 0.63.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 889893b5e..ac1ceeff4 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/lib/pq v1.10.9 github.com/prometheus/client_golang v1.21.1 github.com/prometheus/client_model v0.6.1 - github.com/prometheus/common v0.62.0 + github.com/prometheus/common v0.63.0 github.com/prometheus/exporter-toolkit v0.14.0 github.com/smartystreets/goconvey v1.8.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c @@ -40,9 +40,9 @@ require ( github.com/xhit/go-str2duration/v2 v2.1.0 // indirect golang.org/x/crypto v0.35.0 // indirect golang.org/x/net v0.36.0 // indirect - golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/oauth2 v0.25.0 // indirect golang.org/x/sync v0.11.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.22.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect + google.golang.org/protobuf v1.36.5 // indirect ) diff --git a/go.sum b/go.sum index 5f7a25e95..939e1d083 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -54,8 +54,8 @@ github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGC github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg= github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= @@ -77,16 +77,16 @@ golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= +golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From 5edc331876c3f94bd5ca26e502fee4e4df77e2d1 Mon Sep 17 00:00:00 2001 From: Felix Yuan Date: Fri, 18 Apr 2025 07:14:25 -0700 Subject: [PATCH 222/228] Record table only size bytes as well in addition to the total size bytes (#1149) * Record table only size bytes as well in addition to the total size bytes Signed-off-by: Felix Yuan * Update collector/pg_stat_user_tables.go Co-authored-by: Ben Kochie Signed-off-by: Felix Yuan * Update collector/pg_stat_user_tables.go Co-authored-by: Ben Kochie Signed-off-by: Felix Yuan * Finish renaming elements to index and table size Signed-off-by: Felix Yuan --------- Signed-off-by: Felix Yuan Co-authored-by: Ben Kochie --- collector/pg_stat_user_tables.go | 40 +++++++++++++++++++-------- collector/pg_stat_user_tables_test.go | 14 ++++++++-- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/collector/pg_stat_user_tables.go b/collector/pg_stat_user_tables.go index 254d76a66..ad8bcace7 100644 --- a/collector/pg_stat_user_tables.go +++ b/collector/pg_stat_user_tables.go @@ -150,9 +150,15 @@ var ( []string{"datname", "schemaname", "relname"}, prometheus.Labels{}, ) - statUserTablesTotalSize = prometheus.NewDesc( - prometheus.BuildFQName(namespace, userTableSubsystem, "size_bytes"), - "Total disk space used by this table, in bytes, including all indexes and TOAST data", + statUserIndexSize = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "index_size_bytes"), + "Total disk space used by this index, in bytes", + []string{"datname", "schemaname", "relname"}, + prometheus.Labels{}, + ) + statUserTableSize = prometheus.NewDesc( + prometheus.BuildFQName(namespace, userTableSubsystem, "table_size_bytes"), + "Total disk space used by this table, in bytes", []string{"datname", "schemaname", "relname"}, prometheus.Labels{}, ) @@ -180,7 +186,8 @@ var ( autovacuum_count, analyze_count, autoanalyze_count, - pg_total_relation_size(relid) as total_size + pg_indexes_size(relid) as indexes_size, + pg_table_size(relid) as table_size FROM pg_stat_user_tables` ) @@ -198,10 +205,10 @@ func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instan for rows.Next() { var datname, schemaname, relname sql.NullString var seqScan, seqTupRead, idxScan, idxTupFetch, nTupIns, nTupUpd, nTupDel, nTupHotUpd, nLiveTup, nDeadTup, - nModSinceAnalyze, vacuumCount, autovacuumCount, analyzeCount, autoanalyzeCount, totalSize sql.NullInt64 + nModSinceAnalyze, vacuumCount, autovacuumCount, analyzeCount, autoanalyzeCount, indexSize, tableSize sql.NullInt64 var lastVacuum, lastAutovacuum, lastAnalyze, lastAutoanalyze sql.NullTime - if err := rows.Scan(&datname, &schemaname, &relname, &seqScan, &seqTupRead, &idxScan, &idxTupFetch, &nTupIns, &nTupUpd, &nTupDel, &nTupHotUpd, &nLiveTup, &nDeadTup, &nModSinceAnalyze, &lastVacuum, &lastAutovacuum, &lastAnalyze, &lastAutoanalyze, &vacuumCount, &autovacuumCount, &analyzeCount, &autoanalyzeCount, &totalSize); err != nil { + if err := rows.Scan(&datname, &schemaname, &relname, &seqScan, &seqTupRead, &idxScan, &idxTupFetch, &nTupIns, &nTupUpd, &nTupDel, &nTupHotUpd, &nLiveTup, &nDeadTup, &nModSinceAnalyze, &lastVacuum, &lastAutovacuum, &lastAnalyze, &lastAutoanalyze, &vacuumCount, &autovacuumCount, &analyzeCount, &autoanalyzeCount, &indexSize, &tableSize); err != nil { return err } @@ -427,14 +434,25 @@ func (c *PGStatUserTablesCollector) Update(ctx context.Context, instance *instan datnameLabel, schemanameLabel, relnameLabel, ) - totalSizeMetric := 0.0 - if totalSize.Valid { - totalSizeMetric = float64(totalSize.Int64) + indexSizeMetric := 0.0 + if indexSize.Valid { + indexSizeMetric = float64(indexSize.Int64) + } + ch <- prometheus.MustNewConstMetric( + statUserIndexSize, + prometheus.GaugeValue, + indexSizeMetric, + datnameLabel, schemanameLabel, relnameLabel, + ) + + tableSizeMetric := 0.0 + if tableSize.Valid { + tableSizeMetric = float64(tableSize.Int64) } ch <- prometheus.MustNewConstMetric( - statUserTablesTotalSize, + statUserTableSize, prometheus.GaugeValue, - totalSizeMetric, + tableSizeMetric, datnameLabel, schemanameLabel, relnameLabel, ) } diff --git a/collector/pg_stat_user_tables_test.go b/collector/pg_stat_user_tables_test.go index 5e82335c3..4649bdbc5 100644 --- a/collector/pg_stat_user_tables_test.go +++ b/collector/pg_stat_user_tables_test.go @@ -72,7 +72,8 @@ func TestPGStatUserTablesCollector(t *testing.T) { "autovacuum_count", "analyze_count", "autoanalyze_count", - "total_size"} + "index_size", + "table_size"} rows := sqlmock.NewRows(columns). AddRow("postgres", "public", @@ -96,7 +97,8 @@ func TestPGStatUserTablesCollector(t *testing.T) { 12, 13, 14, - 15) + 15, + 16) mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -128,6 +130,8 @@ func TestPGStatUserTablesCollector(t *testing.T) { {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 12}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 13}, {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_COUNTER, value: 14}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 15}, + {labels: labelMap{"datname": "postgres", "schemaname": "public", "relname": "a_table"}, metricType: dto.MetricType_GAUGE, value: 16}, } convey.Convey("Metrics comparison", t, func() { @@ -173,7 +177,8 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) { "autovacuum_count", "analyze_count", "autoanalyze_count", - "total_size"} + "index_size", + "table_size"} rows := sqlmock.NewRows(columns). AddRow("postgres", nil, @@ -197,6 +202,7 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) { nil, nil, nil, + nil, nil) mock.ExpectQuery(sanitizeQuery(statUserTablesQuery)).WillReturnRows(rows) ch := make(chan prometheus.Metric) @@ -229,6 +235,8 @@ func TestPGStatUserTablesCollectorNullValues(t *testing.T) { {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, + {labels: labelMap{"datname": "postgres", "schemaname": "unknown", "relname": "unknown"}, metricType: dto.MetricType_GAUGE, value: 0}, } convey.Convey("Metrics comparison", t, func() { From 6526065fbcdc2fa780b1db6784b9978602f37d94 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 21:26:10 -0400 Subject: [PATCH 223/228] Bump golang.org/x/net from 0.36.0 to 0.38.0 (#1152) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.36.0 to 0.38.0. - [Commits](https://github.com/golang/net/compare/v0.36.0...v0.38.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-version: 0.38.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index ac1ceeff4..e3eba7880 100644 --- a/go.mod +++ b/go.mod @@ -38,11 +38,11 @@ require ( github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - golang.org/x/crypto v0.35.0 // indirect - golang.org/x/net v0.36.0 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/net v0.38.0 // indirect golang.org/x/oauth2 v0.25.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect google.golang.org/protobuf v1.36.5 // indirect ) diff --git a/go.sum b/go.sum index 939e1d083..25dd5c07d 100644 --- a/go.sum +++ b/go.sum @@ -73,18 +73,18 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= -golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= -golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 5ade81cb9d391aef0606c44ee13830efa55bb3f2 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Wed, 7 May 2025 03:54:01 +0200 Subject: [PATCH 224/228] Update common Prometheus files (#1155) Signed-off-by: prombot --- .github/workflows/golangci-lint.yml | 2 +- Makefile.common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 3893ef86b..672dd424d 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -36,4 +36,4 @@ jobs: uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0 with: args: --verbose - version: v2.0.2 + version: v2.1.5 diff --git a/Makefile.common b/Makefile.common index 81bad5f42..d8b798909 100644 --- a/Makefile.common +++ b/Makefile.common @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v2.0.2 +GOLANGCI_LINT_VERSION ?= v2.1.5 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) From bd8a6135ecc149c02c429a5fa285cac228b244cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 22:14:44 -0400 Subject: [PATCH 225/228] Bump github.com/prometheus/client_golang from 1.21.1 to 1.22.0 (#1154) Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.21.1 to 1.22.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.21.1...v1.22.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-version: 1.22.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 3 +-- go.sum | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index e3eba7880..9acdafc81 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/alecthomas/kingpin/v2 v2.4.0 github.com/blang/semver/v4 v4.0.0 github.com/lib/pq v1.10.9 - github.com/prometheus/client_golang v1.21.1 + github.com/prometheus/client_golang v1.22.0 github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.63.0 github.com/prometheus/exporter-toolkit v0.14.0 @@ -27,7 +27,6 @@ require ( github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect - github.com/klauspost/compress v1.17.11 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/mdlayher/socket v0.4.1 // indirect diff --git a/go.sum b/go.sum index 25dd5c07d..cd073f325 100644 --- a/go.sum +++ b/go.sum @@ -26,8 +26,8 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -50,8 +50,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= -github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= From de42ef7de8bd14f314a609ef50e4c323617258dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=A0tiller?= Date: Fri, 16 May 2025 10:50:19 +0200 Subject: [PATCH 226/228] Export query itself together with queryId in stat_statement metrics (#940) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Export query itself together with queryId in stat_statement metrics * The feature must be enabled via flag. * Limit length of selected query. The query is not added to every metrics, but instead of new metric stat_statement_query_id is introduced that contains mapping between queryId and query. Fixes: #813 --------- Signed-off-by: Jakub Štiller Signed-off-by: Jakub Štiller --- README.md | 6 + collector/collector.go | 7 +- collector/pg_stat_statements.go | 89 +++++++++++-- collector/pg_stat_statements_test.go | 185 ++++++++++++++++++++++++++- 4 files changed, 270 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index dedc5aa55..01bd8b30d 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,12 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra * `[no-]collector.stat_statements` Enable the `stat_statements` collector (default: disabled). +* `[no-]collector.stat_statements.include_query` + Enable selecting statement query together with queryId. (default: disabled) + +* `--collector.stat_statements.query_length` + Maximum length of the statement text. Default is 120. + * `[no-]collector.stat_user_tables` Enable the `stat_user_tables` collector (default: enabled). diff --git a/collector/collector.go b/collector/collector.go index f2102d5ef..298bc36ee 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -37,8 +37,9 @@ const ( // Namespace for all metrics. namespace = "pg" - defaultEnabled = true - defaultDisabled = false + collectorFlagPrefix = "collector." + defaultEnabled = true + defaultDisabled = false ) var ( @@ -74,7 +75,7 @@ func registerCollector(name string, isDefaultEnabled bool, createFunc func(colle } // Create flag for this collector - flagName := fmt.Sprintf("collector.%s", name) + flagName := collectorFlagPrefix + name flagHelp := fmt.Sprintf("Enable the %s collector (default: %s).", name, helpDefaultState) defaultValue := fmt.Sprintf("%v", isDefaultEnabled) diff --git a/collector/pg_stat_statements.go b/collector/pg_stat_statements.go index cabdc3619..9160d3c16 100644 --- a/collector/pg_stat_statements.go +++ b/collector/pg_stat_statements.go @@ -16,27 +16,51 @@ package collector import ( "context" "database/sql" + "fmt" "log/slog" + "github.com/alecthomas/kingpin/v2" "github.com/blang/semver/v4" "github.com/prometheus/client_golang/prometheus" ) const statStatementsSubsystem = "stat_statements" +var ( + includeQueryFlag *bool = nil + statementLengthFlag *uint = nil +) + func init() { // WARNING: // Disabled by default because this set of metrics can be quite expensive on a busy server // Every unique query will cause a new timeseries to be created registerCollector(statStatementsSubsystem, defaultDisabled, NewPGStatStatementsCollector) + + includeQueryFlag = kingpin.Flag( + fmt.Sprint(collectorFlagPrefix, statStatementsSubsystem, ".include_query"), + "Enable selecting statement query together with queryId. (default: disabled)"). + Default(fmt.Sprintf("%v", defaultDisabled)). + Bool() + statementLengthFlag = kingpin.Flag( + fmt.Sprint(collectorFlagPrefix, statStatementsSubsystem, ".query_length"), + "Maximum length of the statement text."). + Default("120"). + Uint() } type PGStatStatementsCollector struct { - log *slog.Logger + log *slog.Logger + includeQueryStatement bool + statementLength uint } func NewPGStatStatementsCollector(config collectorConfig) (Collector, error) { - return &PGStatStatementsCollector{log: config.logger}, nil + return &PGStatStatementsCollector{ + log: config.logger, + includeQueryStatement: *includeQueryFlag, + statementLength: *statementLengthFlag, + }, nil } var ( @@ -71,10 +95,22 @@ var ( prometheus.Labels{}, ) + statStatementsQuery = prometheus.NewDesc( + prometheus.BuildFQName(namespace, statStatementsSubsystem, "query_id"), + "SQL Query to queryid mapping", + []string{"queryid", "query"}, + prometheus.Labels{}, + ) +) + +const ( + pgStatStatementQuerySelect = `LEFT(pg_stat_statements.query, %d) as query,` + pgStatStatementsQuery = `SELECT pg_get_userbyid(userid) as user, pg_database.datname, pg_stat_statements.queryid, + %s pg_stat_statements.calls as calls_total, pg_stat_statements.total_time / 1000.0 as seconds_total, pg_stat_statements.rows as rows_total, @@ -96,6 +132,7 @@ var ( pg_get_userbyid(userid) as user, pg_database.datname, pg_stat_statements.queryid, + %s pg_stat_statements.calls as calls_total, pg_stat_statements.total_exec_time / 1000.0 as seconds_total, pg_stat_statements.rows as rows_total, @@ -117,6 +154,7 @@ var ( pg_get_userbyid(userid) as user, pg_database.datname, pg_stat_statements.queryid, + %s pg_stat_statements.calls as calls_total, pg_stat_statements.total_exec_time / 1000.0 as seconds_total, pg_stat_statements.rows as rows_total, @@ -135,30 +173,42 @@ var ( LIMIT 100;` ) -func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { - var query string +func (c PGStatStatementsCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { + var queryTemplate string switch { case instance.version.GE(semver.MustParse("17.0.0")): - query = pgStatStatementsQuery_PG17 + queryTemplate = pgStatStatementsQuery_PG17 case instance.version.GE(semver.MustParse("13.0.0")): - query = pgStatStatementsNewQuery + queryTemplate = pgStatStatementsNewQuery default: - query = pgStatStatementsQuery + queryTemplate = pgStatStatementsQuery } + var querySelect = "" + if c.includeQueryStatement { + querySelect = fmt.Sprintf(pgStatStatementQuerySelect, c.statementLength) + } + query := fmt.Sprintf(queryTemplate, querySelect) db := instance.getDB() rows, err := db.QueryContext(ctx, query) + var presentQueryIds = make(map[string]struct{}) + if err != nil { return err } defer rows.Close() for rows.Next() { - var user, datname, queryid sql.NullString + var user, datname, queryid, statement sql.NullString var callsTotal, rowsTotal sql.NullInt64 var secondsTotal, blockReadSecondsTotal, blockWriteSecondsTotal sql.NullFloat64 - - if err := rows.Scan(&user, &datname, &queryid, &callsTotal, &secondsTotal, &rowsTotal, &blockReadSecondsTotal, &blockWriteSecondsTotal); err != nil { + var columns []any + if c.includeQueryStatement { + columns = []any{&user, &datname, &queryid, &statement, &callsTotal, &secondsTotal, &rowsTotal, &blockReadSecondsTotal, &blockWriteSecondsTotal} + } else { + columns = []any{&user, &datname, &queryid, &callsTotal, &secondsTotal, &rowsTotal, &blockReadSecondsTotal, &blockWriteSecondsTotal} + } + if err := rows.Scan(columns...); err != nil { return err } @@ -229,6 +279,25 @@ func (PGStatStatementsCollector) Update(ctx context.Context, instance *instance, blockWriteSecondsTotalMetric, userLabel, datnameLabel, queryidLabel, ) + + if c.includeQueryStatement { + _, ok := presentQueryIds[queryidLabel] + if !ok { + presentQueryIds[queryidLabel] = struct{}{} + + queryLabel := "unknown" + if statement.Valid { + queryLabel = statement.String + } + + ch <- prometheus.MustNewConstMetric( + statStatementsQuery, + prometheus.CounterValue, + 1, + queryidLabel, queryLabel, + ) + } + } } if err := rows.Err(); err != nil { return err diff --git a/collector/pg_stat_statements_test.go b/collector/pg_stat_statements_test.go index ea035f557..0497ba380 100644 --- a/collector/pg_stat_statements_test.go +++ b/collector/pg_stat_statements_test.go @@ -14,6 +14,7 @@ package collector import ( "context" + "fmt" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -35,7 +36,7 @@ func TestPGStateStatementsCollector(t *testing.T) { columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} rows := sqlmock.NewRows(columns). AddRow("postgres", "postgres", 1500, 5, 0.4, 100, 0.1, 0.2) - mock.ExpectQuery(sanitizeQuery(pgStatStatementsQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(fmt.Sprintf(pgStatStatementsQuery, ""))).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -66,6 +67,50 @@ func TestPGStateStatementsCollector(t *testing.T) { } } +func TestPGStateStatementsCollectorWithStatement(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db, version: semver.MustParse("12.0.0")} + + columns := []string{"user", "datname", "queryid", "LEFT(pg_stat_statements.query, 100) as query", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} + rows := sqlmock.NewRows(columns). + AddRow("postgres", "postgres", 1500, "select 1 from foo", 5, 0.4, 100, 0.1, 0.2) + mock.ExpectQuery(sanitizeQuery(fmt.Sprintf(pgStatStatementsQuery, fmt.Sprintf(pgStatStatementQuerySelect, 100)))).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatStatementsCollector{includeQueryStatement: true, statementLength: 100} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatStatementsCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 5}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.4}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 100}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.1}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.2}, + {labels: labelMap{"queryid": "1500", "query": "select 1 from foo"}, metricType: dto.MetricType_COUNTER, value: 1}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} + func TestPGStateStatementsCollectorNull(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { @@ -78,7 +123,7 @@ func TestPGStateStatementsCollectorNull(t *testing.T) { columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} rows := sqlmock.NewRows(columns). AddRow(nil, nil, nil, nil, nil, nil, nil, nil) - mock.ExpectQuery(sanitizeQuery(pgStatStatementsNewQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(fmt.Sprintf(pgStatStatementsNewQuery, ""))).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -109,6 +154,50 @@ func TestPGStateStatementsCollectorNull(t *testing.T) { } } +func TestPGStateStatementsCollectorNullWithStatement(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db, version: semver.MustParse("13.3.7")} + + columns := []string{"user", "datname", "queryid", "LEFT(pg_stat_statements.query, 200) as query", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} + rows := sqlmock.NewRows(columns). + AddRow(nil, nil, nil, nil, nil, nil, nil, nil, nil) + mock.ExpectQuery(sanitizeQuery(fmt.Sprintf(pgStatStatementsNewQuery, fmt.Sprintf(pgStatStatementQuerySelect, 200)))).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatStatementsCollector{includeQueryStatement: true, statementLength: 200} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatStatementsCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"user": "unknown", "datname": "unknown", "queryid": "unknown"}, metricType: dto.MetricType_COUNTER, value: 0}, + {labels: labelMap{"queryid": "unknown", "query": "unknown"}, metricType: dto.MetricType_COUNTER, value: 1}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} + func TestPGStateStatementsCollectorNewPG(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { @@ -121,7 +210,7 @@ func TestPGStateStatementsCollectorNewPG(t *testing.T) { columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} rows := sqlmock.NewRows(columns). AddRow("postgres", "postgres", 1500, 5, 0.4, 100, 0.1, 0.2) - mock.ExpectQuery(sanitizeQuery(pgStatStatementsNewQuery)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(fmt.Sprintf(pgStatStatementsNewQuery, ""))).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -152,6 +241,50 @@ func TestPGStateStatementsCollectorNewPG(t *testing.T) { } } +func TestPGStateStatementsCollectorNewPGWithStatement(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db, version: semver.MustParse("13.3.7")} + + columns := []string{"user", "datname", "queryid", "LEFT(pg_stat_statements.query, 300) as query", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} + rows := sqlmock.NewRows(columns). + AddRow("postgres", "postgres", 1500, "select 1 from foo", 5, 0.4, 100, 0.1, 0.2) + mock.ExpectQuery(sanitizeQuery(fmt.Sprintf(pgStatStatementsNewQuery, fmt.Sprintf(pgStatStatementQuerySelect, 300)))).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatStatementsCollector{includeQueryStatement: true, statementLength: 300} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatStatementsCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 5}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.4}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 100}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.1}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.2}, + {labels: labelMap{"queryid": "1500", "query": "select 1 from foo"}, metricType: dto.MetricType_COUNTER, value: 1}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} + func TestPGStateStatementsCollector_PG17(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { @@ -164,7 +297,7 @@ func TestPGStateStatementsCollector_PG17(t *testing.T) { columns := []string{"user", "datname", "queryid", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} rows := sqlmock.NewRows(columns). AddRow("postgres", "postgres", 1500, 5, 0.4, 100, 0.1, 0.2) - mock.ExpectQuery(sanitizeQuery(pgStatStatementsQuery_PG17)).WillReturnRows(rows) + mock.ExpectQuery(sanitizeQuery(fmt.Sprintf(pgStatStatementsQuery_PG17, ""))).WillReturnRows(rows) ch := make(chan prometheus.Metric) go func() { @@ -194,3 +327,47 @@ func TestPGStateStatementsCollector_PG17(t *testing.T) { t.Errorf("there were unfulfilled exceptions: %s", err) } } + +func TestPGStateStatementsCollector_PG17_WithStatement(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error opening a stub db connection: %s", err) + } + defer db.Close() + + inst := &instance{db: db, version: semver.MustParse("17.0.0")} + + columns := []string{"user", "datname", "queryid", "LEFT(pg_stat_statements.query, 300) as query", "calls_total", "seconds_total", "rows_total", "block_read_seconds_total", "block_write_seconds_total"} + rows := sqlmock.NewRows(columns). + AddRow("postgres", "postgres", 1500, "select 1 from foo", 5, 0.4, 100, 0.1, 0.2) + mock.ExpectQuery(sanitizeQuery(fmt.Sprintf(pgStatStatementsQuery_PG17, fmt.Sprintf(pgStatStatementQuerySelect, 300)))).WillReturnRows(rows) + + ch := make(chan prometheus.Metric) + go func() { + defer close(ch) + c := PGStatStatementsCollector{includeQueryStatement: true, statementLength: 300} + + if err := c.Update(context.Background(), inst, ch); err != nil { + t.Errorf("Error calling PGStatStatementsCollector.Update: %s", err) + } + }() + + expected := []MetricResult{ + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 5}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.4}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 100}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.1}, + {labels: labelMap{"user": "postgres", "datname": "postgres", "queryid": "1500"}, metricType: dto.MetricType_COUNTER, value: 0.2}, + {labels: labelMap{"queryid": "1500", "query": "select 1 from foo"}, metricType: dto.MetricType_COUNTER, value: 1}, + } + + convey.Convey("Metrics comparison", t, func() { + for _, expect := range expected { + m := readMetric(<-ch) + convey.So(expect, convey.ShouldResemble, m) + } + }) + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled exceptions: %s", err) + } +} From d1a957f679fd808c02cd88e6da7c11aeb7eae4d8 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Sat, 17 May 2025 12:06:43 +0200 Subject: [PATCH 227/228] Update common Prometheus files (#1159) Signed-off-by: prombot --- Makefile.common | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile.common b/Makefile.common index d8b798909..4de21512f 100644 --- a/Makefile.common +++ b/Makefile.common @@ -62,6 +62,7 @@ SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= GOLANGCI_LINT_VERSION ?= v2.1.5 +GOLANGCI_FMT_OPTS ?= # golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) @@ -156,9 +157,13 @@ $(GOTEST_DIR): @mkdir -p $@ .PHONY: common-format -common-format: +common-format: $(GOLANGCI_LINT) @echo ">> formatting code" $(GO) fmt $(pkgs) +ifdef GOLANGCI_LINT + @echo ">> formatting code with golangci-lint" + $(GOLANGCI_LINT) fmt $(GOLANGCI_FMT_OPTS) +endif .PHONY: common-vet common-vet: @@ -248,8 +253,8 @@ $(PROMU): cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu rm -r $(PROMU_TMP) -.PHONY: proto -proto: +.PHONY: common-proto +common-proto: @echo ">> generating code from proto files" @./scripts/genproto.sh From 94e8399935e541262aaa2bf4e1723c232bea6c04 Mon Sep 17 00:00:00 2001 From: Jonathan Bowe Date: Thu, 29 May 2025 07:53:56 -0400 Subject: [PATCH 228/228] Feat: Improve Error Handling for Server.Scrape (#1158) * Update querySettings Error Return in Scrape If there are errors querying namespace mappings, the potential error from querySettings is obscured. Adding an immediate return if there are errors retreiving settings. Signed-off-by: Jonathan Bowe * Improve Verbosity of queryNamespaceMappings Errors Previously if any errors were encountered by queryNamespaceMappings, only a count of those errors was returned - making debugging those errors harder than it needs to be. I'm changing this to immediately return nil if no errors are encountered, and otherwise an error will be formatted with each of the namespaces and what the error was for that namespace. Signed-off-by: Jonathan Bowe * Simplify Error Message Co-authored-by: Ben Kochie Signed-off-by: Jonathan Bowe --------- Signed-off-by: Jonathan Bowe Signed-off-by: Jonathan Bowe Co-authored-by: Ben Kochie --- cmd/postgres_exporter/server.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmd/postgres_exporter/server.go b/cmd/postgres_exporter/server.go index bd4e76e10..3d2ecde91 100644 --- a/cmd/postgres_exporter/server.go +++ b/cmd/postgres_exporter/server.go @@ -119,12 +119,17 @@ func (s *Server) Scrape(ch chan<- prometheus.Metric, disableSettingsMetrics bool if !disableSettingsMetrics && s.master { if err = querySettings(ch, s); err != nil { err = fmt.Errorf("error retrieving settings: %s", err) + return err } } errMap := queryNamespaceMappings(ch, s) - if len(errMap) > 0 { - err = fmt.Errorf("queryNamespaceMappings returned %d errors", len(errMap)) + if len(errMap) == 0 { + return nil + } + err = fmt.Errorf("queryNamespaceMappings errors encountered") + for namespace, errStr := range errMap { + err = fmt.Errorf("%s, namespace: %s error: %s", err, namespace, errStr) } return err