1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
package backrest
import (
"net/http"
"os"
"time"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/exporter-toolkit/web"
)
var (
webFlagsConfig web.FlagConfig
webEndpoint string
// When reset metrics.
// Before receiving information from pgBackRest (false) or after (true).
MetricResetFlag bool = true
)
// SetPromPortAndPath sets HTTP endpoint parameters
// from command line arguments:
// 'web.endpoint',
// 'web.listen-address',
// 'web.config.file',
// 'web.systemd-socket' (Linux only)
func SetPromPortAndPath(flagsConfig web.FlagConfig, endpoint string) {
webFlagsConfig = flagsConfig
webEndpoint = endpoint
}
// StartPromEndpoint run HTTP endpoint
func StartPromEndpoint(logger log.Logger) {
go func(logger log.Logger) {
http.Handle(webEndpoint, promhttp.Handler())
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`<html>
<head><title>pgBackRest exporter</title></head>
<body>
<h1>pgBackRest exporter</h1>
<p><a href='` + webEndpoint + `'>Metrics</a></p>
</body>
</html>`))
})
server := &http.Server{
ReadHeaderTimeout: 5 * time.Second,
}
if err := web.ListenAndServe(server, &webFlagsConfig, logger); err != nil {
level.Error(logger).Log("msg", "Run web endpoint failed", "err", err)
os.Exit(1)
}
}(logger)
}
// GetPgBackRestInfo get and parse pgBackRest info and set metrics
func GetPgBackRestInfo(config, configIncludePath, backupType string, stanzas, stanzasExclude []string, backupReferenceCount, backupDBCount, backupDBCountLatest, verboseWAL bool, backupDBCountParallelProcesses int, logger log.Logger) {
// To calculate the time elapsed since the last completed full, differential or incremental backup.
// For all stanzas values are calculated relative to one value.
currentUnixTime := time.Now().Unix()
// If specific stanzas are specified for collecting metrics,
// then we reset all metrics before the loop.
// Otherwise, it makes sense to reset the metrics after receiving data from pgBackRest,
// because this operation can be long.
if !MetricResetFlag {
resetMetrics()
}
// Loop over each stanza.
// If stanza not set - perform a single loop step to get metrics for all stanzas.
for _, stanza := range stanzas {
// Flag to check if pgBackRest get info for this stanza.
// By default, it's set to true.
// If we get an error from pgBackRest when getting info for stanza, flag will be set to false.
getDataSuccessStatus := true
// Check that stanza from the include list is not in the exclude list.
// If stanza not set - checking for entry into the exclude list will be performed later.
if stanzaNotInExclude(stanza, stanzasExclude) {
stanzaData, err := getAllInfoData(config, configIncludePath, stanza, backupType, logger)
if err != nil {
getDataSuccessStatus = false
level.Error(logger).Log("msg", "Get data from pgBackRest failed", "err", err)
}
parseStanzaData, err := parseResult(stanzaData)
if err != nil {
getDataSuccessStatus = false
level.Error(logger).Log("msg", "Parse JSON failed", "err", err)
}
if len(parseStanzaData) == 0 {
level.Warn(logger).Log("msg", "No backup data returned")
}
// When no specific stanzas set for collecting we can reset the metrics as late as possible.
if MetricResetFlag {
resetMetrics()
}
getExporterStatusMetrics(stanza, getDataSuccessStatus, setUpMetricValue, logger)
for _, singleStanza := range parseStanzaData {
// If stanza is in the exclude list, skip it.
if stanzaNotInExclude(singleStanza.Name, stanzasExclude) {
getStanzaMetrics(singleStanza.Name, singleStanza.Status, setUpMetricValue, logger)
getRepoMetrics(singleStanza.Name, singleStanza.Repo, setUpMetricValue, logger)
getWALMetrics(singleStanza.Name, singleStanza.Archive, singleStanza.DB, verboseWAL, setUpMetricValue, logger)
// Last backups for current stanza
lastBackups := getBackupMetrics(singleStanza.Name, backupReferenceCount, singleStanza.Backup, singleStanza.DB, setUpMetricValue, logger)
// If full backup exists, the values of metrics for differential and
// incremental backups also will be set.
// If not - metrics won't be set.
if !lastBackups.full.backupTime.IsZero() {
getBackupLastMetrics(singleStanza.Name, lastBackups, currentUnixTime, setUpMetricValue, logger)
}
// If the calculation of the number of databases in backups is enabled.
// Information about number of databases in specific backup has appeared since pgBackRest v2.41.
// In versions < v2.41 this is missing and the metric will be set to 0.
if backupDBCount {
getBackupDBCountMetrics(backupDBCountParallelProcesses, config, configIncludePath, singleStanza.Name, singleStanza.Backup, setUpMetricValue, logger)
}
// If the calculation of the number of databases in latest backups is enabled.
// Information about number of databases in specific backup has appeared since pgBackRest v2.41.
// In versions < v2.41 this is missing and the metric will be set to 0.
if backupDBCountLatest && !lastBackups.full.backupTime.IsZero() {
getBackupLastDBCountMetrics(config, configIncludePath, singleStanza.Name, lastBackups, setUpMetricValue, logger)
}
}
}
} else {
// When stanza is specified in both include and exclude lists, a warning is displayed in the log
// and data for this stanza is not collected.
// It is necessary to set zero metric value for this stanza.
getDataSuccessStatus = false
getExporterStatusMetrics(stanza, getDataSuccessStatus, setUpMetricValue, logger)
level.Warn(logger).Log("msg", "Stanza is specified in include and exclude lists", "stanza", stanza)
}
}
}
// GetExporterInfo set exporter info metric
func GetExporterInfo(exporterVersion string, logger log.Logger) {
getExporterMetrics(exporterVersion, setUpMetricValue, logger)
}
|