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.

base.go 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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. // These flags define which text to prefix to each log entry generated
  14. // by the Logger. Bits are or'ed together to control what's printed.
  15. // There is no control over the order they appear (the order listed
  16. // here) or the format they present (as described in the comments).
  17. // The prefix is followed by a colon only if more than time is stated
  18. // is specified. For example, flags Ldate | Ltime
  19. // produce, 2009/01/23 01:23:23 message.
  20. // The standard is:
  21. // 2009/01/23 01:23:23 ...a/b/c/d.go:23:runtime.Caller() [I]: message
  22. const (
  23. Ldate = 1 << iota // the date in the local time zone: 2009/01/23
  24. Ltime // the time in the local time zone: 01:23:23
  25. Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
  26. Llongfile // full file name and line number: /a/b/c/d.go:23
  27. Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
  28. Lfuncname // function name of the caller: runtime.Caller()
  29. Lshortfuncname // last part of the function name
  30. LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
  31. Llevelinitial // Initial character of the provided level in brackets eg. [I] for info
  32. Llevel // Provided level in brackets [INFO]
  33. // Last 20 characters of the filename
  34. Lmedfile = Lshortfile | Llongfile
  35. // LstdFlags is the initial value for the standard logger
  36. LstdFlags = Ldate | Ltime | Lmedfile | Lshortfuncname | Llevelinitial
  37. )
  38. var flagFromString = map[string]int{
  39. "none": 0,
  40. "date": Ldate,
  41. "time": Ltime,
  42. "microseconds": Lmicroseconds,
  43. "longfile": Llongfile,
  44. "shortfile": Lshortfile,
  45. "funcname": Lfuncname,
  46. "shortfuncname": Lshortfuncname,
  47. "utc": LUTC,
  48. "levelinitial": Llevelinitial,
  49. "level": Llevel,
  50. "medfile": Lmedfile,
  51. "stdflags": LstdFlags,
  52. }
  53. // FlagsFromString takes a comma separated list of flags and returns
  54. // the flags for this string
  55. func FlagsFromString(from string) int {
  56. flags := 0
  57. for _, flag := range strings.Split(strings.ToLower(from), ",") {
  58. f, ok := flagFromString[strings.TrimSpace(flag)]
  59. if ok {
  60. flags = flags | f
  61. }
  62. }
  63. return flags
  64. }
  65. type byteArrayWriter []byte
  66. func (b *byteArrayWriter) Write(p []byte) (int, error) {
  67. *b = append(*b, p...)
  68. return len(p), nil
  69. }
  70. // BaseLogger represent a basic logger for Gitea
  71. type BaseLogger struct {
  72. out io.WriteCloser
  73. mu sync.Mutex
  74. Level Level `json:"level"`
  75. StacktraceLevel Level `json:"stacktraceLevel"`
  76. Flags int `json:"flags"`
  77. Prefix string `json:"prefix"`
  78. Colorize bool `json:"colorize"`
  79. Expression string `json:"expression"`
  80. regexp *regexp.Regexp
  81. }
  82. func (b *BaseLogger) createLogger(out io.WriteCloser, level ...Level) {
  83. b.mu.Lock()
  84. defer b.mu.Unlock()
  85. b.out = out
  86. switch b.Flags {
  87. case 0:
  88. b.Flags = LstdFlags
  89. case -1:
  90. b.Flags = 0
  91. }
  92. if len(level) > 0 {
  93. b.Level = level[0]
  94. }
  95. b.createExpression()
  96. }
  97. func (b *BaseLogger) createExpression() {
  98. if len(b.Expression) > 0 {
  99. var err error
  100. b.regexp, err = regexp.Compile(b.Expression)
  101. if err != nil {
  102. b.regexp = nil
  103. }
  104. }
  105. }
  106. // GetLevel returns the logging level for this logger
  107. func (b *BaseLogger) GetLevel() Level {
  108. return b.Level
  109. }
  110. // GetStacktraceLevel returns the stacktrace logging level for this logger
  111. func (b *BaseLogger) GetStacktraceLevel() Level {
  112. return b.StacktraceLevel
  113. }
  114. // Copy of cheap integer to fixed-width decimal to ascii from logger.
  115. func itoa(buf *[]byte, i int, wid int) {
  116. var b [20]byte
  117. bp := len(b) - 1
  118. for i >= 10 || wid > 1 {
  119. wid--
  120. q := i / 10
  121. b[bp] = byte('0' + i - q*10)
  122. bp--
  123. i = q
  124. }
  125. // i < 10
  126. b[bp] = byte('0' + i)
  127. *buf = append(*buf, b[bp:]...)
  128. }
  129. func (b *BaseLogger) createMsg(buf *[]byte, event *Event) {
  130. *buf = append(*buf, b.Prefix...)
  131. t := event.time
  132. if b.Flags&(Ldate|Ltime|Lmicroseconds) != 0 {
  133. if b.Colorize {
  134. *buf = append(*buf, fgCyanBytes...)
  135. }
  136. if b.Flags&LUTC != 0 {
  137. t = t.UTC()
  138. }
  139. if b.Flags&Ldate != 0 {
  140. year, month, day := t.Date()
  141. itoa(buf, year, 4)
  142. *buf = append(*buf, '/')
  143. itoa(buf, int(month), 2)
  144. *buf = append(*buf, '/')
  145. itoa(buf, day, 2)
  146. *buf = append(*buf, ' ')
  147. }
  148. if b.Flags&(Ltime|Lmicroseconds) != 0 {
  149. hour, min, sec := t.Clock()
  150. itoa(buf, hour, 2)
  151. *buf = append(*buf, ':')
  152. itoa(buf, min, 2)
  153. *buf = append(*buf, ':')
  154. itoa(buf, sec, 2)
  155. if b.Flags&Lmicroseconds != 0 {
  156. *buf = append(*buf, '.')
  157. itoa(buf, t.Nanosecond()/1e3, 6)
  158. }
  159. *buf = append(*buf, ' ')
  160. }
  161. if b.Colorize {
  162. *buf = append(*buf, resetBytes...)
  163. }
  164. }
  165. if b.Flags&(Lshortfile|Llongfile) != 0 {
  166. if b.Colorize {
  167. *buf = append(*buf, fgGreenBytes...)
  168. }
  169. file := event.filename
  170. if b.Flags&Lmedfile == Lmedfile {
  171. startIndex := len(file) - 20
  172. if startIndex > 0 {
  173. file = "..." + file[startIndex:]
  174. }
  175. } else if b.Flags&Lshortfile != 0 {
  176. startIndex := strings.LastIndexByte(file, '/')
  177. if startIndex > 0 && startIndex < len(file) {
  178. file = file[startIndex+1:]
  179. }
  180. }
  181. *buf = append(*buf, file...)
  182. *buf = append(*buf, ':')
  183. itoa(buf, event.line, -1)
  184. if b.Flags&(Lfuncname|Lshortfuncname) != 0 {
  185. *buf = append(*buf, ':')
  186. } else {
  187. if b.Colorize {
  188. *buf = append(*buf, resetBytes...)
  189. }
  190. *buf = append(*buf, ' ')
  191. }
  192. }
  193. if b.Flags&(Lfuncname|Lshortfuncname) != 0 {
  194. if b.Colorize {
  195. *buf = append(*buf, fgGreenBytes...)
  196. }
  197. funcname := event.caller
  198. if b.Flags&Lshortfuncname != 0 {
  199. lastIndex := strings.LastIndexByte(funcname, '.')
  200. if lastIndex > 0 && len(funcname) > lastIndex+1 {
  201. funcname = funcname[lastIndex+1:]
  202. }
  203. }
  204. *buf = append(*buf, funcname...)
  205. if b.Colorize {
  206. *buf = append(*buf, resetBytes...)
  207. }
  208. *buf = append(*buf, ' ')
  209. }
  210. if b.Flags&(Llevel|Llevelinitial) != 0 {
  211. level := strings.ToUpper(event.level.String())
  212. if b.Colorize {
  213. *buf = append(*buf, levelToColor[event.level]...)
  214. }
  215. *buf = append(*buf, '[')
  216. if b.Flags&Llevelinitial != 0 {
  217. *buf = append(*buf, level[0])
  218. } else {
  219. *buf = append(*buf, level...)
  220. }
  221. *buf = append(*buf, ']')
  222. if b.Colorize {
  223. *buf = append(*buf, resetBytes...)
  224. }
  225. *buf = append(*buf, ' ')
  226. }
  227. var msg = []byte(event.msg)
  228. if len(msg) > 0 && msg[len(msg)-1] == '\n' {
  229. msg = msg[:len(msg)-1]
  230. }
  231. pawMode := allowColor
  232. if !b.Colorize {
  233. pawMode = removeColor
  234. }
  235. baw := byteArrayWriter(*buf)
  236. (&protectedANSIWriter{
  237. w: &baw,
  238. mode: pawMode,
  239. }).Write([]byte(msg))
  240. *buf = baw
  241. if event.stacktrace != "" && b.StacktraceLevel <= event.level {
  242. lines := bytes.Split([]byte(event.stacktrace), []byte("\n"))
  243. if len(lines) > 1 {
  244. for _, line := range lines {
  245. *buf = append(*buf, "\n\t"...)
  246. *buf = append(*buf, line...)
  247. }
  248. }
  249. *buf = append(*buf, '\n')
  250. }
  251. *buf = append(*buf, '\n')
  252. }
  253. // LogEvent logs the event to the internal writer
  254. func (b *BaseLogger) LogEvent(event *Event) error {
  255. if b.Level > event.level {
  256. return nil
  257. }
  258. b.mu.Lock()
  259. defer b.mu.Unlock()
  260. if !b.Match(event) {
  261. return nil
  262. }
  263. var buf []byte
  264. b.createMsg(&buf, event)
  265. _, err := b.out.Write(buf)
  266. return err
  267. }
  268. // Match checks if the given event matches the logger's regexp expression
  269. func (b *BaseLogger) Match(event *Event) bool {
  270. if b.regexp == nil {
  271. return true
  272. }
  273. if b.regexp.Match([]byte(fmt.Sprintf("%s:%d:%s", event.filename, event.line, event.caller))) {
  274. return true
  275. }
  276. // Match on the non-colored msg - therefore strip out colors
  277. var msg []byte
  278. baw := byteArrayWriter(msg)
  279. (&protectedANSIWriter{
  280. w: &baw,
  281. mode: removeColor,
  282. }).Write([]byte(event.msg))
  283. msg = baw
  284. if b.regexp.Match(msg) {
  285. return true
  286. }
  287. return false
  288. }
  289. // Close the base logger
  290. func (b *BaseLogger) Close() {
  291. b.mu.Lock()
  292. defer b.mu.Unlock()
  293. if b.out != nil {
  294. b.out.Close()
  295. }
  296. }
  297. // GetName returns empty for these provider loggers
  298. func (b *BaseLogger) GetName() string {
  299. return ""
  300. }