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.

logger_impl.go 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package log
  4. import (
  5. "context"
  6. "runtime"
  7. "strings"
  8. "sync"
  9. "sync/atomic"
  10. "time"
  11. "code.gitea.io/gitea/modules/json"
  12. "code.gitea.io/gitea/modules/util"
  13. )
  14. type LoggerImpl struct {
  15. LevelLogger
  16. ctx context.Context
  17. ctxCancel context.CancelFunc
  18. level atomic.Int32
  19. stacktraceLevel atomic.Int32
  20. eventWriterMu sync.RWMutex
  21. eventWriters map[string]EventWriter
  22. }
  23. var (
  24. _ BaseLogger = (*LoggerImpl)(nil)
  25. _ LevelLogger = (*LoggerImpl)(nil)
  26. )
  27. // SendLogEvent sends a log event to all writers
  28. func (l *LoggerImpl) SendLogEvent(event *Event) {
  29. l.eventWriterMu.RLock()
  30. defer l.eventWriterMu.RUnlock()
  31. if len(l.eventWriters) == 0 {
  32. FallbackErrorf("[no logger writer]: %s", event.MsgSimpleText)
  33. return
  34. }
  35. // the writers have their own goroutines, the message arguments (with Stringer) shouldn't be used in other goroutines
  36. // so the event message must be formatted here
  37. msgFormat, msgArgs := event.msgFormat, event.msgArgs
  38. event.msgFormat, event.msgArgs = "(already processed by formatters)", nil
  39. for _, w := range l.eventWriters {
  40. if event.Level < w.GetLevel() {
  41. continue
  42. }
  43. formatted := &EventFormatted{
  44. Origin: event,
  45. Msg: w.Base().FormatMessage(w.Base().Mode, event, msgFormat, msgArgs...),
  46. }
  47. select {
  48. case w.Base().Queue <- formatted:
  49. default:
  50. bs, _ := json.Marshal(event)
  51. FallbackErrorf("log writer %q queue is full, event: %v", w.GetWriterName(), string(bs))
  52. }
  53. }
  54. }
  55. // syncLevelInternal syncs the level of the logger with the levels of the writers
  56. func (l *LoggerImpl) syncLevelInternal() {
  57. lowestLevel := NONE
  58. for _, w := range l.eventWriters {
  59. if w.GetLevel() < lowestLevel {
  60. lowestLevel = w.GetLevel()
  61. }
  62. }
  63. l.level.Store(int32(lowestLevel))
  64. lowestLevel = NONE
  65. for _, w := range l.eventWriters {
  66. if w.Base().Mode.StacktraceLevel < lowestLevel {
  67. lowestLevel = w.GetLevel()
  68. }
  69. }
  70. l.stacktraceLevel.Store(int32(lowestLevel))
  71. }
  72. // removeWriterInternal removes a writer from the logger, and stops it if it's not shared
  73. func (l *LoggerImpl) removeWriterInternal(w EventWriter) {
  74. if !w.Base().shared {
  75. eventWriterStopWait(w) // only stop non-shared writers, shared writers are managed by the manager
  76. }
  77. delete(l.eventWriters, w.GetWriterName())
  78. }
  79. // AddWriters adds writers to the logger, and starts them. Existing writers will be replaced by new ones.
  80. func (l *LoggerImpl) AddWriters(writer ...EventWriter) {
  81. l.eventWriterMu.Lock()
  82. defer l.eventWriterMu.Unlock()
  83. for _, w := range writer {
  84. if old, ok := l.eventWriters[w.GetWriterName()]; ok {
  85. l.removeWriterInternal(old)
  86. }
  87. }
  88. for _, w := range writer {
  89. l.eventWriters[w.GetWriterName()] = w
  90. eventWriterStartGo(l.ctx, w, false)
  91. }
  92. l.syncLevelInternal()
  93. }
  94. // RemoveWriter removes a writer from the logger, and the writer is closed and flushed if it is not shared
  95. func (l *LoggerImpl) RemoveWriter(modeName string) error {
  96. l.eventWriterMu.Lock()
  97. defer l.eventWriterMu.Unlock()
  98. w, ok := l.eventWriters[modeName]
  99. if !ok {
  100. return util.ErrNotExist
  101. }
  102. l.removeWriterInternal(w)
  103. l.syncLevelInternal()
  104. return nil
  105. }
  106. // RemoveAllWriters removes all writers from the logger, non-shared writers are closed and flushed
  107. func (l *LoggerImpl) RemoveAllWriters() *LoggerImpl {
  108. l.eventWriterMu.Lock()
  109. defer l.eventWriterMu.Unlock()
  110. for _, w := range l.eventWriters {
  111. l.removeWriterInternal(w)
  112. }
  113. l.eventWriters = map[string]EventWriter{}
  114. l.syncLevelInternal()
  115. return l
  116. }
  117. // DumpWriters dumps the writers as a JSON map, it's used for debugging and display purposes.
  118. func (l *LoggerImpl) DumpWriters() map[string]any {
  119. l.eventWriterMu.RLock()
  120. defer l.eventWriterMu.RUnlock()
  121. writers := make(map[string]any, len(l.eventWriters))
  122. for k, w := range l.eventWriters {
  123. bs, err := json.Marshal(w.Base().Mode)
  124. if err != nil {
  125. FallbackErrorf("marshal writer %q to dump failed: %v", k, err)
  126. continue
  127. }
  128. m := map[string]any{}
  129. _ = json.Unmarshal(bs, &m)
  130. m["WriterType"] = w.GetWriterType()
  131. writers[k] = m
  132. }
  133. return writers
  134. }
  135. // Close closes the logger, non-shared writers are closed and flushed
  136. func (l *LoggerImpl) Close() {
  137. l.RemoveAllWriters()
  138. l.ctxCancel()
  139. }
  140. // IsEnabled returns true if the logger is enabled: it has a working level and has writers
  141. // Fatal is not considered as enabled, because it's a special case and the process just exits
  142. func (l *LoggerImpl) IsEnabled() bool {
  143. l.eventWriterMu.RLock()
  144. defer l.eventWriterMu.RUnlock()
  145. return l.level.Load() < int32(FATAL) && len(l.eventWriters) > 0
  146. }
  147. // Log prepares the log event, if the level matches, the event will be sent to the writers
  148. func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) {
  149. if Level(l.level.Load()) > level {
  150. return
  151. }
  152. event := &Event{
  153. Time: time.Now(),
  154. Level: level,
  155. Caller: "?()",
  156. }
  157. pc, filename, line, ok := runtime.Caller(skip + 1)
  158. if ok {
  159. fn := runtime.FuncForPC(pc)
  160. if fn != nil {
  161. event.Caller = fn.Name() + "()"
  162. }
  163. }
  164. event.Filename, event.Line = strings.TrimPrefix(filename, projectPackagePrefix), line
  165. if l.stacktraceLevel.Load() <= int32(level) {
  166. event.Stacktrace = Stack(skip + 1)
  167. }
  168. labels := getGoroutineLabels()
  169. if labels != nil {
  170. event.GoroutinePid = labels["pid"]
  171. }
  172. // get a simple text message without color
  173. msgArgs := make([]any, len(logArgs))
  174. copy(msgArgs, logArgs)
  175. // handle LogStringer values
  176. for i, v := range msgArgs {
  177. if cv, ok := v.(*ColoredValue); ok {
  178. if s, ok := cv.v.(LogStringer); ok {
  179. cv.v = logStringFormatter{v: s}
  180. }
  181. } else if s, ok := v.(LogStringer); ok {
  182. msgArgs[i] = logStringFormatter{v: s}
  183. }
  184. }
  185. event.MsgSimpleText = colorSprintf(false, format, msgArgs...)
  186. event.msgFormat = format
  187. event.msgArgs = msgArgs
  188. l.SendLogEvent(event)
  189. }
  190. func (l *LoggerImpl) GetLevel() Level {
  191. return Level(l.level.Load())
  192. }
  193. func NewLoggerWithWriters(ctx context.Context, name string, writer ...EventWriter) *LoggerImpl {
  194. l := &LoggerImpl{}
  195. l.ctx, l.ctxCancel = newProcessTypedContext(ctx, "Logger: "+name)
  196. l.LevelLogger = BaseLoggerToGeneralLogger(l)
  197. l.eventWriters = map[string]EventWriter{}
  198. l.syncLevelInternal()
  199. l.AddWriters(writer...)
  200. return l
  201. }