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.

333 lines
7.2 KiB

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
5 years ago
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
5 years ago
  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. }
  99. // Close this ChannelledLog
  100. func (l *ChannelledLog) Close() {
  101. l.close <- true
  102. <-l.closed
  103. }
  104. // Flush this ChannelledLog
  105. func (l *ChannelledLog) Flush() {
  106. l.flush <- true
  107. }
  108. // GetLevel gets the level of this ChannelledLog
  109. func (l *ChannelledLog) GetLevel() Level {
  110. return l.loggerProvider.GetLevel()
  111. }
  112. // GetStacktraceLevel gets the level of this ChannelledLog
  113. func (l *ChannelledLog) GetStacktraceLevel() Level {
  114. return l.loggerProvider.GetStacktraceLevel()
  115. }
  116. // GetName returns the name of this ChannelledLog
  117. func (l *ChannelledLog) GetName() string {
  118. return l.name
  119. }
  120. // MultiChannelledLog represents a cached channel to a LoggerProvider
  121. type MultiChannelledLog struct {
  122. name string
  123. bufferLength int64
  124. queue chan *Event
  125. mutex sync.Mutex
  126. loggers map[string]EventLogger
  127. flush chan bool
  128. close chan bool
  129. started bool
  130. level Level
  131. stacktraceLevel Level
  132. closed chan bool
  133. }
  134. // NewMultiChannelledLog a new logger instance with given logger provider and config.
  135. func NewMultiChannelledLog(name string, bufferLength int64) *MultiChannelledLog {
  136. m := &MultiChannelledLog{
  137. name: name,
  138. queue: make(chan *Event, bufferLength),
  139. flush: make(chan bool),
  140. bufferLength: bufferLength,
  141. loggers: make(map[string]EventLogger),
  142. level: NONE,
  143. stacktraceLevel: NONE,
  144. close: make(chan bool),
  145. closed: make(chan bool),
  146. }
  147. return m
  148. }
  149. // AddLogger adds a logger to this MultiChannelledLog
  150. func (m *MultiChannelledLog) AddLogger(logger EventLogger) error {
  151. m.mutex.Lock()
  152. name := logger.GetName()
  153. if _, has := m.loggers[name]; has {
  154. m.mutex.Unlock()
  155. return ErrDuplicateName{name}
  156. }
  157. m.loggers[name] = logger
  158. if logger.GetLevel() < m.level {
  159. m.level = logger.GetLevel()
  160. }
  161. if logger.GetStacktraceLevel() < m.stacktraceLevel {
  162. m.stacktraceLevel = logger.GetStacktraceLevel()
  163. }
  164. m.mutex.Unlock()
  165. go m.Start()
  166. return nil
  167. }
  168. // DelLogger removes a sub logger from this MultiChannelledLog
  169. // NB: If you delete the last sublogger this logger will simply drop
  170. // log events
  171. func (m *MultiChannelledLog) DelLogger(name string) bool {
  172. m.mutex.Lock()
  173. logger, has := m.loggers[name]
  174. if !has {
  175. m.mutex.Unlock()
  176. return false
  177. }
  178. delete(m.loggers, name)
  179. m.internalResetLevel()
  180. m.mutex.Unlock()
  181. logger.Flush()
  182. logger.Close()
  183. return true
  184. }
  185. // GetEventLogger returns a sub logger from this MultiChannelledLog
  186. func (m *MultiChannelledLog) GetEventLogger(name string) EventLogger {
  187. m.mutex.Lock()
  188. defer m.mutex.Unlock()
  189. return m.loggers[name]
  190. }
  191. // GetEventLoggerNames returns a list of names
  192. func (m *MultiChannelledLog) GetEventLoggerNames() []string {
  193. m.mutex.Lock()
  194. defer m.mutex.Unlock()
  195. var keys []string
  196. for k := range m.loggers {
  197. keys = append(keys, k)
  198. }
  199. return keys
  200. }
  201. func (m *MultiChannelledLog) closeLoggers() {
  202. m.mutex.Lock()
  203. for _, logger := range m.loggers {
  204. logger.Flush()
  205. logger.Close()
  206. }
  207. m.mutex.Unlock()
  208. m.closed <- true
  209. }
  210. // Start processing the MultiChannelledLog
  211. func (m *MultiChannelledLog) Start() {
  212. m.mutex.Lock()
  213. if m.started {
  214. m.mutex.Unlock()
  215. return
  216. }
  217. m.started = true
  218. m.mutex.Unlock()
  219. for {
  220. select {
  221. case event, ok := <-m.queue:
  222. if !ok {
  223. m.closeLoggers()
  224. return
  225. }
  226. m.mutex.Lock()
  227. for _, logger := range m.loggers {
  228. err := logger.LogEvent(event)
  229. if err != nil {
  230. fmt.Println(err)
  231. }
  232. }
  233. m.mutex.Unlock()
  234. case _, ok := <-m.flush:
  235. if !ok {
  236. m.closeLoggers()
  237. return
  238. }
  239. m.mutex.Lock()
  240. for _, logger := range m.loggers {
  241. logger.Flush()
  242. }
  243. m.mutex.Unlock()
  244. case <-m.close:
  245. m.closeLoggers()
  246. return
  247. }
  248. }
  249. }
  250. // LogEvent logs an event to this MultiChannelledLog
  251. func (m *MultiChannelledLog) LogEvent(event *Event) error {
  252. select {
  253. case m.queue <- event:
  254. return nil
  255. case <-time.After(60 * time.Second):
  256. // We're blocked!
  257. return ErrTimeout{
  258. Name: m.name,
  259. Provider: "MultiChannelledLog",
  260. }
  261. }
  262. }
  263. // Close this MultiChannelledLog
  264. func (m *MultiChannelledLog) Close() {
  265. m.close <- true
  266. <-m.closed
  267. }
  268. // Flush this ChannelledLog
  269. func (m *MultiChannelledLog) Flush() {
  270. m.flush <- true
  271. }
  272. // GetLevel gets the level of this MultiChannelledLog
  273. func (m *MultiChannelledLog) GetLevel() Level {
  274. return m.level
  275. }
  276. // GetStacktraceLevel gets the level of this MultiChannelledLog
  277. func (m *MultiChannelledLog) GetStacktraceLevel() Level {
  278. return m.stacktraceLevel
  279. }
  280. func (m *MultiChannelledLog) internalResetLevel() Level {
  281. m.level = NONE
  282. for _, logger := range m.loggers {
  283. level := logger.GetLevel()
  284. if level < m.level {
  285. m.level = level
  286. }
  287. level = logger.GetStacktraceLevel()
  288. if level < m.stacktraceLevel {
  289. m.stacktraceLevel = level
  290. }
  291. }
  292. return m.level
  293. }
  294. // ResetLevel will reset the level of this MultiChannelledLog
  295. func (m *MultiChannelledLog) ResetLevel() Level {
  296. m.mutex.Lock()
  297. defer m.mutex.Unlock()
  298. return m.internalResetLevel()
  299. }
  300. // GetName gets the name of this MultiChannelledLog
  301. func (m *MultiChannelledLog) GetName() string {
  302. return m.name
  303. }