github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/go-chi/chi/middleware/logger.go (about) 1 package middleware 2 3 import ( 4 "bytes" 5 "context" 6 "log" 7 "os" 8 "time" 9 10 "github.com/hellobchain/newcryptosm/http" 11 ) 12 13 var ( 14 // LogEntryCtxKey is the context.Context key to store the request log entry. 15 LogEntryCtxKey = &contextKey{"LogEntry"} 16 17 // DefaultLogger is called by the Logger middleware handler to log each request. 18 // Its made a package-level variable so that it can be reconfigured for custom 19 // logging configurations. 20 DefaultLogger = RequestLogger(&DefaultLogFormatter{Logger: log.New(os.Stdout, "", log.LstdFlags), NoColor: false}) 21 ) 22 23 // Logger is a middleware that logs the start and end of each request, along 24 // with some useful data about what was requested, what the response status was, 25 // and how long it took to return. When standard output is a TTY, Logger will 26 // print in color, otherwise it will print in black and white. Logger prints a 27 // request ID if one is provided. 28 // 29 // Alternatively, look at https://github.com/pressly/lg and the `lg.RequestLogger` 30 // middleware pkg. 31 func Logger(next http.Handler) http.Handler { 32 return DefaultLogger(next) 33 } 34 35 // RequestLogger returns a logger handler using a custom LogFormatter. 36 func RequestLogger(f LogFormatter) func(next http.Handler) http.Handler { 37 return func(next http.Handler) http.Handler { 38 fn := func(w http.ResponseWriter, r *http.Request) { 39 entry := f.NewLogEntry(r) 40 ww := NewWrapResponseWriter(w, r.ProtoMajor) 41 42 t1 := time.Now() 43 defer func() { 44 entry.Write(ww.Status(), ww.BytesWritten(), time.Since(t1)) 45 }() 46 47 next.ServeHTTP(ww, WithLogEntry(r, entry)) 48 } 49 return http.HandlerFunc(fn) 50 } 51 } 52 53 // LogFormatter initiates the beginning of a new LogEntry per request. 54 // See DefaultLogFormatter for an example implementation. 55 type LogFormatter interface { 56 NewLogEntry(r *http.Request) LogEntry 57 } 58 59 // LogEntry records the final log when a request completes. 60 // See defaultLogEntry for an example implementation. 61 type LogEntry interface { 62 Write(status, bytes int, elapsed time.Duration) 63 Panic(v interface{}, stack []byte) 64 } 65 66 // GetLogEntry returns the in-context LogEntry for a request. 67 func GetLogEntry(r *http.Request) LogEntry { 68 entry, _ := r.Context().Value(LogEntryCtxKey).(LogEntry) 69 return entry 70 } 71 72 // WithLogEntry sets the in-context LogEntry for a request. 73 func WithLogEntry(r *http.Request, entry LogEntry) *http.Request { 74 r = r.WithContext(context.WithValue(r.Context(), LogEntryCtxKey, entry)) 75 return r 76 } 77 78 // LoggerInterface accepts printing to stdlib logger or compatible logger. 79 type LoggerInterface interface { 80 Print(v ...interface{}) 81 } 82 83 // DefaultLogFormatter is a simple logger that implements a LogFormatter. 84 type DefaultLogFormatter struct { 85 Logger LoggerInterface 86 NoColor bool 87 } 88 89 // NewLogEntry creates a new LogEntry for the request. 90 func (l *DefaultLogFormatter) NewLogEntry(r *http.Request) LogEntry { 91 useColor := !l.NoColor 92 entry := &defaultLogEntry{ 93 DefaultLogFormatter: l, 94 request: r, 95 buf: &bytes.Buffer{}, 96 useColor: useColor, 97 } 98 99 reqID := GetReqID(r.Context()) 100 if reqID != "" { 101 cW(entry.buf, useColor, nYellow, "[%s] ", reqID) 102 } 103 cW(entry.buf, useColor, nCyan, "\"") 104 cW(entry.buf, useColor, bMagenta, "%s ", r.Method) 105 106 scheme := "http" 107 if r.TLS != nil { 108 scheme = "https" 109 } 110 cW(entry.buf, useColor, nCyan, "%s://%s%s %s\" ", scheme, r.Host, r.RequestURI, r.Proto) 111 112 entry.buf.WriteString("from ") 113 entry.buf.WriteString(r.RemoteAddr) 114 entry.buf.WriteString(" - ") 115 116 return entry 117 } 118 119 type defaultLogEntry struct { 120 *DefaultLogFormatter 121 request *http.Request 122 buf *bytes.Buffer 123 useColor bool 124 } 125 126 func (l *defaultLogEntry) Write(status, bytes int, elapsed time.Duration) { 127 switch { 128 case status < 200: 129 cW(l.buf, l.useColor, bBlue, "%03d", status) 130 case status < 300: 131 cW(l.buf, l.useColor, bGreen, "%03d", status) 132 case status < 400: 133 cW(l.buf, l.useColor, bCyan, "%03d", status) 134 case status < 500: 135 cW(l.buf, l.useColor, bYellow, "%03d", status) 136 default: 137 cW(l.buf, l.useColor, bRed, "%03d", status) 138 } 139 140 cW(l.buf, l.useColor, bBlue, " %dB", bytes) 141 142 l.buf.WriteString(" in ") 143 if elapsed < 500*time.Millisecond { 144 cW(l.buf, l.useColor, nGreen, "%s", elapsed) 145 } else if elapsed < 5*time.Second { 146 cW(l.buf, l.useColor, nYellow, "%s", elapsed) 147 } else { 148 cW(l.buf, l.useColor, nRed, "%s", elapsed) 149 } 150 151 l.Logger.Print(l.buf.String()) 152 } 153 154 func (l *defaultLogEntry) Panic(v interface{}, stack []byte) { 155 panicEntry := l.NewLogEntry(l.request).(*defaultLogEntry) 156 cW(panicEntry.buf, l.useColor, bRed, "panic: %+v", v) 157 l.Logger.Print(panicEntry.buf.String()) 158 l.Logger.Print(string(stack)) 159 }