package main
import (
"context"
"fmt"
"log"
"net"
"net/http"
"os"
"github.com/gorilla/handlers"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// HTTPOutput serves the Prometheus metrics endpoint.
type HTTPOutput struct {
server *http.Server
config *HTTPOutputConfig
}
// NewHTTPOutput creates the HTTP output and applies the current configuration.
func NewHTTPOutput() *HTTPOutput {
s := new(HTTPOutput)
s.server = &http.Server{}
s.Reload()
return s
}
// AddHandlers (re)builds the request multiplexer: the metrics endpoint plus a
// landing page linking to it.
func (s *HTTPOutput) AddHandlers() {
mux := http.NewServeMux()
s.server.Handler = mux
mux.Handle(s.config.MetricsPath, handlers.CombinedLoggingHandler(os.Stdout, promhttp.HandlerFor(app.registry, promhttp.HandlerOpts{})))
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`
Drive Health Metrics
Drive Health Metrics
Metrics
`))
})
}
// Reload refreshes the configuration, listen address, and handlers.
func (s *HTTPOutput) Reload() {
s.config = &app.config.HTTP
s.server.Addr = fmt.Sprintf("%s:%d", s.config.BindAddr, s.config.Port)
s.AddHandlers()
}
// OutputEnabled reports whether the HTTP output is enabled.
func (s *HTTPOutput) OutputEnabled() bool {
return s.config.Enabled
}
// Start launches the server and blocks until it is accepting connections.
func (s *HTTPOutput) Start(ctx context.Context) {
isListening := make(chan bool)
go s.StartWithIsListening(ctx, isListening)
<-isListening
}
// StartWithIsListening runs the server, signalling on isListening once the
// listener is bound, and shutting down when the context is cancelled.
func (s *HTTPOutput) StartWithIsListening(ctx context.Context, isListening chan bool) {
if !s.config.Enabled {
isListening <- true
return
}
go func() {
<-ctx.Done()
if err := s.server.Shutdown(context.Background()); err != nil {
log.Println("Error shutting down http server:", err)
}
}()
log.Println("Starting http server:", s.server.Addr)
l, err := net.Listen("tcp", s.server.Addr)
if err != nil {
log.Fatal("Listen: ", err)
}
isListening <- true
if err := s.server.Serve(l); err != nil && err != http.ErrServerClosed {
log.Println("HTTP server failure:", err)
}
}