mirror of
https://github.com/prometheus-community/postgres_exporter
synced 2025-05-04 17:08:02 +00:00
Add explicit type conversion functions from sql to prometheus.
This commit is contained in:
parent
0fd7504047
commit
c92bb1e610
@ -11,7 +11,7 @@ import (
|
|||||||
//"strconv"
|
//"strconv"
|
||||||
//"strings"
|
//"strings"
|
||||||
"time"
|
"time"
|
||||||
//"math"
|
"math"
|
||||||
|
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@ -98,9 +98,9 @@ var metricMaps = map[string]map[string]ColumnMapping {
|
|||||||
"stats_reset" : { COUNTER, "Time at which these statistics were last reset", nil },
|
"stats_reset" : { COUNTER, "Time at which these statistics were last reset", nil },
|
||||||
},
|
},
|
||||||
"pg_stat_database" : map[string]ColumnMapping {
|
"pg_stat_database" : map[string]ColumnMapping {
|
||||||
"datid" : { COUNTER, "OID of a database", nil },
|
"datid" : { LABEL, "OID of a database", nil },
|
||||||
"datname" : { COUNTER, "Name of this database", nil },
|
"datname" : { LABEL, "Name of this database", nil },
|
||||||
"numbackends" : { COUNTER, "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 },
|
"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 },
|
||||||
"xact_commit" : { COUNTER, "Number of transactions in this database that have been committed", nil },
|
"xact_commit" : { COUNTER, "Number of transactions in this database that have been committed", nil },
|
||||||
"xact_rollback" : { COUNTER, "Number of transactions in this database that have been rolled back", nil },
|
"xact_rollback" : { COUNTER, "Number of transactions in this database that have been rolled back", nil },
|
||||||
"blks_read" : { COUNTER, "Number of disk blocks read in this database", nil },
|
"blks_read" : { COUNTER, "Number of disk blocks read in this database", nil },
|
||||||
@ -119,8 +119,8 @@ var metricMaps = map[string]map[string]ColumnMapping {
|
|||||||
"stats_reset" : { COUNTER, "Time at which these statistics were last reset", nil },
|
"stats_reset" : { COUNTER, "Time at which these statistics were last reset", nil },
|
||||||
},
|
},
|
||||||
"pg_stat_database_conflicts" : map[string]ColumnMapping {
|
"pg_stat_database_conflicts" : map[string]ColumnMapping {
|
||||||
"datid" : { COUNTER, "OID of a database", nil },
|
"datid" : { LABEL, "OID of a database", nil },
|
||||||
"datname" : { COUNTER, "Name of this database", nil },
|
"datname" : { LABEL, "Name of this database", nil },
|
||||||
"confl_tablespace" : { COUNTER, "Number of queries in this database that have been canceled due to dropped tablespaces", nil },
|
"confl_tablespace" : { COUNTER, "Number of queries in this database that have been canceled due to dropped tablespaces", nil },
|
||||||
"confl_lock" : { COUNTER, "Number of queries in this database that have been canceled due to lock timeouts", nil },
|
"confl_lock" : { COUNTER, "Number of queries in this database that have been canceled due to lock timeouts", nil },
|
||||||
"confl_snapshot" : { COUNTER, "Number of queries in this database that have been canceled due to old snapshots", nil },
|
"confl_snapshot" : { COUNTER, "Number of queries in this database that have been canceled due to old snapshots", nil },
|
||||||
@ -175,6 +175,44 @@ func makeDescMap(metricMaps map[string]map[string]ColumnMapping) map[string]Metr
|
|||||||
return metricMap
|
return metricMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 nil:
|
||||||
|
return math.NaN(), true
|
||||||
|
default:
|
||||||
|
return math.NaN(), 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
|
||||||
|
default:
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Exporter collects MySQL metrics. It implements prometheus.Collector.
|
// Exporter collects MySQL metrics. It implements prometheus.Collector.
|
||||||
type Exporter struct {
|
type Exporter struct {
|
||||||
dsn string
|
dsn string
|
||||||
@ -270,6 +308,7 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) {
|
|||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
for namespace, mapping := range e.metricMap {
|
for namespace, mapping := range e.metricMap {
|
||||||
|
log.Debugln("Querying namespace: ", namespace)
|
||||||
func () { // Don't fail on a bad scrape of one metric
|
func () { // Don't fail on a bad scrape of one metric
|
||||||
rows, err := db.Query(fmt.Sprintf("SELECT * FROM %s;", namespace))
|
rows, err := db.Query(fmt.Sprintf("SELECT * FROM %s;", namespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -293,7 +332,7 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) {
|
|||||||
columnIdx[n] = i
|
columnIdx[n] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
var columnData = make([]sql.RawBytes, len(columnNames))
|
var columnData = make([]interface{}, len(columnNames))
|
||||||
var scanArgs = make([]interface{}, len(columnNames))
|
var scanArgs = make([]interface{}, len(columnNames))
|
||||||
for i := range columnData {
|
for i := range columnData {
|
||||||
scanArgs[i] = &columnData[i]
|
scanArgs[i] = &columnData[i]
|
||||||
@ -310,7 +349,7 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) {
|
|||||||
// Get the label values for this row
|
// Get the label values for this row
|
||||||
var labels = make([]string, len(mapping.labels))
|
var labels = make([]string, len(mapping.labels))
|
||||||
for i, n := range labels {
|
for i, n := range labels {
|
||||||
labels[i] = string(columnData[columnIdx[n]])
|
labels[i], _ = dbToString(columnData[columnIdx[n]])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop over column names, and match to scan data. Unknown columns
|
// Loop over column names, and match to scan data. Unknown columns
|
||||||
@ -322,16 +361,13 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) {
|
|||||||
if metricMapping.discard {
|
if metricMapping.discard {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var value float64
|
value, ok := dbToFloat64(columnData[idx])
|
||||||
var nf sql.NullFloat64
|
if ! ok {
|
||||||
err = nf.Scan(columnData[idx])
|
|
||||||
if err != nil {
|
|
||||||
e.error.Set(1)
|
e.error.Set(1)
|
||||||
log.Errorln("Unexpected error parsing column: ", namespace, columnName, err)
|
log.Errorln("Unexpected error parsing column: ", namespace, columnName, columnData[idx])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
value = nf.Float64
|
|
||||||
|
|
||||||
// Generate the metric
|
// Generate the metric
|
||||||
ch <- prometheus.MustNewConstMetric(metricMapping.desc, metricMapping.vtype, value, labels...)
|
ch <- prometheus.MustNewConstMetric(metricMapping.desc, metricMapping.vtype, value, labels...)
|
||||||
@ -341,13 +377,11 @@ func (e *Exporter) scrape(ch chan<- prometheus.Metric) {
|
|||||||
|
|
||||||
// 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.
|
||||||
var value float64
|
value, ok := dbToFloat64(columnData[idx])
|
||||||
var nf sql.NullFloat64
|
if ! ok {
|
||||||
err = nf.Scan(columnData[idx])
|
log.Warnln("Unparseable column type - discarding: ", namespace, columnName, err)
|
||||||
if err != nil {
|
continue
|
||||||
log.Warnln("Could not parse unknown column to float64: ", namespace, columnName, err)
|
|
||||||
}
|
}
|
||||||
value = nf.Float64
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(desc, prometheus.UntypedValue, value, labels...)
|
ch <- prometheus.MustNewConstMetric(desc, prometheus.UntypedValue, value, labels...)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user