diff options
Diffstat (limited to 'logging/middleware.go')
-rw-r--r-- | logging/middleware.go | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/logging/middleware.go b/logging/middleware.go new file mode 100644 index 0000000..cbb345a --- /dev/null +++ b/logging/middleware.go @@ -0,0 +1,107 @@ +package logging + +import ( + "context" + "errors" + "io" + "time" + + "tildegit.org/tjp/gus" +) + +func LogRequests(logger Logger) gus.Middleware { + return func(inner gus.Handler) gus.Handler { + return func(ctx context.Context, request *gus.Request) *gus.Response { + start := time.Now() + + response := inner(ctx, request) + if response != nil { + body := loggedResponseBody{ + request: request, + response: response, + body: response.Body, + start: start, + logger: logger, + } + response.Body = &body + } + + return response + } + } +} + +type loggedResponseBody struct { + request *gus.Request + response *gus.Response + body io.Reader + + start time.Time + + written int + logger Logger +} + +func loggingBody(logger Logger, request *gus.Request, response *gus.Response) io.Reader { + body := &loggedResponseBody{ + request: request, + response: response, + body: response.Body, + start: time.Now(), + written: 0, + logger: logger, + } + + if _, ok := response.Body.(io.WriterTo); ok { + return loggedWriteToResponseBody{body} + } + + return body +} + +func (lr *loggedResponseBody) log() { + end := time.Now() + _ = lr.logger.Log( + "msg", "request", + "ts", end, + "dur", end.Sub(lr.start), + "url", lr.request.URL, + "status", lr.response.Status, + "bodylen", lr.written, + ) +} + +func (lr *loggedResponseBody) Read(b []byte) (int, error) { + if lr.body == nil { + return 0, io.EOF + } + + wr, err := lr.body.Read(b) + lr.written += wr + + if errors.Is(err, io.EOF) { + lr.log() + } + + return wr, err +} + +func (lr *loggedResponseBody) Close() error { + if cl, ok := lr.body.(io.Closer); ok { + return cl.Close() + } + return nil +} + +type loggedWriteToResponseBody struct { + *loggedResponseBody +} + +func (lwtr loggedWriteToResponseBody) WriteTo(dst io.Writer) (int64, error) { + n, err := lwtr.body.(io.WriterTo).WriteTo(dst) + if err == nil { + lwtr.written += int(n) + lwtr.log() + } + return n, err +} |