1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
12 "git.curoverse.com/arvados.git/sdk/go/stats"
13 "github.com/Sirupsen/logrus"
16 type contextKey struct {
20 var requestTimeContextKey = contextKey{"requestTime"}
22 var Logger logrus.FieldLogger = logrus.StandardLogger()
24 // LogRequests wraps an http.Handler, logging each request and
25 // response via logrus.
26 func LogRequests(h http.Handler) http.Handler {
27 return http.HandlerFunc(func(wrapped http.ResponseWriter, req *http.Request) {
28 w := &responseTimer{ResponseWriter: WrapResponseWriter(wrapped)}
29 req = req.WithContext(context.WithValue(req.Context(), &requestTimeContextKey, time.Now()))
30 lgr := Logger.WithFields(logrus.Fields{
31 "RequestID": req.Header.Get("X-Request-Id"),
32 "remoteAddr": req.RemoteAddr,
33 "reqForwardedFor": req.Header.Get("X-Forwarded-For"),
34 "reqMethod": req.Method,
35 "reqPath": req.URL.Path[1:],
36 "reqBytes": req.ContentLength,
38 logRequest(w, req, lgr)
39 defer logResponse(w, req, lgr)
44 func logRequest(w *responseTimer, req *http.Request, lgr *logrus.Entry) {
48 func logResponse(w *responseTimer, req *http.Request, lgr *logrus.Entry) {
49 if tStart, ok := req.Context().Value(&requestTimeContextKey).(time.Time); ok {
51 lgr = lgr.WithFields(logrus.Fields{
52 "timeTotal": stats.Duration(tDone.Sub(tStart)),
53 "timeToStatus": stats.Duration(w.writeTime.Sub(tStart)),
54 "timeWriteBody": stats.Duration(tDone.Sub(w.writeTime)),
57 respCode := w.WroteStatus()
59 respCode = http.StatusOK
61 lgr.WithFields(logrus.Fields{
62 "respStatusCode": respCode,
63 "respStatus": http.StatusText(respCode),
64 "respBytes": w.WroteBodyBytes(),
68 type responseTimer struct {
74 func (rt *responseTimer) CloseNotify() <-chan bool {
75 if cn, ok := rt.ResponseWriter.(http.CloseNotifier); ok {
76 return cn.CloseNotify()
81 func (rt *responseTimer) WriteHeader(code int) {
84 rt.writeTime = time.Now()
86 rt.ResponseWriter.WriteHeader(code)
89 func (rt *responseTimer) Write(p []byte) (int, error) {
92 rt.writeTime = time.Now()
94 return rt.ResponseWriter.Write(p)