forked from mirrors/statsd_exporter
add lifecycle api
Signed-off-by: glightfoot <glightfoot@rsglab.com>
This commit is contained in:
parent
da4a2950a7
commit
1293a24b59
2 changed files with 58 additions and 25 deletions
|
@ -82,6 +82,7 @@ Also, tags without values (`#some_tag`) are not supported and will be ignored.
|
||||||
NOTE: Version 0.7.0 switched to the [kingpin](https://github.com/alecthomas/kingpin) flags library. With this change, flag behaviour is POSIX-ish:
|
NOTE: Version 0.7.0 switched to the [kingpin](https://github.com/alecthomas/kingpin) flags library. With this change, flag behaviour is POSIX-ish:
|
||||||
|
|
||||||
* long flags start with two dashes (`--version`)
|
* long flags start with two dashes (`--version`)
|
||||||
|
* boolean long flags are disabled by prefixing with no (`--flag-name` is true, `--no-flag-name` is false)
|
||||||
* multiple short flags can be combined (but there currently is only one)
|
* multiple short flags can be combined (but there currently is only one)
|
||||||
* flag processing stops at the first `--`
|
* flag processing stops at the first `--`
|
||||||
|
|
||||||
|
@ -94,6 +95,7 @@ NOTE: Version 0.7.0 switched to the [kingpin](https://github.com/alecthomas/king
|
||||||
--web.listen-address=":9102"
|
--web.listen-address=":9102"
|
||||||
The address on which to expose the web interface
|
The address on which to expose the web interface
|
||||||
and generated Prometheus metrics.
|
and generated Prometheus metrics.
|
||||||
|
--web.enable-lifecycle Enable shutdown and reload via HTTP request.
|
||||||
--web.telemetry-path="/metrics"
|
--web.telemetry-path="/metrics"
|
||||||
Path under which to expose metrics.
|
Path under which to expose metrics.
|
||||||
--statsd.listen-udp=":9125"
|
--statsd.listen-udp=":9125"
|
||||||
|
@ -138,6 +140,11 @@ NOTE: Version 0.7.0 switched to the [kingpin](https://github.com/alecthomas/king
|
||||||
--version Show application version.
|
--version Show application version.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Lifecycle API
|
||||||
|
|
||||||
|
The `statsd_exporter` has an optional lifecycle API (disabled by default) that can be used to reload or quit the exporter
|
||||||
|
by sending a `PUT` or `POST` request to the `/-/reload` or `/-/quit` endpoints.
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
$ go test
|
$ go test
|
||||||
|
|
76
main.go
76
main.go
|
@ -199,23 +199,12 @@ func (u uncheckedCollector) Collect(c chan<- prometheus.Metric) {
|
||||||
u.c.Collect(c)
|
u.c.Collect(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveHTTP(listenAddress, metricsEndpoint string, logger log.Logger) {
|
func serveHTTP(mux http.Handler, listenAddress string, logger log.Logger) {
|
||||||
http.Handle(metricsEndpoint, promhttp.Handler())
|
level.Error(logger).Log("msg", http.ListenAndServe(listenAddress, mux))
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Write([]byte(`<html>
|
|
||||||
<head><title>StatsD Exporter</title></head>
|
|
||||||
<body>
|
|
||||||
<h1>StatsD Exporter</h1>
|
|
||||||
<p><a href="` + metricsEndpoint + `">Metrics</a></p>
|
|
||||||
</body>
|
|
||||||
</html>`))
|
|
||||||
})
|
|
||||||
level.Error(logger).Log("msg", http.ListenAndServe(listenAddress, nil))
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func configReloader(fileName string, mapper *mapper.MetricMapper, cacheSize int, logger log.Logger, option mapper.CacheOption) {
|
func sighupConfigReloader(fileName string, mapper *mapper.MetricMapper, cacheSize int, logger log.Logger, option mapper.CacheOption) {
|
||||||
|
|
||||||
signals := make(chan os.Signal, 1)
|
signals := make(chan os.Signal, 1)
|
||||||
signal.Notify(signals, syscall.SIGHUP)
|
signal.Notify(signals, syscall.SIGHUP)
|
||||||
|
|
||||||
|
@ -224,15 +213,21 @@ func configReloader(fileName string, mapper *mapper.MetricMapper, cacheSize int,
|
||||||
level.Warn(logger).Log("msg", "Received signal but no mapping config to reload", "signal", s)
|
level.Warn(logger).Log("msg", "Received signal but no mapping config to reload", "signal", s)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
level.Info(logger).Log("msg", "Received signal, attempting reload", "signal", s)
|
level.Info(logger).Log("msg", "Received signal, attempting reload", "signal", s)
|
||||||
err := mapper.InitFromFile(fileName, cacheSize, option)
|
|
||||||
if err != nil {
|
reloadConfig(fileName, mapper, cacheSize, logger, option)
|
||||||
level.Info(logger).Log("msg", "Error reloading config", "error", err)
|
}
|
||||||
configLoads.WithLabelValues("failure").Inc()
|
}
|
||||||
} else {
|
|
||||||
level.Info(logger).Log("msg", "Config reloaded successfully")
|
func reloadConfig(fileName string, mapper *mapper.MetricMapper, cacheSize int, logger log.Logger, option mapper.CacheOption) {
|
||||||
configLoads.WithLabelValues("success").Inc()
|
err := mapper.InitFromFile(fileName, cacheSize, option)
|
||||||
}
|
if err != nil {
|
||||||
|
level.Info(logger).Log("msg", "Error reloading config", "error", err)
|
||||||
|
configLoads.WithLabelValues("failure").Inc()
|
||||||
|
} else {
|
||||||
|
level.Info(logger).Log("msg", "Config reloaded successfully")
|
||||||
|
configLoads.WithLabelValues("success").Inc()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +248,7 @@ func dumpFSM(mapper *mapper.MetricMapper, dumpFilename string, logger log.Logger
|
||||||
func main() {
|
func main() {
|
||||||
var (
|
var (
|
||||||
listenAddress = kingpin.Flag("web.listen-address", "The address on which to expose the web interface and generated Prometheus metrics.").Default(":9102").String()
|
listenAddress = kingpin.Flag("web.listen-address", "The address on which to expose the web interface and generated Prometheus metrics.").Default(":9102").String()
|
||||||
|
enableLifecycle = kingpin.Flag("web.enable-lifecycle", "Enable shutdown and reload via HTTP request.").Default("false").Bool()
|
||||||
metricsEndpoint = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String()
|
metricsEndpoint = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String()
|
||||||
statsdListenUDP = kingpin.Flag("statsd.listen-udp", "The UDP address on which to receive statsd metric lines. \"\" disables it.").Default(":9125").String()
|
statsdListenUDP = kingpin.Flag("statsd.listen-udp", "The UDP address on which to receive statsd metric lines. \"\" disables it.").Default(":9125").String()
|
||||||
statsdListenTCP = kingpin.Flag("statsd.listen-tcp", "The TCP address on which to receive statsd metric lines. \"\" disables it.").Default(":9125").String()
|
statsdListenTCP = kingpin.Flag("statsd.listen-tcp", "The TCP address on which to receive statsd metric lines. \"\" disables it.").Default(":9125").String()
|
||||||
|
@ -289,8 +285,6 @@ func main() {
|
||||||
level.Info(logger).Log("msg", "Accepting StatsD Traffic", "udp", *statsdListenUDP, "tcp", *statsdListenTCP, "unixgram", *statsdListenUnixgram)
|
level.Info(logger).Log("msg", "Accepting StatsD Traffic", "udp", *statsdListenUDP, "tcp", *statsdListenTCP, "unixgram", *statsdListenUnixgram)
|
||||||
level.Info(logger).Log("msg", "Accepting Prometheus Requests", "addr", *listenAddress)
|
level.Info(logger).Log("msg", "Accepting Prometheus Requests", "addr", *listenAddress)
|
||||||
|
|
||||||
go serveHTTP(*listenAddress, *metricsEndpoint, logger)
|
|
||||||
|
|
||||||
events := make(chan event.Events, *eventQueueSize)
|
events := make(chan event.Events, *eventQueueSize)
|
||||||
defer close(events)
|
defer close(events)
|
||||||
eventQueue := event.NewEventQueue(events, *eventFlushThreshold, *eventFlushInterval, eventsFlushed)
|
eventQueue := event.NewEventQueue(events, *eventFlushThreshold, *eventFlushInterval, eventsFlushed)
|
||||||
|
@ -448,10 +442,42 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.Handle(*metricsEndpoint, promhttp.Handler())
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte(`<html>
|
||||||
|
<head><title>StatsD Exporter</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>StatsD Exporter</h1>
|
||||||
|
<p><a href="` + *metricsEndpoint + `">Metrics</a></p>
|
||||||
|
</body>
|
||||||
|
</html>`))
|
||||||
|
})
|
||||||
|
if *enableLifecycle {
|
||||||
|
mux.HandleFunc("/-/reload", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method == http.MethodPut || r.Method == http.MethodPost {
|
||||||
|
if *mappingConfig == "" {
|
||||||
|
level.Warn(logger).Log("msg", "Received lifecycle api reload but no mapping config to reload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
level.Info(logger).Log("msg", "Received lifecycle api reload, attempting reload")
|
||||||
|
reloadConfig(*mappingConfig, mapper, *cacheSize, logger, cacheOption)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
mux.HandleFunc("/-/quit", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method == http.MethodPut || r.Method == http.MethodPost {
|
||||||
|
level.Info(logger).Log("msg", "Received lifecycle api quit, exiting")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
go serveHTTP(mux, *listenAddress, logger)
|
||||||
|
|
||||||
signals := make(chan os.Signal, 1)
|
signals := make(chan os.Signal, 1)
|
||||||
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
|
||||||
|
|
||||||
go configReloader(*mappingConfig, mapper, *cacheSize, logger, cacheOption)
|
go sighupConfigReloader(*mappingConfig, mapper, *cacheSize, logger, cacheOption)
|
||||||
go exporter.Listen(events)
|
go exporter.Listen(events)
|
||||||
|
|
||||||
<-signals
|
<-signals
|
||||||
|
|
Loading…
Reference in a new issue