-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.go
176 lines (142 loc) · 4.19 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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Package main is the main runtime of the birdwatcher application
package main
import (
"encoding/json"
"flag"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/coreos/go-systemd/daemon"
"github.com/prometheus/client_golang/prometheus/promhttp"
log "github.com/sirupsen/logrus"
"github.com/skoef/birdwatcher/birdwatcher"
)
const (
systemdStatusBufferSize = 32
)
// variables filled in by goreleaser during release
var (
version = "devel"
commit = "none"
// date = "unknown"
)
//nolint:funlen // we should refactor this a bit
func main() {
// initialize logging
log.SetOutput(os.Stdout)
log.SetLevel(log.InfoLevel)
var (
configFile = flag.String("config", "/etc/birdwatcher.conf", "path to config file")
checkConfig = flag.Bool("check-config", false, "check config file and exit")
debugFlag = flag.Bool("debug", false, "increase loglevel to debug")
useSystemd = flag.Bool("systemd", false, "optimize behavior for running under systemd")
versionFlag = flag.Bool("version", false, "show version and exit")
)
flag.Parse()
if *versionFlag {
fmt.Printf("birdwatcher, %s (%s)\n", version, commit)
return
}
log.Infof("starting birdwatcher, %s (%s)", version, commit)
if *debugFlag {
log.SetLevel(log.DebugLevel)
}
if *useSystemd {
// if we're running under systemd, we don't need the timestamps
// since journald will take care of those
log.SetFormatter(&log.TextFormatter{DisableTimestamp: true})
}
log.WithFields(log.Fields{
"configFile": *configFile,
}).Debug("opening configuration file")
var config birdwatcher.Config
if err := birdwatcher.ReadConfig(&config, *configFile); err != nil {
// return slightly different message when birdwatcher was invoked with -check-config
if *checkConfig {
fmt.Printf("Configuration file %s not OK: %s\n", *configFile, err)
os.Exit(1)
}
log.Fatal(err.Error())
}
if *checkConfig {
fmt.Printf("Configuration file %s OK\n", *configFile)
if *debugFlag {
configJSON, err := json.MarshalIndent(config, "", " ")
if err != nil {
log.Fatal(err.Error())
}
fmt.Println(string(configJSON))
}
return
}
// enable prometheus
// Expose /metrics HTTP endpoint using the created custom registry.
if config.Prometheus.Enabled {
go func() {
if err := startPrometheus(config.Prometheus); err != nil {
log.WithError(err).Fatal("could not start prometheus exporter")
}
}()
}
// start health checker
hc := birdwatcher.NewHealthCheck(config)
ready := make(chan bool)
// create status update channel for systemd
// give it a little buffer so the chances of it blocking the health check
// is low
sdStatus := make(chan string, systemdStatusBufferSize)
go func() {
// make sure we read from the sdStatus channel, regardless if we use
// systemd integration or not to prevent the channel from blocking
for update := range sdStatus {
if *useSystemd {
log.Debug("notifying systemd of new status")
sdnotify("STATUS=" + update)
}
}
}()
go hc.Start(config.GetServices(), ready, sdStatus)
// wait for all health services to have started
<-ready
if *useSystemd {
log.Debug("notifying systemd birdwatcher is ready")
sdnotify(daemon.SdNotifyReady)
}
// wait until interrupted
signalCh := make(chan os.Signal, 1)
signal.Notify(signalCh, os.Interrupt)
signal.Notify(signalCh, syscall.SIGTERM, syscall.SIGQUIT)
sig := <-signalCh
log.WithFields(log.Fields{
"signal": sig,
}).Info("signal received, stopping")
if *useSystemd {
log.Debug("notifying systemd birdwatcher is stopping")
sdnotify(daemon.SdNotifyStopping)
}
hc.Stop()
}
// sdnotify is a little wrapper for daemon.SdNotify
func sdnotify(msg string) {
if ok, err := daemon.SdNotify(false, msg); ok && err != nil {
log.WithError(err).Error("could not notify systemd")
}
}
func startPrometheus(c birdwatcher.PrometheusConfig) error {
log.WithFields(log.Fields{
"port": c.Port,
"path": c.Path,
}).Info("starting prometheus exporter")
mux := http.NewServeMux()
mux.Handle(c.Path, promhttp.Handler())
httpServer := &http.Server{
Addr: fmt.Sprintf("0.0.0.0:%d", c.Port),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
Handler: mux,
}
return httpServer.ListenAndServe()
}