gitea源码

event_format.go 6.3KB

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