github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/kit/httptransport/handlers/log_handler.go (about) 1 package handlers 2 3 import ( 4 "net/http" 5 "strconv" 6 7 "github.com/google/uuid" 8 "github.com/pkg/errors" 9 10 "github.com/machinefi/w3bstream/pkg/depends/kit/httptransport/httpx" 11 "github.com/machinefi/w3bstream/pkg/depends/kit/logr" 12 "github.com/machinefi/w3bstream/pkg/depends/kit/metax" 13 "github.com/machinefi/w3bstream/pkg/depends/x/misc/timer" 14 ) 15 16 func LogHandler() func(handler http.Handler) http.Handler { 17 return func(handler http.Handler) http.Handler { 18 return &loggerHandler{ 19 next: handler, 20 } 21 } 22 } 23 24 type loggerHandler struct { 25 next http.Handler 26 } 27 28 type LoggerResponseWriter struct { 29 rw http.ResponseWriter 30 written bool 31 statusCode int 32 err error 33 } 34 35 func (rw *LoggerResponseWriter) Header() http.Header { return rw.rw.Header() } 36 37 func (rw *LoggerResponseWriter) WriteErr(err error) { rw.err = err } 38 39 func (rw *LoggerResponseWriter) WriteHeader(sc int) { 40 if rw.written { 41 return 42 } 43 rw.rw.WriteHeader(sc) 44 rw.statusCode = sc 45 rw.written = true 46 } 47 48 func (rw *LoggerResponseWriter) Write(data []byte) (int, error) { 49 if rw.err != nil && rw.statusCode >= http.StatusBadRequest { 50 rw.err = errors.New(string(data)) 51 } 52 return rw.rw.Write(data) 53 } 54 55 func (h *loggerHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { 56 cost := timer.Start() 57 reqID := req.Header.Get(httpx.HeaderRequestID) 58 if reqID == "" { 59 reqID = uuid.New().String() 60 } 61 62 var ( 63 w = &LoggerResponseWriter{rw: rw} 64 l = logr.FromContext(req.Context()) 65 ) 66 67 defer func() { 68 header := req.Header 69 duration := strconv.FormatInt(cost().Microseconds(), 10) + "μs" 70 fields := []interface{}{ 71 "@cst", duration, 72 "@rmt", httpx.ClientIP(req), 73 "@mtd", req.Method[0:3], 74 "@url", req.URL.String(), 75 "@agent", header.Get(httpx.HeaderUserAgent), 76 "@status", w.statusCode, 77 } 78 if w.err != nil { 79 if w.statusCode >= http.StatusInternalServerError { 80 l.WithValues(fields).Error(w.err) 81 } else { 82 l.WithValues(fields).Warn(w.err) 83 } 84 } else { 85 l.WithValues(fields).Info("") 86 } 87 }() 88 89 h.next.ServeHTTP( 90 w, 91 req.WithContext( 92 metax.ContextWithMeta(req.Context(), metax.ParseMeta(reqID)), 93 ), 94 ) 95 }