code.gitea.io/gitea@v1.22.3/modules/log/event_format.go (about) 1 // Copyright 2023 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package log 5 6 import ( 7 "bytes" 8 "fmt" 9 "strings" 10 "time" 11 ) 12 13 type Event struct { 14 Time time.Time 15 16 GoroutinePid string 17 Caller string 18 Filename string 19 Line int 20 21 Level Level 22 23 MsgSimpleText string 24 25 msgFormat string // the format and args is only valid in the caller's goroutine 26 msgArgs []any // they are discarded before the event is passed to the writer's channel 27 28 Stacktrace string 29 } 30 31 type EventFormatted struct { 32 Origin *Event 33 Msg any // the message formatted by the writer's formatter, the writer knows its type 34 } 35 36 type EventFormatter func(mode *WriterMode, event *Event, msgFormat string, msgArgs ...any) []byte 37 38 type logStringFormatter struct { 39 v LogStringer 40 } 41 42 var _ fmt.Formatter = logStringFormatter{} 43 44 func (l logStringFormatter) Format(f fmt.State, verb rune) { 45 if f.Flag('#') && verb == 'v' { 46 _, _ = fmt.Fprintf(f, "%#v", l.v) 47 return 48 } 49 _, _ = f.Write([]byte(l.v.LogString())) 50 } 51 52 // Copy of cheap integer to fixed-width decimal to ascii from logger. 53 // TODO: legacy bugs: doesn't support negative number, overflow if wid it too large. 54 func itoa(buf []byte, i, wid int) []byte { 55 var s [20]byte 56 bp := len(s) - 1 57 for i >= 10 || wid > 1 { 58 wid-- 59 q := i / 10 60 s[bp] = byte('0' + i - q*10) 61 bp-- 62 i = q 63 } 64 // i < 10 65 s[bp] = byte('0' + i) 66 return append(buf, s[bp:]...) 67 } 68 69 func colorSprintf(colorize bool, format string, args ...any) string { 70 hasColorValue := false 71 for _, v := range args { 72 if _, hasColorValue = v.(*ColoredValue); hasColorValue { 73 break 74 } 75 } 76 if colorize || !hasColorValue { 77 return fmt.Sprintf(format, args...) 78 } 79 80 noColors := make([]any, len(args)) 81 copy(noColors, args) 82 for i, v := range args { 83 if cv, ok := v.(*ColoredValue); ok { 84 noColors[i] = cv.v 85 } 86 } 87 return fmt.Sprintf(format, noColors...) 88 } 89 90 // EventFormatTextMessage makes the log message for a writer with its mode. This function is a copy of the original package 91 func EventFormatTextMessage(mode *WriterMode, event *Event, msgFormat string, msgArgs ...any) []byte { 92 buf := make([]byte, 0, 1024) 93 buf = append(buf, mode.Prefix...) 94 t := event.Time 95 flags := mode.Flags.Bits() 96 if flags&(Ldate|Ltime|Lmicroseconds) != 0 { 97 if mode.Colorize { 98 buf = append(buf, fgCyanBytes...) 99 } 100 if flags&LUTC != 0 { 101 t = t.UTC() 102 } 103 if flags&Ldate != 0 { 104 year, month, day := t.Date() 105 buf = itoa(buf, year, 4) 106 buf = append(buf, '/') 107 buf = itoa(buf, int(month), 2) 108 buf = append(buf, '/') 109 buf = itoa(buf, day, 2) 110 buf = append(buf, ' ') 111 } 112 if flags&(Ltime|Lmicroseconds) != 0 { 113 hour, min, sec := t.Clock() 114 buf = itoa(buf, hour, 2) 115 buf = append(buf, ':') 116 buf = itoa(buf, min, 2) 117 buf = append(buf, ':') 118 buf = itoa(buf, sec, 2) 119 if flags&Lmicroseconds != 0 { 120 buf = append(buf, '.') 121 buf = itoa(buf, t.Nanosecond()/1e3, 6) 122 } 123 buf = append(buf, ' ') 124 } 125 if mode.Colorize { 126 buf = append(buf, resetBytes...) 127 } 128 } 129 if flags&(Lshortfile|Llongfile) != 0 { 130 if mode.Colorize { 131 buf = append(buf, fgGreenBytes...) 132 } 133 file := event.Filename 134 if flags&Lmedfile == Lmedfile { 135 startIndex := len(file) - 20 136 if startIndex > 0 { 137 file = "..." + file[startIndex:] 138 } 139 } else if flags&Lshortfile != 0 { 140 startIndex := strings.LastIndexByte(file, '/') 141 if startIndex > 0 && startIndex < len(file) { 142 file = file[startIndex+1:] 143 } 144 } 145 buf = append(buf, file...) 146 buf = append(buf, ':') 147 buf = itoa(buf, event.Line, -1) 148 if flags&(Lfuncname|Lshortfuncname) != 0 { 149 buf = append(buf, ':') 150 } else { 151 if mode.Colorize { 152 buf = append(buf, resetBytes...) 153 } 154 buf = append(buf, ' ') 155 } 156 } 157 if flags&(Lfuncname|Lshortfuncname) != 0 { 158 if mode.Colorize { 159 buf = append(buf, fgGreenBytes...) 160 } 161 funcname := event.Caller 162 if flags&Lshortfuncname != 0 { 163 lastIndex := strings.LastIndexByte(funcname, '.') 164 if lastIndex > 0 && len(funcname) > lastIndex+1 { 165 funcname = funcname[lastIndex+1:] 166 } 167 } 168 buf = append(buf, funcname...) 169 if mode.Colorize { 170 buf = append(buf, resetBytes...) 171 } 172 buf = append(buf, ' ') 173 } 174 175 if flags&(Llevel|Llevelinitial) != 0 { 176 level := strings.ToUpper(event.Level.String()) 177 if mode.Colorize { 178 buf = append(buf, ColorBytes(levelToColor[event.Level]...)...) 179 } 180 buf = append(buf, '[') 181 if flags&Llevelinitial != 0 { 182 buf = append(buf, level[0]) 183 } else { 184 buf = append(buf, level...) 185 } 186 buf = append(buf, ']') 187 if mode.Colorize { 188 buf = append(buf, resetBytes...) 189 } 190 buf = append(buf, ' ') 191 } 192 193 var msg []byte 194 195 // if the log needs colorizing, do it 196 if mode.Colorize && len(msgArgs) > 0 { 197 hasColorValue := false 198 for _, v := range msgArgs { 199 if _, hasColorValue = v.(*ColoredValue); hasColorValue { 200 break 201 } 202 } 203 if hasColorValue { 204 msg = []byte(fmt.Sprintf(msgFormat, msgArgs...)) 205 } 206 } 207 // try to re-use the pre-formatted simple text message 208 if len(msg) == 0 { 209 msg = []byte(event.MsgSimpleText) 210 } 211 // if still no message, do the normal Sprintf for the message 212 if len(msg) == 0 { 213 msg = []byte(colorSprintf(mode.Colorize, msgFormat, msgArgs...)) 214 } 215 // remove at most one trailing new line 216 if len(msg) > 0 && msg[len(msg)-1] == '\n' { 217 msg = msg[:len(msg)-1] 218 } 219 220 if flags&Lgopid == Lgopid { 221 if event.GoroutinePid != "" { 222 buf = append(buf, '[') 223 if mode.Colorize { 224 buf = append(buf, ColorBytes(FgHiYellow)...) 225 } 226 buf = append(buf, event.GoroutinePid...) 227 if mode.Colorize { 228 buf = append(buf, resetBytes...) 229 } 230 buf = append(buf, ']', ' ') 231 } 232 } 233 buf = append(buf, msg...) 234 235 if event.Stacktrace != "" && mode.StacktraceLevel <= event.Level { 236 lines := bytes.Split([]byte(event.Stacktrace), []byte("\n")) 237 for _, line := range lines { 238 buf = append(buf, "\n\t"...) 239 buf = append(buf, line...) 240 } 241 buf = append(buf, '\n') 242 } 243 buf = append(buf, '\n') 244 return buf 245 }