package logging import ( "context" "errors" "fmt" "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 { response := inner(ctx, request) if response != nil { response.Body = loggingBody(logger, request, response) } return response } } } type loggedResponseBody struct { request *gus.Request response *gus.Response body io.Reader start time.Time written int logger Logger } 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) { fmt.Println("lwtrb.WriteTo()") n, err := lwtr.body.(io.WriterTo).WriteTo(dst) if err == nil { lwtr.written += int(n) lwtr.log() } return n, err } 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 }