gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package log
  4. import (
  5. "regexp"
  6. "sync"
  7. "testing"
  8. "time"
  9. "github.com/stretchr/testify/assert"
  10. )
  11. type dummyWriter struct {
  12. *EventWriterBaseImpl
  13. delay time.Duration
  14. mu sync.Mutex
  15. logs []string
  16. }
  17. func (d *dummyWriter) Write(p []byte) (n int, err error) {
  18. if d.delay > 0 {
  19. time.Sleep(d.delay)
  20. }
  21. d.mu.Lock()
  22. defer d.mu.Unlock()
  23. d.logs = append(d.logs, string(p))
  24. return len(p), nil
  25. }
  26. func (d *dummyWriter) Close() error {
  27. return nil
  28. }
  29. func (d *dummyWriter) FetchLogs() []string {
  30. d.mu.Lock()
  31. defer d.mu.Unlock()
  32. logs := d.logs
  33. d.logs = nil
  34. return logs
  35. }
  36. func newDummyWriter(name string, level Level, delay time.Duration) *dummyWriter {
  37. w := &dummyWriter{
  38. EventWriterBaseImpl: NewEventWriterBase(name, "dummy", WriterMode{Level: level, Flags: FlagsFromBits(0)}),
  39. }
  40. w.delay = delay
  41. w.Base().OutputWriteCloser = w
  42. return w
  43. }
  44. func TestLogger(t *testing.T) {
  45. logger := NewLoggerWithWriters(t.Context(), "test")
  46. dump := logger.DumpWriters()
  47. assert.Empty(t, dump)
  48. assert.Equal(t, NONE, logger.GetLevel())
  49. assert.False(t, logger.IsEnabled())
  50. w1 := newDummyWriter("dummy-1", DEBUG, 0)
  51. logger.AddWriters(w1)
  52. assert.Equal(t, DEBUG, logger.GetLevel())
  53. w2 := newDummyWriter("dummy-2", WARN, 200*time.Millisecond)
  54. logger.AddWriters(w2)
  55. assert.Equal(t, DEBUG, logger.GetLevel())
  56. dump = logger.DumpWriters()
  57. assert.Len(t, dump, 2)
  58. logger.Trace("trace-level") // this level is not logged
  59. logger.Debug("debug-level")
  60. logger.Error("error-level")
  61. // w2 is slow, so only w1 has logs
  62. time.Sleep(100 * time.Millisecond)
  63. assert.Equal(t, []string{"debug-level\n", "error-level\n"}, w1.FetchLogs())
  64. assert.Empty(t, w2.FetchLogs())
  65. logger.Close()
  66. // after Close, all logs are flushed
  67. assert.Empty(t, w1.FetchLogs())
  68. assert.Equal(t, []string{"error-level\n"}, w2.FetchLogs())
  69. }
  70. func TestLoggerPause(t *testing.T) {
  71. logger := NewLoggerWithWriters(t.Context(), "test")
  72. w1 := newDummyWriter("dummy-1", DEBUG, 0)
  73. logger.AddWriters(w1)
  74. GetManager().PauseAll()
  75. time.Sleep(50 * time.Millisecond)
  76. logger.Info("info-level")
  77. time.Sleep(100 * time.Millisecond)
  78. assert.Empty(t, w1.FetchLogs())
  79. GetManager().ResumeAll()
  80. time.Sleep(100 * time.Millisecond)
  81. assert.Equal(t, []string{"info-level\n"}, w1.FetchLogs())
  82. logger.Close()
  83. }
  84. type testLogString struct {
  85. Field string
  86. }
  87. func (t testLogString) LogString() string {
  88. return "log-string"
  89. }
  90. type testLogStringPtrReceiver struct {
  91. Field string
  92. }
  93. func (t *testLogStringPtrReceiver) LogString() string {
  94. return "log-string-ptr-receiver"
  95. }
  96. func genericFunc[T any](logger Logger, v T) {
  97. logger.Info("from genericFunc: %v", v)
  98. }
  99. func TestLoggerOutput(t *testing.T) {
  100. t.Run("LogString", func(t *testing.T) {
  101. logger := NewLoggerWithWriters(t.Context(), "test")
  102. w1 := newDummyWriter("dummy-1", DEBUG, 0)
  103. w1.Mode.Colorize = true
  104. logger.AddWriters(w1)
  105. logger.Info("%s %s %#v %v", testLogString{}, &testLogString{}, testLogString{Field: "detail"}, NewColoredValue(testLogString{}, FgRed))
  106. logger.Info("%s %s %#v %v", testLogStringPtrReceiver{}, &testLogStringPtrReceiver{}, testLogStringPtrReceiver{Field: "detail"}, NewColoredValue(testLogStringPtrReceiver{}, FgRed))
  107. logger.Close()
  108. assert.Equal(t, []string{
  109. "log-string log-string log.testLogString{Field:\"detail\"} \x1b[31mlog-string\x1b[0m\n",
  110. "log-string-ptr-receiver log-string-ptr-receiver &log.testLogStringPtrReceiver{Field:\"detail\"} \x1b[31mlog-string-ptr-receiver\x1b[0m\n",
  111. }, w1.FetchLogs())
  112. })
  113. t.Run("Caller", func(t *testing.T) {
  114. logger := NewLoggerWithWriters(t.Context(), "test")
  115. w1 := newDummyWriter("dummy-1", DEBUG, 0)
  116. w1.EventWriterBaseImpl.Mode.Flags.flags = Lmedfile | Lshortfuncname
  117. logger.AddWriters(w1)
  118. anonymousFunc := func(logger Logger) {
  119. logger.Info("from anonymousFunc")
  120. }
  121. genericFunc(logger, "123")
  122. anonymousFunc(logger)
  123. logger.Close()
  124. logs := w1.FetchLogs()
  125. assert.Len(t, logs, 2)
  126. assert.Regexp(t, `modules/log/logger_test.go:\w+:`+regexp.QuoteMeta(`genericFunc() from genericFunc: 123`), logs[0])
  127. assert.Regexp(t, `modules/log/logger_test.go:\w+:`+regexp.QuoteMeta(`TestLoggerOutput.2.1() from anonymousFunc`), logs[1])
  128. })
  129. }
  130. func TestLoggerExpressionFilter(t *testing.T) {
  131. logger := NewLoggerWithWriters(t.Context(), "test")
  132. w1 := newDummyWriter("dummy-1", DEBUG, 0)
  133. w1.Mode.Expression = "foo.*"
  134. logger.AddWriters(w1)
  135. logger.Info("foo")
  136. logger.Info("bar")
  137. logger.Info("foo bar")
  138. logger.SendLogEvent(&Event{Level: INFO, Filename: "foo.go", MsgSimpleText: "by filename"})
  139. logger.Close()
  140. assert.Equal(t, []string{"foo\n", "foo bar\n", "by filename\n"}, w1.FetchLogs())
  141. }