| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- package requestlog
- import (
- "io"
- "io/ioutil"
- "net/http"
- "time"
- lr "github.com/porter-dev/porter/internal/logger"
- )
- // Handler wraps an HTTP handler so that a log entry can be generated for
- // request/response stats
- type Handler struct {
- handler http.Handler
- logger *lr.Logger
- }
- // NewHandler creates a new Handler instance based on an http.HandlerFunc
- func NewHandler(h http.HandlerFunc, l *lr.Logger) *Handler {
- return &Handler{
- handler: h,
- logger: l,
- }
- }
- // ServeHTTP calls its underlying handler's ServeHTTP method, then calls
- // Log after the handler returns.
- //
- // ServeHTTP will always consume the request body up to the first error,
- // even if the underlying handler does not.
- func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- start := time.Now()
- le := &logEntry{
- ReceivedTime: start,
- RequestMethod: r.Method,
- RequestURL: r.URL.String(),
- RequestHeaderSize: headerSize(r.Header),
- UserAgent: r.UserAgent(),
- Referer: r.Referer(),
- Proto: r.Proto,
- }
- r2 := new(http.Request)
- *r2 = *r
- rcc := &readCounterCloser{r: r.Body}
- r2.Body = rcc
- w2 := &responseStats{w: w}
- h.handler.ServeHTTP(w2, r2)
- le.Latency = time.Since(start)
- if rcc.err == nil && rcc.r != nil {
- // If the handler hasn't encountered an error in the Body (like EOF),
- // then consume the rest of the Body to provide an accurate rcc.n.
- io.Copy(ioutil.Discard, rcc)
- }
- le.RequestBodySize = rcc.n
- le.Status = w2.code
- if le.Status == 0 {
- le.Status = http.StatusOK
- }
- le.ResponseHeaderSize, le.ResponseBodySize = w2.size()
- h.logger.Info().
- Time("received_time", le.ReceivedTime).
- Str("method", le.RequestMethod).
- Str("url", le.RequestURL).
- Int64("header_size", le.RequestHeaderSize).
- Int64("body_size", le.RequestBodySize).
- Str("agent", le.UserAgent).
- Str("referer", le.Referer).
- Str("proto", le.Proto).
- Int("status", le.Status).
- Int64("resp_header_size", le.ResponseHeaderSize).
- Int64("resp_body_size", le.ResponseBodySize).
- Dur("latency", le.Latency).
- Msg("")
- }
|