Merged pull request #513 from influxdata/nc-http-logging

feat: Add optional http logging to handler
pull/10616/head
Nathaniel Cook 2018-07-31 11:17:04 -06:00
commit 422612fca7
3 changed files with 32 additions and 9 deletions

View File

@ -117,6 +117,7 @@ func fluxF(cmd *cobra.Command, args []string) {
handler := http.NewHandlerFromRegistry("query", reg) handler := http.NewHandlerFromRegistry("query", reg)
handler.Handler = queryHandler handler.Handler = queryHandler
handler.Logger = logger
logger.Info("listening", zap.String("transport", "http"), zap.String("addr", bindAddr)) logger.Info("listening", zap.String("transport", "http"), zap.String("addr", bindAddr))
if err := nethttp.ListenAndServe(bindAddr, handler); err != nil { if err := nethttp.ListenAndServe(bindAddr, handler); err != nil {

View File

@ -11,6 +11,7 @@ import (
"github.com/influxdata/platform/kit/prom" "github.com/influxdata/platform/kit/prom"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"go.uber.org/zap"
) )
const ( const (
@ -34,6 +35,9 @@ type Handler struct {
requests *prometheus.CounterVec requests *prometheus.CounterVec
requestDur *prometheus.HistogramVec requestDur *prometheus.HistogramVec
// Logger if set will log all HTTP requests as they are served
Logger *zap.Logger
} }
// NewHandler creates a new handler with the given name. // NewHandler creates a new handler with the given name.
@ -73,21 +77,31 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w = statusW w = statusW
// TODO: This could be problematic eventually. But for now it should be fine. // TODO: This could be problematic eventually. But for now it should be fine.
defer func() { defer func(start time.Time) {
duration := time.Since(start)
statusClass := statusW.statusCodeClass()
statusCode := statusW.code()
h.requests.With(prometheus.Labels{ h.requests.With(prometheus.Labels{
"handler": h.name, "handler": h.name,
"method": r.Method, "method": r.Method,
"path": r.URL.Path, "path": r.URL.Path,
"status": statusW.statusCodeClass(), "status": statusClass,
}).Inc() }).Inc()
}()
defer func(start time.Time) {
h.requestDur.With(prometheus.Labels{ h.requestDur.With(prometheus.Labels{
"handler": h.name, "handler": h.name,
"method": r.Method, "method": r.Method,
"path": r.URL.Path, "path": r.URL.Path,
"status": statusW.statusCodeClass(), "status": statusClass,
}).Observe(time.Since(start).Seconds()) }).Observe(duration.Seconds())
if h.Logger != nil {
h.Logger.Info("served http request",
zap.String("handler", h.name),
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.Int("status", statusCode),
zap.Int("duration_ns", int(duration)),
)
}
}(time.Now()) }(time.Now())
switch { switch {

View File

@ -19,13 +19,21 @@ func (w *statusResponseWriter) WriteHeader(statusCode int) {
w.ResponseWriter.WriteHeader(statusCode) w.ResponseWriter.WriteHeader(statusCode)
} }
func (w *statusResponseWriter) code() int {
code := w.statusCode
if code == 0 {
// When statusCode is 0 then WriteHeader was never called and we can assume that
// the ResponseWriter wrote an http.StatusOK.
code = http.StatusOK
}
return code
}
func (w *statusResponseWriter) statusCodeClass() string { func (w *statusResponseWriter) statusCodeClass() string {
class := "XXX" class := "XXX"
switch w.statusCode / 100 { switch w.code() / 100 {
case 1: case 1:
class = "1XX" class = "1XX"
case 0, 2: case 2:
// When statusCode is 0 then WriteHeader was never called and we can assume that the ResponseWriter wrote an http.StatusOK.
class = "2XX" class = "2XX"
case 3: case 3:
class = "3XX" class = "3XX"