gitea源码

logger_impl.go 6.6KB

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