summaryrefslogtreecommitdiff
path: root/logging/middleware.go
diff options
context:
space:
mode:
Diffstat (limited to 'logging/middleware.go')
-rw-r--r--logging/middleware.go107
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
+}