Implemented handler to fetch broker stats

This implements a handler at https://[snowflake-broker]/metrics for the
snowflake collecTor module to fetch stats from the broker. Logged
metrics are copied out to the response with a text/plain; charset=utf-8
content type. This implements bug #31376.
This commit is contained in:
Cecylia Bocovich 2019-08-13 11:44:15 -04:00
parent 4e5a50f2b5
commit 0aef40100a

View file

@ -67,6 +67,12 @@ type SnowflakeHandler struct {
handle func(*BrokerContext, http.ResponseWriter, *http.Request) handle func(*BrokerContext, http.ResponseWriter, *http.Request)
} }
// Implements the http.Handler interface
type MetricsHandler struct {
logFilename string
handle func(string, http.ResponseWriter, *http.Request)
}
func (sh SnowflakeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (sh SnowflakeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Session-ID") w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Session-ID")
@ -77,6 +83,16 @@ func (sh SnowflakeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
sh.handle(sh.BrokerContext, w, r) sh.handle(sh.BrokerContext, w, r)
} }
func (mh MetricsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Session-ID")
// Return early if it's CORS preflight.
if "OPTIONS" == r.Method {
return
}
mh.handle(mh.logFilename, w, r)
}
// Proxies may poll for client offers concurrently. // Proxies may poll for client offers concurrently.
type ProxyPoll struct { type ProxyPoll struct {
id string id string
@ -251,6 +267,23 @@ func robotsTxtHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("User-agent: *\nDisallow: /\n")) w.Write([]byte("User-agent: *\nDisallow: /\n"))
} }
func metricsHandler(metricsFilename string, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
if metricsFilename == "" {
http.NotFound(w, r)
return
}
metricsFile, err := os.OpenFile(metricsFilename, os.O_RDONLY, 0644)
if err != nil {
log.Println("Error opening metrics file for reading")
http.NotFound(w, r)
return
}
io.Copy(w, metricsFile)
}
func main() { func main() {
var acmeEmail string var acmeEmail string
var acmeHostnamesCommas string var acmeHostnamesCommas string
@ -313,6 +346,7 @@ func main() {
http.Handle("/client", SnowflakeHandler{ctx, clientOffers}) http.Handle("/client", SnowflakeHandler{ctx, clientOffers})
http.Handle("/answer", SnowflakeHandler{ctx, proxyAnswers}) http.Handle("/answer", SnowflakeHandler{ctx, proxyAnswers})
http.Handle("/debug", SnowflakeHandler{ctx, debugHandler}) http.Handle("/debug", SnowflakeHandler{ctx, debugHandler})
http.Handle("/metrics", MetricsHandler{metricsFilename, metricsHandler})
server := http.Server{ server := http.Server{
Addr: addr, Addr: addr,