mirror of
				https://github.com/datarhei/core.git
				synced 2025-10-31 11:26:52 +08:00 
			
		
		
		
	Log HTTP request and response body sizes
This commit is contained in:
		| @@ -1,65 +0,0 @@ | |||||||
| // Package bodysize is an echo middleware that fixes the final number of body bytes sent on the wire |  | ||||||
| package bodysize |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
|  |  | ||||||
| 	"github.com/labstack/echo/v4" |  | ||||||
| 	"github.com/labstack/echo/v4/middleware" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type Config struct { |  | ||||||
| 	Skipper middleware.Skipper |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var DefaultConfig = Config{ |  | ||||||
| 	Skipper: middleware.DefaultSkipper, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func New() echo.MiddlewareFunc { |  | ||||||
| 	return NewWithConfig(DefaultConfig) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // New return a new bodysize middleware handler |  | ||||||
| func NewWithConfig(config Config) echo.MiddlewareFunc { |  | ||||||
| 	if config.Skipper == nil { |  | ||||||
| 		config.Skipper = DefaultConfig.Skipper |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return func(next echo.HandlerFunc) echo.HandlerFunc { |  | ||||||
| 		return func(c echo.Context) error { |  | ||||||
| 			if config.Skipper(c) { |  | ||||||
| 				return next(c) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			res := c.Response() |  | ||||||
|  |  | ||||||
| 			writer := res.Writer |  | ||||||
| 			w := &fakeWriter{ |  | ||||||
| 				ResponseWriter: res.Writer, |  | ||||||
| 			} |  | ||||||
| 			res.Writer = w |  | ||||||
|  |  | ||||||
| 			defer func() { |  | ||||||
| 				res.Writer = writer |  | ||||||
| 				res.Size = w.size |  | ||||||
| 			}() |  | ||||||
|  |  | ||||||
| 			return next(c) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type fakeWriter struct { |  | ||||||
| 	http.ResponseWriter |  | ||||||
|  |  | ||||||
| 	size int64 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (w *fakeWriter) Write(body []byte) (int, error) { |  | ||||||
| 	n, err := w.ResponseWriter.Write(body) |  | ||||||
|  |  | ||||||
| 	w.size += int64(n) |  | ||||||
|  |  | ||||||
| 	return n, err |  | ||||||
| } |  | ||||||
| @@ -2,6 +2,7 @@ | |||||||
| package log | package log | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"io" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| @@ -45,40 +46,92 @@ func NewWithConfig(config Config) echo.MiddlewareFunc { | |||||||
| 			start := time.Now() | 			start := time.Now() | ||||||
|  |  | ||||||
| 			req := c.Request() | 			req := c.Request() | ||||||
|  |  | ||||||
|  | 			var reader io.ReadCloser | ||||||
|  | 			r := &sizeReadCloser{} | ||||||
|  |  | ||||||
|  | 			if req.Body != nil { | ||||||
|  | 				reader = req.Body | ||||||
|  | 				r.ReadCloser = req.Body | ||||||
|  | 				req.Body = r | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			res := c.Response() | 			res := c.Response() | ||||||
|  |  | ||||||
|  | 			writer := res.Writer | ||||||
|  | 			w := &sizeWriter{ | ||||||
|  | 				ResponseWriter: res.Writer, | ||||||
|  | 			} | ||||||
|  | 			res.Writer = w | ||||||
|  |  | ||||||
| 			path := req.URL.Path | 			path := req.URL.Path | ||||||
| 			raw := req.URL.RawQuery | 			raw := req.URL.RawQuery | ||||||
|  |  | ||||||
| 			if err := next(c); err != nil { | 			defer func() { | ||||||
| 				c.Error(err) | 				res.Writer = writer | ||||||
| 			} | 				req.Body = reader | ||||||
|  |  | ||||||
| 			latency := time.Since(start) | 				latency := time.Since(start) | ||||||
|  |  | ||||||
| 			if raw != "" { | 				if raw != "" { | ||||||
| 				path = path + "?" + raw | 					path = path + "?" + raw | ||||||
| 			} | 				} | ||||||
|  |  | ||||||
| 			logger := config.Logger.WithFields(log.Fields{ | 				logger := config.Logger.WithFields(log.Fields{ | ||||||
| 				"client":      c.RealIP(), | 					"client":        c.RealIP(), | ||||||
| 				"method":      req.Method, | 					"method":        req.Method, | ||||||
| 				"path":        path, | 					"path":          path, | ||||||
| 				"proto":       req.Proto, | 					"proto":         req.Proto, | ||||||
| 				"status":      res.Status, | 					"status":        res.Status, | ||||||
| 				"status_text": http.StatusText(res.Status), | 					"status_text":   http.StatusText(res.Status), | ||||||
| 				"size_bytes":  res.Size, | 					"tx_size_bytes": w.size, | ||||||
| 				"latency_ms":  latency.Milliseconds(), | 					"rx_size_bytes": r.size, | ||||||
| 				"user_agent":  req.Header.Get("User-Agent"), | 					"latency_ms":    latency.Milliseconds(), | ||||||
| 			}) | 					"user_agent":    req.Header.Get("User-Agent"), | ||||||
|  | 				}) | ||||||
|  |  | ||||||
| 			if res.Status >= 400 { | 				if res.Status >= 400 { | ||||||
| 				logger.Warn().Log("") | 					logger.Warn().Log("") | ||||||
| 			} | 				} | ||||||
|  |  | ||||||
| 			logger.Debug().Log("") | 				logger.Debug().Log("") | ||||||
|  | 			}() | ||||||
|  |  | ||||||
| 			return nil | 			return next(c) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type sizeWriter struct { | ||||||
|  | 	http.ResponseWriter | ||||||
|  |  | ||||||
|  | 	size int64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *sizeWriter) Write(body []byte) (int, error) { | ||||||
|  | 	n, err := w.ResponseWriter.Write(body) | ||||||
|  |  | ||||||
|  | 	w.size += int64(n) | ||||||
|  |  | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type sizeReadCloser struct { | ||||||
|  | 	io.ReadCloser | ||||||
|  |  | ||||||
|  | 	size int64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *sizeReadCloser) Read(p []byte) (int, error) { | ||||||
|  | 	n, err := r.ReadCloser.Read(p) | ||||||
|  |  | ||||||
|  | 	r.size += int64(n) | ||||||
|  |  | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *sizeReadCloser) Close() error { | ||||||
|  | 	err := r.ReadCloser.Close() | ||||||
|  |  | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|   | |||||||
| @@ -51,7 +51,6 @@ import ( | |||||||
| 	"github.com/datarhei/core/v16/session" | 	"github.com/datarhei/core/v16/session" | ||||||
| 	"github.com/datarhei/core/v16/srt" | 	"github.com/datarhei/core/v16/srt" | ||||||
|  |  | ||||||
| 	mwbodysize "github.com/datarhei/core/v16/http/middleware/bodysize" |  | ||||||
| 	mwcache "github.com/datarhei/core/v16/http/middleware/cache" | 	mwcache "github.com/datarhei/core/v16/http/middleware/cache" | ||||||
| 	mwcors "github.com/datarhei/core/v16/http/middleware/cors" | 	mwcors "github.com/datarhei/core/v16/http/middleware/cors" | ||||||
| 	mwgzip "github.com/datarhei/core/v16/http/middleware/gzip" | 	mwgzip "github.com/datarhei/core/v16/http/middleware/gzip" | ||||||
| @@ -341,7 +340,6 @@ func NewServer(config Config) (Server, error) { | |||||||
| 			return nil | 			return nil | ||||||
| 		}, | 		}, | ||||||
| 	})) | 	})) | ||||||
| 	s.router.Use(mwbodysize.New()) |  | ||||||
| 	s.router.Use(mwsession.NewHTTPWithConfig(mwsession.HTTPConfig{ | 	s.router.Use(mwsession.NewHTTPWithConfig(mwsession.HTTPConfig{ | ||||||
| 		Collector: config.Sessions.Collector("http"), | 		Collector: config.Sessions.Collector("http"), | ||||||
| 	})) | 	})) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Ingo Oppermann
					Ingo Oppermann