github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gin/logger.go (about) 1 // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 2 // Use of this source code is governed by a MIT style 3 // license that can be found in the LICENSE file. 4 5 package gin 6 7 import ( 8 "fmt" 9 "github.com/hellobchain/newcryptosm/http" 10 "io" 11 "os" 12 "time" 13 14 "github.com/mattn/go-isatty" 15 ) 16 17 type consoleColorModeValue int 18 19 const ( 20 autoColor consoleColorModeValue = iota 21 disableColor 22 forceColor 23 ) 24 25 const ( 26 green = "\033[97;42m" 27 white = "\033[90;47m" 28 yellow = "\033[90;43m" 29 red = "\033[97;41m" 30 blue = "\033[97;44m" 31 magenta = "\033[97;45m" 32 cyan = "\033[97;46m" 33 reset = "\033[0m" 34 ) 35 36 var consoleColorMode = autoColor 37 38 // LoggerConfig defines the config for Logger middleware. 39 type LoggerConfig struct { 40 // Optional. Default value is gin.defaultLogFormatter 41 Formatter LogFormatter 42 43 // Output is a writer where logs are written. 44 // Optional. Default value is gin.DefaultWriter. 45 Output io.Writer 46 47 // SkipPaths is a url path array which logs are not written. 48 // Optional. 49 SkipPaths []string 50 } 51 52 // LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter 53 type LogFormatter func(params LogFormatterParams) string 54 55 // LogFormatterParams is the structure any formatter will be handed when time to log comes 56 type LogFormatterParams struct { 57 Request *http.Request 58 59 // TimeStamp shows the time after the server returns a response. 60 TimeStamp time.Time 61 // StatusCode is HTTP response code. 62 StatusCode int 63 // Latency is how much time the server cost to process a certain request. 64 Latency time.Duration 65 // ClientIP equals Context's ClientIP method. 66 ClientIP string 67 // Method is the HTTP method given to the request. 68 Method string 69 // Path is a path the client requests. 70 Path string 71 // ErrorMessage is set if error has occurred in processing the request. 72 ErrorMessage string 73 // isTerm shows whether does gin's output descriptor refers to a terminal. 74 isTerm bool 75 // BodySize is the size of the Response Body 76 BodySize int 77 // Keys are the keys set on the request's context. 78 Keys map[string]interface{} 79 } 80 81 // StatusCodeColor is the ANSI color for appropriately logging http status code to a terminal. 82 func (p *LogFormatterParams) StatusCodeColor() string { 83 code := p.StatusCode 84 85 switch { 86 case code >= http.StatusOK && code < http.StatusMultipleChoices: 87 return green 88 case code >= http.StatusMultipleChoices && code < http.StatusBadRequest: 89 return white 90 case code >= http.StatusBadRequest && code < http.StatusInternalServerError: 91 return yellow 92 default: 93 return red 94 } 95 } 96 97 // MethodColor is the ANSI color for appropriately logging http method to a terminal. 98 func (p *LogFormatterParams) MethodColor() string { 99 method := p.Method 100 101 switch method { 102 case http.MethodGet: 103 return blue 104 case http.MethodPost: 105 return cyan 106 case http.MethodPut: 107 return yellow 108 case http.MethodDelete: 109 return red 110 case http.MethodPatch: 111 return green 112 case http.MethodHead: 113 return magenta 114 case http.MethodOptions: 115 return white 116 default: 117 return reset 118 } 119 } 120 121 // ResetColor resets all escape attributes. 122 func (p *LogFormatterParams) ResetColor() string { 123 return reset 124 } 125 126 // IsOutputColor indicates whether can colors be outputted to the log. 127 func (p *LogFormatterParams) IsOutputColor() bool { 128 return consoleColorMode == forceColor || (consoleColorMode == autoColor && p.isTerm) 129 } 130 131 // defaultLogFormatter is the default log format function Logger middleware uses. 132 var defaultLogFormatter = func(param LogFormatterParams) string { 133 var statusColor, methodColor, resetColor string 134 if param.IsOutputColor() { 135 statusColor = param.StatusCodeColor() 136 methodColor = param.MethodColor() 137 resetColor = param.ResetColor() 138 } 139 140 if param.Latency > time.Minute { 141 // Truncate in a golang < 1.8 safe way 142 param.Latency = param.Latency - param.Latency%time.Second 143 } 144 return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n%s", 145 param.TimeStamp.Format("2006/01/02 - 15:04:05"), 146 statusColor, param.StatusCode, resetColor, 147 param.Latency, 148 param.ClientIP, 149 methodColor, param.Method, resetColor, 150 param.Path, 151 param.ErrorMessage, 152 ) 153 } 154 155 // DisableConsoleColor disables color output in the console. 156 func DisableConsoleColor() { 157 consoleColorMode = disableColor 158 } 159 160 // ForceConsoleColor force color output in the console. 161 func ForceConsoleColor() { 162 consoleColorMode = forceColor 163 } 164 165 // ErrorLogger returns a handlerfunc for any error type. 166 func ErrorLogger() HandlerFunc { 167 return ErrorLoggerT(ErrorTypeAny) 168 } 169 170 // ErrorLoggerT returns a handlerfunc for a given error type. 171 func ErrorLoggerT(typ ErrorType) HandlerFunc { 172 return func(c *Context) { 173 c.Next() 174 errors := c.Errors.ByType(typ) 175 if len(errors) > 0 { 176 c.JSON(-1, errors) 177 } 178 } 179 } 180 181 // Logger instances a Logger middleware that will write the logs to gin.DefaultWriter. 182 // By default gin.DefaultWriter = os.Stdout. 183 func Logger() HandlerFunc { 184 return LoggerWithConfig(LoggerConfig{}) 185 } 186 187 // LoggerWithFormatter instance a Logger middleware with the specified log format function. 188 func LoggerWithFormatter(f LogFormatter) HandlerFunc { 189 return LoggerWithConfig(LoggerConfig{ 190 Formatter: f, 191 }) 192 } 193 194 // LoggerWithWriter instance a Logger middleware with the specified writer buffer. 195 // Example: os.Stdout, a file opened in write mode, a socket... 196 func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc { 197 return LoggerWithConfig(LoggerConfig{ 198 Output: out, 199 SkipPaths: notlogged, 200 }) 201 } 202 203 // LoggerWithConfig instance a Logger middleware with config. 204 func LoggerWithConfig(conf LoggerConfig) HandlerFunc { 205 formatter := conf.Formatter 206 if formatter == nil { 207 formatter = defaultLogFormatter 208 } 209 210 out := conf.Output 211 if out == nil { 212 out = DefaultWriter 213 } 214 215 notlogged := conf.SkipPaths 216 217 isTerm := true 218 219 if w, ok := out.(*os.File); !ok || os.Getenv("TERM") == "dumb" || 220 (!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd())) { 221 isTerm = false 222 } 223 224 var skip map[string]struct{} 225 226 if length := len(notlogged); length > 0 { 227 skip = make(map[string]struct{}, length) 228 229 for _, path := range notlogged { 230 skip[path] = struct{}{} 231 } 232 } 233 234 return func(c *Context) { 235 // Start timer 236 start := time.Now() 237 path := c.Request.URL.Path 238 raw := c.Request.URL.RawQuery 239 240 // Process request 241 c.Next() 242 243 // Log only when path is not being skipped 244 if _, ok := skip[path]; !ok { 245 param := LogFormatterParams{ 246 Request: c.Request, 247 isTerm: isTerm, 248 Keys: c.Keys, 249 } 250 251 // Stop timer 252 param.TimeStamp = time.Now() 253 param.Latency = param.TimeStamp.Sub(start) 254 255 param.ClientIP = c.ClientIP() 256 param.Method = c.Request.Method 257 param.StatusCode = c.Writer.Status() 258 param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String() 259 260 param.BodySize = c.Writer.Size() 261 262 if raw != "" { 263 path = path + "?" + raw 264 } 265 266 param.Path = path 267 268 fmt.Fprint(out, formatter(param)) 269 } 270 } 271 }