Files
weave-scope/common/middleware/logging.go

70 lines
1.9 KiB
Go

package middleware
import (
"bufio"
"fmt"
"net"
"net/http"
"time"
log "github.com/Sirupsen/logrus"
)
// Log middleware logs http requests
type Log struct {
LogSuccess bool // LogSuccess true -> log successful queries; false -> only log failed queries
}
// Wrap implements Middleware
func (l Log) Wrap(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
begin := time.Now()
uri := r.RequestURI // capture the URI before running next, as it may get rewritten
i := &interceptor{ResponseWriter: w, statusCode: http.StatusOK}
next.ServeHTTP(i, r)
if l.LogSuccess || !(100 <= i.statusCode && i.statusCode < 400) {
log.Infof("%s %s (%d) %s", r.Method, uri, i.statusCode, time.Since(begin))
}
})
}
// Logging middleware logs each HTTP request method, path, response code and
// duration for all HTTP requests.
var Logging = Log{
LogSuccess: true,
}
// LogFailed middleware logs each HTTP request method, path, response code and
// duration for non-2xx HTTP requests.
var LogFailed = Log{
LogSuccess: false,
}
// interceptor implements WriteHeader to intercept status codes. WriteHeader
// may not be called on success, so initialize statusCode with the status you
// want to report on success, i.e. http.StatusOK.
//
// interceptor also implements net.Hijacker, to let the downstream Handler
// hijack the connection. This is needed, for example, for working with websockets.
type interceptor struct {
http.ResponseWriter
statusCode int
recorded bool
}
func (i *interceptor) WriteHeader(code int) {
if !i.recorded {
i.statusCode = code
i.recorded = true
}
i.ResponseWriter.WriteHeader(code)
}
func (i *interceptor) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hj, ok := i.ResponseWriter.(http.Hijacker)
if !ok {
return nil, nil, fmt.Errorf("interceptor: can't cast parent ResponseWriter to Hijacker")
}
return hj.Hijack()
}