You've already forked postgres_exporter
mirror of
https://github.com/prometheus-community/postgres_exporter.git
synced 2025-08-12 14:02:47 +03:00
Accept constantLabels as parameters
When you area monitoring server from cloud providers the exporter IP/hostname is not the server IP, so add some constant labels is useful on dashboards and alerts. And is very important to use with `--disable-default-metrics` to add info like `datname` and figure out the database name that you are monitoring
This commit is contained in:
committed by
Will Rouesnel
parent
265a2ea8eb
commit
c225a1e194
@@ -38,6 +38,7 @@ var (
|
|||||||
disableDefaultMetrics = kingpin.Flag("disable-default-metrics", "Do not include default metrics.").Default("false").OverrideDefaultFromEnvar("PG_EXPORTER_DISABLE_DEFAULT_METRICS").Bool()
|
disableDefaultMetrics = kingpin.Flag("disable-default-metrics", "Do not include default metrics.").Default("false").OverrideDefaultFromEnvar("PG_EXPORTER_DISABLE_DEFAULT_METRICS").Bool()
|
||||||
queriesPath = kingpin.Flag("extend.query-path", "Path to custom queries to run.").Default("").OverrideDefaultFromEnvar("PG_EXPORTER_EXTEND_QUERY_PATH").String()
|
queriesPath = kingpin.Flag("extend.query-path", "Path to custom queries to run.").Default("").OverrideDefaultFromEnvar("PG_EXPORTER_EXTEND_QUERY_PATH").String()
|
||||||
onlyDumpMaps = kingpin.Flag("dumpmaps", "Do not run, simply dump the maps.").Bool()
|
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("").OverrideDefaultFromEnvar("PG_EXPORTER_CONTANT_LABELS").String()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Metric name parts.
|
// Metric name parts.
|
||||||
@@ -484,13 +485,15 @@ func makeDescMap(pgVersion semver.Version, metricMaps map[string]map[string]Colu
|
|||||||
thisMap := make(map[string]MetricMap)
|
thisMap := make(map[string]MetricMap)
|
||||||
|
|
||||||
// Get the constant labels
|
// Get the constant labels
|
||||||
var constLabels []string
|
var variableLabels []string
|
||||||
for columnName, columnMapping := range mappings {
|
for columnName, columnMapping := range mappings {
|
||||||
if columnMapping.usage == LABEL {
|
if columnMapping.usage == LABEL {
|
||||||
constLabels = append(constLabels, columnName)
|
variableLabels = append(variableLabels, columnName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constLabels := newConstLabels()
|
||||||
|
|
||||||
for columnName, columnMapping := range mappings {
|
for columnName, columnMapping := range mappings {
|
||||||
// Check column version compatibility for the current map
|
// Check column version compatibility for the current map
|
||||||
// Force to discard if not compatible.
|
// Force to discard if not compatible.
|
||||||
@@ -522,7 +525,7 @@ func makeDescMap(pgVersion semver.Version, metricMaps map[string]map[string]Colu
|
|||||||
case COUNTER:
|
case COUNTER:
|
||||||
thisMap[columnName] = MetricMap{
|
thisMap[columnName] = MetricMap{
|
||||||
vtype: prometheus.CounterValue,
|
vtype: prometheus.CounterValue,
|
||||||
desc: prometheus.NewDesc(fmt.Sprintf("%s_%s", namespace, columnName), columnMapping.description, constLabels, nil),
|
desc: prometheus.NewDesc(fmt.Sprintf("%s_%s", namespace, columnName), columnMapping.description, variableLabels, constLabels),
|
||||||
conversion: func(in interface{}) (float64, bool) {
|
conversion: func(in interface{}) (float64, bool) {
|
||||||
return dbToFloat64(in)
|
return dbToFloat64(in)
|
||||||
},
|
},
|
||||||
@@ -530,7 +533,7 @@ func makeDescMap(pgVersion semver.Version, metricMaps map[string]map[string]Colu
|
|||||||
case GAUGE:
|
case GAUGE:
|
||||||
thisMap[columnName] = MetricMap{
|
thisMap[columnName] = MetricMap{
|
||||||
vtype: prometheus.GaugeValue,
|
vtype: prometheus.GaugeValue,
|
||||||
desc: prometheus.NewDesc(fmt.Sprintf("%s_%s", namespace, columnName), columnMapping.description, constLabels, nil),
|
desc: prometheus.NewDesc(fmt.Sprintf("%s_%s", namespace, columnName), columnMapping.description, variableLabels, constLabels),
|
||||||
conversion: func(in interface{}) (float64, bool) {
|
conversion: func(in interface{}) (float64, bool) {
|
||||||
return dbToFloat64(in)
|
return dbToFloat64(in)
|
||||||
},
|
},
|
||||||
@@ -538,7 +541,7 @@ func makeDescMap(pgVersion semver.Version, metricMaps map[string]map[string]Colu
|
|||||||
case MAPPEDMETRIC:
|
case MAPPEDMETRIC:
|
||||||
thisMap[columnName] = MetricMap{
|
thisMap[columnName] = MetricMap{
|
||||||
vtype: prometheus.GaugeValue,
|
vtype: prometheus.GaugeValue,
|
||||||
desc: prometheus.NewDesc(fmt.Sprintf("%s_%s", namespace, columnName), columnMapping.description, constLabels, nil),
|
desc: prometheus.NewDesc(fmt.Sprintf("%s_%s", namespace, columnName), columnMapping.description, variableLabels, constLabels),
|
||||||
conversion: func(in interface{}) (float64, bool) {
|
conversion: func(in interface{}) (float64, bool) {
|
||||||
text, ok := in.(string)
|
text, ok := in.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -555,7 +558,7 @@ func makeDescMap(pgVersion semver.Version, metricMaps map[string]map[string]Colu
|
|||||||
case DURATION:
|
case DURATION:
|
||||||
thisMap[columnName] = MetricMap{
|
thisMap[columnName] = MetricMap{
|
||||||
vtype: prometheus.GaugeValue,
|
vtype: prometheus.GaugeValue,
|
||||||
desc: prometheus.NewDesc(fmt.Sprintf("%s_%s_milliseconds", namespace, columnName), columnMapping.description, constLabels, nil),
|
desc: prometheus.NewDesc(fmt.Sprintf("%s_%s_milliseconds", namespace, columnName), columnMapping.description, variableLabels, constLabels),
|
||||||
conversion: func(in interface{}) (float64, bool) {
|
conversion: func(in interface{}) (float64, bool) {
|
||||||
var durationString string
|
var durationString string
|
||||||
switch t := in.(type) {
|
switch t := in.(type) {
|
||||||
@@ -583,7 +586,7 @@ func makeDescMap(pgVersion semver.Version, metricMaps map[string]map[string]Colu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
metricMap[namespace] = MetricMapNamespace{constLabels, thisMap}
|
metricMap[namespace] = MetricMapNamespace{variableLabels, thisMap}
|
||||||
}
|
}
|
||||||
|
|
||||||
return metricMap
|
return metricMap
|
||||||
@@ -715,29 +718,34 @@ func NewExporter(dsn string, disableDefaultMetrics bool, userQueriesPath string)
|
|||||||
Subsystem: exporter,
|
Subsystem: exporter,
|
||||||
Name: "last_scrape_duration_seconds",
|
Name: "last_scrape_duration_seconds",
|
||||||
Help: "Duration of the last scrape of metrics from PostgresSQL.",
|
Help: "Duration of the last scrape of metrics from PostgresSQL.",
|
||||||
|
ConstLabels: newConstLabels(),
|
||||||
}),
|
}),
|
||||||
totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{
|
totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Subsystem: exporter,
|
Subsystem: exporter,
|
||||||
Name: "scrapes_total",
|
Name: "scrapes_total",
|
||||||
Help: "Total number of times PostgresSQL was scraped for metrics.",
|
Help: "Total number of times PostgresSQL was scraped for metrics.",
|
||||||
|
ConstLabels: newConstLabels(),
|
||||||
}),
|
}),
|
||||||
error: prometheus.NewGauge(prometheus.GaugeOpts{
|
error: prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Subsystem: exporter,
|
Subsystem: exporter,
|
||||||
Name: "last_scrape_error",
|
Name: "last_scrape_error",
|
||||||
Help: "Whether the last scrape of metrics from PostgreSQL resulted in an error (1 for error, 0 for success).",
|
Help: "Whether the last scrape of metrics from PostgreSQL resulted in an error (1 for error, 0 for success).",
|
||||||
|
ConstLabels: newConstLabels(),
|
||||||
}),
|
}),
|
||||||
psqlUp: prometheus.NewGauge(prometheus.GaugeOpts{
|
psqlUp: prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Name: "up",
|
Name: "up",
|
||||||
Help: "Whether the last scrape of metrics from PostgreSQL was able to connect to the server (1 for yes, 0 for no).",
|
Help: "Whether the last scrape of metrics from PostgreSQL was able to connect to the server (1 for yes, 0 for no).",
|
||||||
|
ConstLabels: newConstLabels(),
|
||||||
}),
|
}),
|
||||||
userQueriesError: prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
userQueriesError: prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Subsystem: exporter,
|
Subsystem: exporter,
|
||||||
Name: "user_queries_load_error",
|
Name: "user_queries_load_error",
|
||||||
Help: "Whether the user queries file was loaded and parsed successfully (1 for error, 0 for success).",
|
Help: "Whether the user queries file was loaded and parsed successfully (1 for error, 0 for success).",
|
||||||
|
ConstLabels: newConstLabels(),
|
||||||
}, []string{"filename", "hashsum"}),
|
}, []string{"filename", "hashsum"}),
|
||||||
metricMap: nil,
|
metricMap: nil,
|
||||||
queryOverrides: nil,
|
queryOverrides: nil,
|
||||||
@@ -783,10 +791,32 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
|||||||
e.userQueriesError.Collect(ch)
|
e.userQueriesError.Collect(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newConstLabels() prometheus.Labels {
|
||||||
|
if constantLabelsList == nil || *constantLabelsList == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var constLabels = make(prometheus.Labels)
|
||||||
|
parts := strings.Split(*constantLabelsList, ",")
|
||||||
|
for _, p := range parts {
|
||||||
|
keyValue := strings.Split(strings.TrimSpace(p), "=")
|
||||||
|
if len(keyValue) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key := strings.TrimSpace(keyValue[0])
|
||||||
|
value := strings.TrimSpace(keyValue[1])
|
||||||
|
if key == "" || value == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
constLabels[key] = value
|
||||||
|
}
|
||||||
|
return constLabels
|
||||||
|
}
|
||||||
|
|
||||||
func newDesc(subsystem, name, help string) *prometheus.Desc {
|
func newDesc(subsystem, name, help string) *prometheus.Desc {
|
||||||
return prometheus.NewDesc(
|
return prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(namespace, subsystem, name),
|
prometheus.BuildFQName(namespace, subsystem, name),
|
||||||
help, nil, nil,
|
help, nil, newConstLabels(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,7 +902,7 @@ func queryNamespaceMapping(ch chan<- prometheus.Metric, db *sql.DB, namespace st
|
|||||||
} else {
|
} else {
|
||||||
// Unknown metric. Report as untyped if scan to float64 works, else note an error too.
|
// Unknown metric. Report as untyped if scan to float64 works, else note an error too.
|
||||||
metricLabel := fmt.Sprintf("%s_%s", namespace, columnName)
|
metricLabel := fmt.Sprintf("%s_%s", namespace, columnName)
|
||||||
desc := prometheus.NewDesc(metricLabel, fmt.Sprintf("Unknown metric from %s", namespace), mapping.labels, nil)
|
desc := prometheus.NewDesc(metricLabel, fmt.Sprintf("Unknown metric from %s", namespace), mapping.labels, newConstLabels())
|
||||||
|
|
||||||
// Its not an error to fail here, since the values are
|
// Its not an error to fail here, since the values are
|
||||||
// unexpected anyway.
|
// unexpected anyway.
|
||||||
@@ -976,7 +1006,7 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, db *sql.DB) err
|
|||||||
|
|
||||||
// Output the version as a special metric
|
// Output the version as a special metric
|
||||||
versionDesc := prometheus.NewDesc(fmt.Sprintf("%s_%s", namespace, staticLabelName),
|
versionDesc := prometheus.NewDesc(fmt.Sprintf("%s_%s", namespace, staticLabelName),
|
||||||
"Version string as reported by postgres", []string{"version", "short_version"}, nil)
|
"Version string as reported by postgres", []string{"version", "short_version"}, newConstLabels())
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(versionDesc,
|
ch <- prometheus.MustNewConstMetric(versionDesc,
|
||||||
prometheus.UntypedValue, 1, versionString, semanticVersion.String())
|
prometheus.UntypedValue, 1, versionString, semanticVersion.String())
|
||||||
|
Reference in New Issue
Block a user