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

event.go 7.4 kB

Better logging (#6038) (#6095) * Panic don't fatal on create new logger Fixes #5854 Signed-off-by: Andrew Thornton <art27@cantab.net> * partial broken * Update the logging infrastrcture Signed-off-by: Andrew Thornton <art27@cantab.net> * Reset the skip levels for Fatal and Error Signed-off-by: Andrew Thornton <art27@cantab.net> * broken ncsa * More log.Error fixes Signed-off-by: Andrew Thornton <art27@cantab.net> * Remove nal * set log-levels to lowercase * Make console_test test all levels * switch to lowercased levels * OK now working * Fix vetting issues * Fix lint * Fix tests * change default logging to match current gitea * Improve log testing Signed-off-by: Andrew Thornton <art27@cantab.net> * reset error skip levels to 0 * Update documentation and access logger configuration * Redirect the router log back to gitea if redirect macaron log but also allow setting the log level - i.e. TRACE * Fix broken level caching * Refactor the router log * Add Router logger * Add colorizing options * Adjust router colors * Only create logger if they will be used * update app.ini.sample * rename Attribute ColorAttribute * Change from white to green for function * Set fatal/error levels * Restore initial trace logger * Fix Trace arguments in modules/auth/auth.go * Properly handle XORMLogger * Improve admin/config page * fix fmt * Add auto-compression of old logs * Update error log levels * Remove the unnecessary skip argument from Error, Fatal and Critical * Add stacktrace support * Fix tests * Remove x/sync from vendors? * Add stderr option to console logger * Use filepath.ToSlash to protect against Windows in tests * Remove prefixed underscores from names in colors.go * Remove not implemented database logger This was removed from Gogs on 4 Mar 2016 but left in the configuration since then. * Ensure that log paths are relative to ROOT_PATH * use path.Join * rename jsonConfig to logConfig * Rename "config" to "jsonConfig" to make it clearer * Requested changes * Requested changes: XormLogger * Try to color the windows terminal If successful default to colorizing the console logs * fixup * Colorize initially too * update vendor * Colorize logs on default and remove if this is not a colorizing logger * Fix documentation * fix test * Use go-isatty to detect if on windows we are on msys or cygwin * Fix spelling mistake * Add missing vendors * More changes * Rationalise the ANSI writer protection * Adjust colors on advice from @0x5c * Make Flags a comma separated list * Move to use the windows constant for ENABLE_VIRTUAL_TERMINAL_PROCESSING * Ensure matching is done on the non-colored message - to simpify EXPRESSION
6 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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. "fmt"
  7. "sync"
  8. "time"
  9. )
  10. // Event represents a logging event
  11. type Event struct {
  12. level Level
  13. msg string
  14. caller string
  15. filename string
  16. line int
  17. time time.Time
  18. stacktrace string
  19. }
  20. // EventLogger represents the behaviours of a logger
  21. type EventLogger interface {
  22. LogEvent(event *Event) error
  23. Close()
  24. Flush()
  25. GetLevel() Level
  26. GetStacktraceLevel() Level
  27. GetName() string
  28. }
  29. // ChannelledLog represents a cached channel to a LoggerProvider
  30. type ChannelledLog struct {
  31. name string
  32. provider string
  33. queue chan *Event
  34. loggerProvider LoggerProvider
  35. flush chan bool
  36. close chan bool
  37. closed chan bool
  38. }
  39. // NewChannelledLog a new logger instance with given logger provider and config.
  40. func NewChannelledLog(name, provider, config string, bufferLength int64) (*ChannelledLog, error) {
  41. if log, ok := providers[provider]; ok {
  42. l := &ChannelledLog{
  43. queue: make(chan *Event, bufferLength),
  44. flush: make(chan bool),
  45. close: make(chan bool),
  46. closed: make(chan bool),
  47. }
  48. l.loggerProvider = log()
  49. if err := l.loggerProvider.Init(config); err != nil {
  50. return nil, err
  51. }
  52. l.name = name
  53. l.provider = provider
  54. go l.Start()
  55. return l, nil
  56. }
  57. return nil, ErrUnknownProvider{provider}
  58. }
  59. // Start processing the ChannelledLog
  60. func (l *ChannelledLog) Start() {
  61. for {
  62. select {
  63. case event, ok := <-l.queue:
  64. if !ok {
  65. l.closeLogger()
  66. return
  67. }
  68. l.loggerProvider.LogEvent(event)
  69. case _, ok := <-l.flush:
  70. if !ok {
  71. l.closeLogger()
  72. return
  73. }
  74. l.loggerProvider.Flush()
  75. case _, _ = <-l.close:
  76. l.closeLogger()
  77. return
  78. }
  79. }
  80. }
  81. // LogEvent logs an event to this ChannelledLog
  82. func (l *ChannelledLog) LogEvent(event *Event) error {
  83. select {
  84. case l.queue <- event:
  85. return nil
  86. case <-time.After(60 * time.Second):
  87. // We're blocked!
  88. return ErrTimeout{
  89. Name: l.name,
  90. Provider: l.provider,
  91. }
  92. }
  93. }
  94. func (l *ChannelledLog) closeLogger() {
  95. l.loggerProvider.Flush()
  96. l.loggerProvider.Close()
  97. l.closed <- true
  98. return
  99. }
  100. // Close this ChannelledLog
  101. func (l *ChannelledLog) Close() {
  102. l.close <- true
  103. <-l.closed
  104. }
  105. // Flush this ChannelledLog
  106. func (l *ChannelledLog) Flush() {
  107. l.flush <- true
  108. }
  109. // GetLevel gets the level of this ChannelledLog
  110. func (l *ChannelledLog) GetLevel() Level {
  111. return l.loggerProvider.GetLevel()
  112. }
  113. // GetStacktraceLevel gets the level of this ChannelledLog
  114. func (l *ChannelledLog) GetStacktraceLevel() Level {
  115. return l.loggerProvider.GetStacktraceLevel()
  116. }
  117. // GetName returns the name of this ChannelledLog
  118. func (l *ChannelledLog) GetName() string {
  119. return l.name
  120. }
  121. // MultiChannelledLog represents a cached channel to a LoggerProvider
  122. type MultiChannelledLog struct {
  123. name string
  124. bufferLength int64
  125. queue chan *Event
  126. mutex sync.Mutex
  127. loggers map[string]EventLogger
  128. flush chan bool
  129. close chan bool
  130. started bool
  131. level Level
  132. stacktraceLevel Level
  133. closed chan bool
  134. }
  135. // NewMultiChannelledLog a new logger instance with given logger provider and config.
  136. func NewMultiChannelledLog(name string, bufferLength int64) *MultiChannelledLog {
  137. m := &MultiChannelledLog{
  138. name: name,
  139. queue: make(chan *Event, bufferLength),
  140. flush: make(chan bool),
  141. bufferLength: bufferLength,
  142. loggers: make(map[string]EventLogger),
  143. level: NONE,
  144. stacktraceLevel: NONE,
  145. close: make(chan bool),
  146. closed: make(chan bool),
  147. }
  148. return m
  149. }
  150. // AddLogger adds a logger to this MultiChannelledLog
  151. func (m *MultiChannelledLog) AddLogger(logger EventLogger) error {
  152. m.mutex.Lock()
  153. name := logger.GetName()
  154. if _, has := m.loggers[name]; has {
  155. m.mutex.Unlock()
  156. return ErrDuplicateName{name}
  157. }
  158. m.loggers[name] = logger
  159. if logger.GetLevel() < m.level {
  160. m.level = logger.GetLevel()
  161. }
  162. if logger.GetStacktraceLevel() < m.stacktraceLevel {
  163. m.stacktraceLevel = logger.GetStacktraceLevel()
  164. }
  165. m.mutex.Unlock()
  166. go m.Start()
  167. return nil
  168. }
  169. // DelLogger removes a sub logger from this MultiChannelledLog
  170. // NB: If you delete the last sublogger this logger will simply drop
  171. // log events
  172. func (m *MultiChannelledLog) DelLogger(name string) bool {
  173. m.mutex.Lock()
  174. logger, has := m.loggers[name]
  175. if !has {
  176. m.mutex.Unlock()
  177. return false
  178. }
  179. delete(m.loggers, name)
  180. m.internalResetLevel()
  181. m.mutex.Unlock()
  182. logger.Flush()
  183. logger.Close()
  184. return true
  185. }
  186. // GetEventLogger returns a sub logger from this MultiChannelledLog
  187. func (m *MultiChannelledLog) GetEventLogger(name string) EventLogger {
  188. m.mutex.Lock()
  189. defer m.mutex.Unlock()
  190. return m.loggers[name]
  191. }
  192. // GetEventLoggerNames returns a list of names
  193. func (m *MultiChannelledLog) GetEventLoggerNames() []string {
  194. m.mutex.Lock()
  195. defer m.mutex.Unlock()
  196. var keys []string
  197. for k := range m.loggers {
  198. keys = append(keys, k)
  199. }
  200. return keys
  201. }
  202. func (m *MultiChannelledLog) closeLoggers() {
  203. m.mutex.Lock()
  204. for _, logger := range m.loggers {
  205. logger.Flush()
  206. logger.Close()
  207. }
  208. m.mutex.Unlock()
  209. m.closed <- true
  210. return
  211. }
  212. // Start processing the MultiChannelledLog
  213. func (m *MultiChannelledLog) Start() {
  214. m.mutex.Lock()
  215. if m.started {
  216. m.mutex.Unlock()
  217. return
  218. }
  219. m.started = true
  220. m.mutex.Unlock()
  221. for {
  222. select {
  223. case event, ok := <-m.queue:
  224. if !ok {
  225. m.closeLoggers()
  226. return
  227. }
  228. m.mutex.Lock()
  229. for _, logger := range m.loggers {
  230. err := logger.LogEvent(event)
  231. if err != nil {
  232. fmt.Println(err)
  233. }
  234. }
  235. m.mutex.Unlock()
  236. case _, ok := <-m.flush:
  237. if !ok {
  238. m.closeLoggers()
  239. return
  240. }
  241. m.mutex.Lock()
  242. for _, logger := range m.loggers {
  243. logger.Flush()
  244. }
  245. m.mutex.Unlock()
  246. case <-m.close:
  247. m.closeLoggers()
  248. return
  249. }
  250. }
  251. }
  252. // LogEvent logs an event to this MultiChannelledLog
  253. func (m *MultiChannelledLog) LogEvent(event *Event) error {
  254. select {
  255. case m.queue <- event:
  256. return nil
  257. case <-time.After(60 * time.Second):
  258. // We're blocked!
  259. return ErrTimeout{
  260. Name: m.name,
  261. Provider: "MultiChannelledLog",
  262. }
  263. }
  264. }
  265. // Close this MultiChannelledLog
  266. func (m *MultiChannelledLog) Close() {
  267. m.close <- true
  268. <-m.closed
  269. }
  270. // Flush this ChannelledLog
  271. func (m *MultiChannelledLog) Flush() {
  272. m.flush <- true
  273. }
  274. // GetLevel gets the level of this MultiChannelledLog
  275. func (m *MultiChannelledLog) GetLevel() Level {
  276. return m.level
  277. }
  278. // GetStacktraceLevel gets the level of this MultiChannelledLog
  279. func (m *MultiChannelledLog) GetStacktraceLevel() Level {
  280. return m.stacktraceLevel
  281. }
  282. func (m *MultiChannelledLog) internalResetLevel() Level {
  283. m.level = NONE
  284. for _, logger := range m.loggers {
  285. level := logger.GetLevel()
  286. if level < m.level {
  287. m.level = level
  288. }
  289. level = logger.GetStacktraceLevel()
  290. if level < m.stacktraceLevel {
  291. m.stacktraceLevel = level
  292. }
  293. }
  294. return m.level
  295. }
  296. // ResetLevel will reset the level of this MultiChannelledLog
  297. func (m *MultiChannelledLog) ResetLevel() Level {
  298. m.mutex.Lock()
  299. defer m.mutex.Unlock()
  300. return m.internalResetLevel()
  301. }
  302. // GetName gets the name of this MultiChannelledLog
  303. func (m *MultiChannelledLog) GetName() string {
  304. return m.name
  305. }