-
Notifications
You must be signed in to change notification settings - Fork 14
/
sensu_exporter.go
130 lines (115 loc) · 2.87 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
package main
import (
"encoding/json"
"flag"
"fmt"
"net/http"
"sync"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log"
)
var (
timeout = flag.Duration("timeout", 20, "Timeout in seconds for the API request")
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
cli *http.Client
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 {
status = 0.0
}
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 := c.cli.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, cli *http.Client) *SensuCollector {
return &SensuCollector{
cli: cli,
apiUrl: url,
CheckStatus: prometheus.NewDesc(
"sensu_check_status",
"Sensu Check Status(1:Up, 0:Down)",
[]string{"client", "check_name"},
nil,
),
}
}
func main() {
flag.Parse()
collector := NewSensuCollector(*sensuAPI, &http.Client{
Timeout: *timeout,
})
fmt.Println(collector.cli.Timeout)
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))
}