github.com/gogf/gf/v2@v2.7.4/os/glog/glog_logger_handler.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package glog 8 9 import ( 10 "bytes" 11 "context" 12 "time" 13 14 "github.com/gogf/gf/v2/util/gconv" 15 ) 16 17 // Handler is function handler for custom logging content outputs. 18 type Handler func(ctx context.Context, in *HandlerInput) 19 20 // HandlerInput is the input parameter struct for logging Handler. 21 // 22 // The logging content is consisted in: 23 // TimeFormat [LevelFormat] {TraceId} {CtxStr} Prefix CallerFunc CallerPath Content Values Stack 24 // 25 // The header in the logging content is: 26 // TimeFormat [LevelFormat] {TraceId} {CtxStr} Prefix CallerFunc CallerPath 27 type HandlerInput struct { 28 internalHandlerInfo 29 30 // Current Logger object. 31 Logger *Logger 32 33 // Buffer for logging content outputs. 34 Buffer *bytes.Buffer 35 36 // (ReadOnly) Logging time, which is the time that logging triggers. 37 Time time.Time 38 39 // Formatted time string for output, like "2016-01-09 12:00:00". 40 TimeFormat string 41 42 // (ReadOnly) Using color constant value, like COLOR_RED, COLOR_BLUE, etc. 43 // Example: 34 44 Color int 45 46 // (ReadOnly) Using level, like LEVEL_INFO, LEVEL_ERRO, etc. 47 // Example: 256 48 Level int 49 50 // Formatted level string for output, like "DEBU", "ERRO", etc. 51 // Example: ERRO 52 LevelFormat string 53 54 // The source function name that calls logging, only available if F_CALLER_FN set. 55 CallerFunc string 56 57 // The source file path and its line number that calls logging, 58 // only available if F_FILE_SHORT or F_FILE_LONG set. 59 CallerPath string 60 61 // The retrieved context value string from context, only available if Config.CtxKeys configured. 62 // It's empty if no Config.CtxKeys configured. 63 CtxStr string 64 65 // Trace id, only available if OpenTelemetry is enabled, or else it's an empty string. 66 TraceId string 67 68 // Custom prefix string in logging content header part. 69 // Note that, it takes no effect if HeaderPrint is disabled. 70 Prefix string 71 72 // Custom logging content for logging. 73 Content string 74 75 // The passed un-formatted values array to logger. 76 Values []any 77 78 // Stack string produced by logger, only available if Config.StStatus configured. 79 // Note that there are usually multiple lines in stack content. 80 Stack string 81 82 // IsAsync marks it is in asynchronous logging. 83 IsAsync bool 84 } 85 86 type internalHandlerInfo struct { 87 index int // Middleware handling index for internal usage. 88 handlers []Handler // Handler array calling bu index. 89 } 90 91 // defaultHandler is the default handler for package. 92 var defaultHandler Handler 93 94 // doFinalPrint is a handler for logging content printing. 95 // This handler outputs logging content to file/stdout/write if any of them configured. 96 func doFinalPrint(ctx context.Context, in *HandlerInput) { 97 buffer := in.Logger.doFinalPrint(ctx, in) 98 if in.Buffer.Len() == 0 { 99 in.Buffer = buffer 100 } 101 } 102 103 // SetDefaultHandler sets default handler for package. 104 func SetDefaultHandler(handler Handler) { 105 defaultHandler = handler 106 } 107 108 // GetDefaultHandler returns the default handler of package. 109 func GetDefaultHandler() Handler { 110 return defaultHandler 111 } 112 113 // Next calls the next logging handler in middleware way. 114 func (in *HandlerInput) Next(ctx context.Context) { 115 in.index++ 116 if in.index < len(in.handlers) { 117 in.handlers[in.index](ctx, in) 118 } 119 } 120 121 // String returns the logging content formatted by default logging handler. 122 func (in *HandlerInput) String(withColor ...bool) string { 123 formatWithColor := false 124 if len(withColor) > 0 { 125 formatWithColor = withColor[0] 126 } 127 return in.getDefaultBuffer(formatWithColor).String() 128 } 129 130 // ValuesContent converts and returns values as string content. 131 func (in *HandlerInput) ValuesContent() string { 132 var ( 133 buffer = bytes.NewBuffer(nil) 134 valueContent string 135 ) 136 for _, v := range in.Values { 137 valueContent = gconv.String(v) 138 if len(valueContent) == 0 { 139 continue 140 } 141 if buffer.Len() == 0 { 142 buffer.WriteString(valueContent) 143 continue 144 } 145 if buffer.Bytes()[buffer.Len()-1] != '\n' { 146 buffer.WriteString(" " + valueContent) 147 continue 148 } 149 // Remove one blank line(\n\n). 150 if valueContent[0] == '\n' { 151 valueContent = valueContent[1:] 152 } 153 buffer.WriteString(valueContent) 154 } 155 return buffer.String() 156 } 157 158 func (in *HandlerInput) getDefaultBuffer(withColor bool) *bytes.Buffer { 159 buffer := bytes.NewBuffer(nil) 160 if in.Logger.config.HeaderPrint { 161 if in.TimeFormat != "" { 162 buffer.WriteString(in.TimeFormat) 163 } 164 if in.Logger.config.LevelPrint && in.LevelFormat != "" { 165 var levelStr = "[" + in.LevelFormat + "]" 166 if withColor { 167 in.addStringToBuffer(buffer, in.Logger.getColoredStr( 168 in.Logger.getColorByLevel(in.Level), levelStr, 169 )) 170 } else { 171 in.addStringToBuffer(buffer, levelStr) 172 } 173 } 174 } 175 if in.TraceId != "" { 176 in.addStringToBuffer(buffer, "{"+in.TraceId+"}") 177 } 178 if in.CtxStr != "" { 179 in.addStringToBuffer(buffer, "{"+in.CtxStr+"}") 180 } 181 if in.Logger.config.HeaderPrint { 182 if in.Prefix != "" { 183 in.addStringToBuffer(buffer, in.Prefix) 184 } 185 if in.CallerFunc != "" { 186 in.addStringToBuffer(buffer, in.CallerFunc) 187 } 188 if in.CallerPath != "" { 189 in.addStringToBuffer(buffer, in.CallerPath) 190 } 191 } 192 193 if in.Content != "" { 194 in.addStringToBuffer(buffer, in.Content) 195 } 196 197 if len(in.Values) > 0 { 198 in.addStringToBuffer(buffer, in.ValuesContent()) 199 } 200 201 if in.Stack != "" { 202 in.addStringToBuffer(buffer, "\nStack:\n"+in.Stack) 203 } 204 // avoid a single space at the end of a line. 205 buffer.WriteString("\n") 206 return buffer 207 } 208 209 func (in *HandlerInput) getRealBuffer(withColor bool) *bytes.Buffer { 210 if in.Buffer.Len() > 0 { 211 return in.Buffer 212 } 213 return in.getDefaultBuffer(withColor) 214 } 215 216 func (in *HandlerInput) addStringToBuffer(buffer *bytes.Buffer, strings ...string) { 217 for _, s := range strings { 218 if buffer.Len() > 0 { 219 buffer.WriteByte(' ') 220 } 221 buffer.WriteString(s) 222 } 223 }