-
Notifications
You must be signed in to change notification settings - Fork 7
/
main.go
143 lines (123 loc) · 3.18 KB
/
main.go
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
139
140
141
142
143
package main
import (
"bufio"
"flag"
"fmt"
"log"
"net/http"
"os"
"regexp"
"strconv"
"strings"
"syscall"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
/* CLI flags */
var (
addr = flag.String("listen-address", ":8080", "The address to listen on for HTTP requests.")
interval = flag.Int("refresh-interval", 60, "Metric refresh interval in seconds")
/* BackupPC-specific */
dataDir = flag.String("data-dir", "/var/lib/backuppc", "Path to directory with pc, cpool and pool directories")
configDir = flag.String("config-dir", "/etc/backuppc", "Path to directory BackupPC configuration config.pl")
)
/* DiskUsage - https://gist.github.com/lunny/9828326 */
type DiskStatus struct {
All uint64 `json:"all"`
Used uint64 `json:"used"`
Free uint64 `json:"free"`
}
// disk usage of path/disk
func DiskUsage(path string) (disk DiskStatus) {
fs := syscall.Statfs_t{}
err := syscall.Statfs(path, &fs)
if err != nil {
return
}
disk.All = fs.Blocks * uint64(fs.Bsize)
disk.Free = fs.Bfree * uint64(fs.Bsize)
disk.Used = disk.All - disk.Free
return
}
const (
B = 1
KB = 1024 * B
MB = 1024 * KB
GB = 1024 * MB
)
/* Metrics */
var (
poolUsageMetric = prometheus.NewGauge(prometheus.GaugeOpts{Name: "backuppc_pool_usage", Help: "BackupPC pool usage (0 to 1)"})
lastAgeMetric = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "backuppc_last_age",
Help: "Age of most recent backup for every host, in seconds.",
},
[]string{
"hostname",
},
)
)
func poolUsageMetricFn() {
disk := DiskUsage(fmt.Sprintf("%s/cpool", *dataDir))
poolUsageFloat := float64(disk.Used) / float64(disk.All)
poolUsageMetric.Set(poolUsageFloat)
}
func hosts() []string {
var hostsFound []string
hostsFile := fmt.Sprintf("%s/hosts", *configDir)
file, err := os.Open(hostsFile)
if err == nil {
scanner := bufio.NewScanner(file)
for scanner.Scan() {
s := scanner.Text()
match, _ := regexp.MatchString("^ *(#).*$", s)
fields := strings.Fields(s)
if !match && len(fields) >= 2 {
hostname := fields[0]
if hostname != "host" {
hostsFound = append(hostsFound, hostname)
}
}
}
}
defer file.Close()
return hostsFound
}
func lastAgeMetricFn() {
for _, hostname := range hosts() {
backupsPath := fmt.Sprintf("%s/pc/%s/backups", *dataDir, hostname)
file, err := os.Open(backupsPath)
if err == nil {
scanner := bufio.NewScanner(file)
minAge := int64(-1)
for scanner.Scan() {
s := scanner.Text()
if strings.Contains(s, "full") || strings.Contains(s, "incr") {
timestamp, _ := strconv.Atoi((strings.Fields(s)[2]))
age := time.Now().Unix() - int64(timestamp)
if minAge < 0 || minAge > age {
minAge = age
}
}
}
lastAgeMetric.WithLabelValues(hostname).Set(float64(minAge))
}
defer file.Close()
}
}
func main() {
flag.Parse()
prometheus.MustRegister(poolUsageMetric)
prometheus.MustRegister(lastAgeMetric)
ticker := time.NewTicker(time.Duration(*interval) * time.Second)
go func() {
for range ticker.C {
poolUsageMetricFn()
lastAgeMetricFn()
}
}()
http.Handle("/metrics", promhttp.Handler())
log.Fatal(http.ListenAndServe(*addr, nil))
}