forked from reachlin/sensu_exporter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsensu_exporter.go
135 lines (118 loc) · 2.84 KB
/
sensu_exporter.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
package main
import (
"encoding/json"
"flag"
"fmt"
"net/http"
"sync"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log"
)
var (
httpClient = &http.Client{
Timeout: 3 * time.Second,
}
listenAddress = flag.String(
// exporter port list:
// https://github.com/prometheus/prometheus/wiki/Default-port-allocations
"listen", ":9251",
"Address to listen on for serving Prometheus Metrics.",
)
sensuAPI = flag.String(
"api", "http://localhost:4567",
"Address to Sensu API.",
)
)
type SensuCheckResult struct {
Client string
Check SensuCheck
}
type SensuCheck struct {
Name string
Duration float64
Executed int64
Subscribers []string
Output string
Status int
Issued int64
Interval int
}
// BEGIN: Class SensuCollector
type SensuCollector struct {
apiUrl string
mutex sync.RWMutex
CheckStatus *prometheus.Desc
}
func (c *SensuCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.CheckStatus
}
func (c *SensuCollector) Collect(ch chan<- prometheus.Metric) {
c.mutex.Lock() // To protect metrics from concurrent collects.
defer c.mutex.Unlock()
results := c.getCheckResults()
for i, result := range results {
log.Debugln("...", fmt.Sprintf("%d, %v, %v", i, result.Check.Name, result.Check.Status))
// in Sensu, 0 means OK
// in Prometheus, 1 means OK
status := 0.0
if result.Check.Status == 0 {
status = 1.0
} else if result.Check.Status == 1 {
status = 0.0
} else {
status = float64(result.Check.Status)
}
ch <- prometheus.MustNewConstMetric(
c.CheckStatus,
prometheus.GaugeValue,
status,
result.Client,
result.Check.Name,
)
}
}
func (c *SensuCollector) getCheckResults() []SensuCheckResult {
log.Debugln("Sensu API URL", c.apiUrl)
results := []SensuCheckResult{}
err := c.GetJson(c.apiUrl+"/results", &results)
if err != nil {
log.Errorln("Query Sensu failed.", fmt.Sprintf("%v", err))
}
return results
}
func (c *SensuCollector) GetJson(url string, obj interface{}) error {
resp, err := httpClient.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
return json.NewDecoder(resp.Body).Decode(obj)
}
// END: Class SensuCollector
func NewSensuCollector(url string) *SensuCollector {
return &SensuCollector{
apiUrl: url,
CheckStatus: prometheus.NewDesc(
"sensu_check_status",
"Sensu Check Status(1:Up, 0:Down)",
[]string{"client", "check_name"},
nil,
),
}
}
func main() {
flag.Parse()
serveMetrics()
}
func serveMetrics() {
collector := NewSensuCollector(*sensuAPI)
prometheus.MustRegister(collector)
metricPath := "/metrics"
http.Handle(metricPath, prometheus.Handler())
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(metricPath))
})
log.Infoln("Listening on", *listenAddress)
log.Fatal(http.ListenAndServe(*listenAddress, nil))
}