8406: Treat EXIT_TEMPFAIL as EXIT_RETRY_UNLOCKED if we have previously gotten
[arvados.git] / services / keepstore / logging_router.go
1 package main
2
3 // LoggingRESTRouter
4 // LoggingResponseWriter
5
6 import (
7         "github.com/gorilla/mux"
8         "log"
9         "net/http"
10         "strings"
11         "time"
12 )
13
14 // LoggingResponseWriter has anonymous fields ResponseWriter and ResponseBody
15 type LoggingResponseWriter struct {
16         Status int
17         Length int
18         http.ResponseWriter
19         ResponseBody string
20         sentHdr      time.Time
21 }
22
23 // WriteHeader writes header to ResponseWriter
24 func (loggingWriter *LoggingResponseWriter) WriteHeader(code int) {
25         if loggingWriter.sentHdr == zeroTime {
26                 loggingWriter.sentHdr = time.Now()
27         }
28         loggingWriter.Status = code
29         loggingWriter.ResponseWriter.WriteHeader(code)
30 }
31
32 var zeroTime time.Time
33
34 func (loggingWriter *LoggingResponseWriter) Write(data []byte) (int, error) {
35         if loggingWriter.Length == 0 && len(data) > 0 && loggingWriter.sentHdr == zeroTime {
36                 loggingWriter.sentHdr = time.Now()
37         }
38         loggingWriter.Length += len(data)
39         if loggingWriter.Status >= 400 {
40                 loggingWriter.ResponseBody += string(data)
41         }
42         return loggingWriter.ResponseWriter.Write(data)
43 }
44
45 // LoggingRESTRouter is used to add logging capabilities to mux.Router
46 type LoggingRESTRouter struct {
47         router *mux.Router
48 }
49
50 // MakeLoggingRESTRouter initializes LoggingRESTRouter
51 func MakeLoggingRESTRouter() *LoggingRESTRouter {
52         router := MakeRESTRouter()
53         return (&LoggingRESTRouter{router})
54 }
55
56 func (loggingRouter *LoggingRESTRouter) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
57         t0 := time.Now()
58         loggingWriter := LoggingResponseWriter{http.StatusOK, 0, resp, "", zeroTime}
59         loggingRouter.router.ServeHTTP(&loggingWriter, req)
60         statusText := http.StatusText(loggingWriter.Status)
61         if loggingWriter.Status >= 400 {
62                 statusText = strings.Replace(loggingWriter.ResponseBody, "\n", "", -1)
63         }
64         now := time.Now()
65         tTotal := now.Sub(t0)
66         tLatency := loggingWriter.sentHdr.Sub(t0)
67         tResponse := now.Sub(loggingWriter.sentHdr)
68         log.Printf("[%s] %s %s %d %.6fs %.6fs %.6fs %d %d \"%s\"", req.RemoteAddr, req.Method, req.URL.Path[1:], req.ContentLength, tTotal.Seconds(), tLatency.Seconds(), tResponse.Seconds(), loggingWriter.Status, loggingWriter.Length, statusText)
69
70 }