File: backrest_exporter.go

package info (click to toggle)
prometheus-pgbackrest-exporter 0.19.0%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 480 kB
  • sloc: sh: 141; makefile: 136
file content (138 lines) | stat: -rw-r--r-- 5,997 bytes parent folder | download
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)
}