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.

270 lines
6.3 KiB

  1. // Copyright 2019 The Gitea Authors. 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. package log
  5. import (
  6. "bytes"
  7. "fmt"
  8. "io"
  9. "regexp"
  10. "strings"
  11. "sync"
  12. )
  13. type byteArrayWriter []byte
  14. func (b *byteArrayWriter) Write(p []byte) (int, error) {
  15. *b = append(*b, p...)
  16. return len(p), nil
  17. }
  18. // WriterLogger represent a basic logger for Gitea
  19. type WriterLogger struct {
  20. out io.WriteCloser
  21. mu sync.Mutex
  22. Level Level `json:"level"`
  23. StacktraceLevel Level `json:"stacktraceLevel"`
  24. Flags int `json:"flags"`
  25. Prefix string `json:"prefix"`
  26. Colorize bool `json:"colorize"`
  27. Expression string `json:"expression"`
  28. regexp *regexp.Regexp
  29. }
  30. // NewWriterLogger creates a new WriterLogger from the provided WriteCloser.
  31. // Optionally the level can be changed at the same time.
  32. func (logger *WriterLogger) NewWriterLogger(out io.WriteCloser, level ...Level) {
  33. logger.mu.Lock()
  34. defer logger.mu.Unlock()
  35. logger.out = out
  36. switch logger.Flags {
  37. case 0:
  38. logger.Flags = LstdFlags
  39. case -1:
  40. logger.Flags = 0
  41. }
  42. if len(level) > 0 {
  43. logger.Level = level[0]
  44. }
  45. logger.createExpression()
  46. }
  47. func (logger *WriterLogger) createExpression() {
  48. if len(logger.Expression) > 0 {
  49. var err error
  50. logger.regexp, err = regexp.Compile(logger.Expression)
  51. if err != nil {
  52. logger.regexp = nil
  53. }
  54. }
  55. }
  56. // GetLevel returns the logging level for this logger
  57. func (logger *WriterLogger) GetLevel() Level {
  58. return logger.Level
  59. }
  60. // GetStacktraceLevel returns the stacktrace logging level for this logger
  61. func (logger *WriterLogger) GetStacktraceLevel() Level {
  62. return logger.StacktraceLevel
  63. }
  64. // Copy of cheap integer to fixed-width decimal to ascii from logger.
  65. func itoa(buf *[]byte, i int, wid int) {
  66. var logger [20]byte
  67. bp := len(logger) - 1
  68. for i >= 10 || wid > 1 {
  69. wid--
  70. q := i / 10
  71. logger[bp] = byte('0' + i - q*10)
  72. bp--
  73. i = q
  74. }
  75. // i < 10
  76. logger[bp] = byte('0' + i)
  77. *buf = append(*buf, logger[bp:]...)
  78. }
  79. func (logger *WriterLogger) createMsg(buf *[]byte, event *Event) {
  80. *buf = append(*buf, logger.Prefix...)
  81. t := event.time
  82. if logger.Flags&(Ldate|Ltime|Lmicroseconds) != 0 {
  83. if logger.Colorize {
  84. *buf = append(*buf, fgCyanBytes...)
  85. }
  86. if logger.Flags&LUTC != 0 {
  87. t = t.UTC()
  88. }
  89. if logger.Flags&Ldate != 0 {
  90. year, month, day := t.Date()
  91. itoa(buf, year, 4)
  92. *buf = append(*buf, '/')
  93. itoa(buf, int(month), 2)
  94. *buf = append(*buf, '/')
  95. itoa(buf, day, 2)
  96. *buf = append(*buf, ' ')
  97. }
  98. if logger.Flags&(Ltime|Lmicroseconds) != 0 {
  99. hour, min, sec := t.Clock()
  100. itoa(buf, hour, 2)
  101. *buf = append(*buf, ':')
  102. itoa(buf, min, 2)
  103. *buf = append(*buf, ':')
  104. itoa(buf, sec, 2)
  105. if logger.Flags&Lmicroseconds != 0 {
  106. *buf = append(*buf, '.')
  107. itoa(buf, t.Nanosecond()/1e3, 6)
  108. }
  109. *buf = append(*buf, ' ')
  110. }
  111. if logger.Colorize {
  112. *buf = append(*buf, resetBytes...)
  113. }
  114. }
  115. if logger.Flags&(Lshortfile|Llongfile) != 0 {
  116. if logger.Colorize {
  117. *buf = append(*buf, fgGreenBytes...)
  118. }
  119. file := event.filename
  120. if logger.Flags&Lmedfile == Lmedfile {
  121. startIndex := len(file) - 20
  122. if startIndex > 0 {
  123. file = "..." + file[startIndex:]
  124. }
  125. } else if logger.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. itoa(buf, event.line, -1)
  134. if logger.Flags&(Lfuncname|Lshortfuncname) != 0 {
  135. *buf = append(*buf, ':')
  136. } else {
  137. if logger.Colorize {
  138. *buf = append(*buf, resetBytes...)
  139. }
  140. *buf = append(*buf, ' ')
  141. }
  142. }
  143. if logger.Flags&(Lfuncname|Lshortfuncname) != 0 {
  144. if logger.Colorize {
  145. *buf = append(*buf, fgGreenBytes...)
  146. }
  147. funcname := event.caller
  148. if logger.Flags&Lshortfuncname != 0 {
  149. lastIndex := strings.LastIndexByte(funcname, '.')
  150. if lastIndex > 0 && len(funcname) > lastIndex+1 {
  151. funcname = funcname[lastIndex+1:]
  152. }
  153. }
  154. *buf = append(*buf, funcname...)
  155. if logger.Colorize {
  156. *buf = append(*buf, resetBytes...)
  157. }
  158. *buf = append(*buf, ' ')
  159. }
  160. if logger.Flags&(Llevel|Llevelinitial) != 0 {
  161. level := strings.ToUpper(event.level.String())
  162. if logger.Colorize {
  163. *buf = append(*buf, levelToColor[event.level]...)
  164. }
  165. *buf = append(*buf, '[')
  166. if logger.Flags&Llevelinitial != 0 {
  167. *buf = append(*buf, level[0])
  168. } else {
  169. *buf = append(*buf, level...)
  170. }
  171. *buf = append(*buf, ']')
  172. if logger.Colorize {
  173. *buf = append(*buf, resetBytes...)
  174. }
  175. *buf = append(*buf, ' ')
  176. }
  177. var msg = []byte(event.msg)
  178. if len(msg) > 0 && msg[len(msg)-1] == '\n' {
  179. msg = msg[:len(msg)-1]
  180. }
  181. pawMode := allowColor
  182. if !logger.Colorize {
  183. pawMode = removeColor
  184. }
  185. baw := byteArrayWriter(*buf)
  186. (&protectedANSIWriter{
  187. w: &baw,
  188. mode: pawMode,
  189. }).Write([]byte(msg))
  190. *buf = baw
  191. if event.stacktrace != "" && logger.StacktraceLevel <= event.level {
  192. lines := bytes.Split([]byte(event.stacktrace), []byte("\n"))
  193. if len(lines) > 1 {
  194. for _, line := range lines {
  195. *buf = append(*buf, "\n\t"...)
  196. *buf = append(*buf, line...)
  197. }
  198. }
  199. *buf = append(*buf, '\n')
  200. }
  201. *buf = append(*buf, '\n')
  202. }
  203. // LogEvent logs the event to the internal writer
  204. func (logger *WriterLogger) LogEvent(event *Event) error {
  205. if logger.Level > event.level {
  206. return nil
  207. }
  208. logger.mu.Lock()
  209. defer logger.mu.Unlock()
  210. if !logger.Match(event) {
  211. return nil
  212. }
  213. var buf []byte
  214. logger.createMsg(&buf, event)
  215. _, err := logger.out.Write(buf)
  216. return err
  217. }
  218. // Match checks if the given event matches the logger's regexp expression
  219. func (logger *WriterLogger) Match(event *Event) bool {
  220. if logger.regexp == nil {
  221. return true
  222. }
  223. if logger.regexp.Match([]byte(fmt.Sprintf("%s:%d:%s", event.filename, event.line, event.caller))) {
  224. return true
  225. }
  226. // Match on the non-colored msg - therefore strip out colors
  227. var msg []byte
  228. baw := byteArrayWriter(msg)
  229. (&protectedANSIWriter{
  230. w: &baw,
  231. mode: removeColor,
  232. }).Write([]byte(event.msg))
  233. msg = baw
  234. return logger.regexp.Match(msg)
  235. }
  236. // Close the base logger
  237. func (logger *WriterLogger) Close() {
  238. logger.mu.Lock()
  239. defer logger.mu.Unlock()
  240. if logger.out != nil {
  241. logger.out.Close()
  242. }
  243. }
  244. // GetName returns empty for these provider loggers
  245. func (logger *WriterLogger) GetName() string {
  246. return ""
  247. }