diff --git a/pgpool2_exporter.go b/pgpool2_exporter.go index 098da35..b3c6460 100644 --- a/pgpool2_exporter.go +++ b/pgpool2_exporter.go @@ -31,15 +31,16 @@ import ( _ "os" "regexp" "strconv" + "strings" "sync" "time" + "github.com/alecthomas/kingpin/v2" "github.com/blang/semver" "github.com/go-kit/log/level" _ "github.com/lib/pq" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/promlog" - "github.com/alecthomas/kingpin/v2" ) var ( @@ -516,6 +517,17 @@ func queryNamespaceMapping(ch chan<- prometheus.Metric, db *sql.DB, namespace st continue } + if columnName == "replication_delay" { + value, ok := dbToDuration(columnData[idx]) + if !ok { + nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Unexpected error parsing column: ", namespace, columnName, columnData[idx]))) + continue + } + // Generate the metric + ch <- prometheus.MustNewConstMetric(metricMapping.desc, metricMapping.vtype, float64(value.Milliseconds()), labels...) + continue + } + value, ok := dbToFloat64(columnData[idx]) if !ok { nonfatalErrors = append(nonfatalErrors, errors.New(fmt.Sprintln("Unexpected error parsing column: ", namespace, columnName, columnData[idx]))) @@ -627,6 +639,38 @@ func dbToString(t interface{}) (string, bool) { } } +// Convert database.sql to string for Prometheus labels. Null types are mapped to empty strings. +func dbToDuration(t interface{}) (time.Duration, bool) { + switch v := t.(type) { + case int64: + return time.Duration(v * int64(time.Second)), true + case float64: + return time.Duration(int64(v * float64(time.Second))), true + case nil: + return time.Second * 0, true + case []byte: + result, err := parseDurationField(string(v)) + return result, err == nil + case string: + result, err := parseDurationField(v) + return result, err == nil + default: + return time.Second * 0, false + } +} + +// Convert string to time.duration. +func parseDurationField(value string) (time.Duration, error) { + fmt.Printf("", value) + strV := strings.TrimSuffix(strings.TrimSuffix(value, " seconds"), " second") + number, err := strconv.ParseFloat(strV, 64) + if err != nil { + level.Error(Logger).Log("msg", "Could not parse duration", "err", err) + return time.Second * 0, err + } + return time.Duration(int64(number * float64(time.Second))), nil +} + // Convert bool to int. func parseStatusField(value string) float64 { switch value {