You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

event_format.go 5.8KB

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