github.com/safing/portbase@v0.19.5/api/enriched-response.go (about) 1 package api 2 3 import ( 4 "bufio" 5 "errors" 6 "net" 7 "net/http" 8 9 "github.com/safing/portbase/log" 10 ) 11 12 // LoggingResponseWriter is a wrapper for http.ResponseWriter for better request logging. 13 type LoggingResponseWriter struct { 14 ResponseWriter http.ResponseWriter 15 Request *http.Request 16 Status int 17 } 18 19 // NewLoggingResponseWriter wraps a http.ResponseWriter. 20 func NewLoggingResponseWriter(w http.ResponseWriter, r *http.Request) *LoggingResponseWriter { 21 return &LoggingResponseWriter{ 22 ResponseWriter: w, 23 Request: r, 24 } 25 } 26 27 // Header wraps the original Header method. 28 func (lrw *LoggingResponseWriter) Header() http.Header { 29 return lrw.ResponseWriter.Header() 30 } 31 32 // Write wraps the original Write method. 33 func (lrw *LoggingResponseWriter) Write(b []byte) (int, error) { 34 return lrw.ResponseWriter.Write(b) 35 } 36 37 // WriteHeader wraps the original WriteHeader method to extract information. 38 func (lrw *LoggingResponseWriter) WriteHeader(code int) { 39 lrw.Status = code 40 lrw.ResponseWriter.WriteHeader(code) 41 } 42 43 // Hijack wraps the original Hijack method, if available. 44 func (lrw *LoggingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { 45 hijacker, ok := lrw.ResponseWriter.(http.Hijacker) 46 if ok { 47 c, b, err := hijacker.Hijack() 48 if err != nil { 49 return nil, nil, err 50 } 51 log.Tracer(lrw.Request.Context()).Infof("api request: %s HIJ %s", lrw.Request.RemoteAddr, lrw.Request.RequestURI) 52 return c, b, nil 53 } 54 return nil, nil, errors.New("response does not implement http.Hijacker") 55 } 56 57 // RequestLogger is a logging middleware. 58 func RequestLogger(next http.Handler) http.Handler { 59 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 60 log.Tracer(r.Context()).Tracef("api request: %s ___ %s", r.RemoteAddr, r.RequestURI) 61 lrw := NewLoggingResponseWriter(w, r) 62 next.ServeHTTP(lrw, r) 63 if lrw.Status != 0 { 64 // request may have been hijacked 65 log.Tracer(r.Context()).Infof("api request: %s %d %s", lrw.Request.RemoteAddr, lrw.Status, lrw.Request.RequestURI) 66 } 67 }) 68 }