log_test.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. package log
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "strings"
  7. "testing"
  8. "time"
  9. "github.com/rs/zerolog"
  10. "github.com/rs/zerolog/log"
  11. "github.com/spf13/viper"
  12. )
  13. func TestGetLogger(t *testing.T) {
  14. initialLogger := GetLogger()
  15. if initialLogger == nil {
  16. t.Error("GetLogger() returned nil")
  17. }
  18. secondLogger := GetLogger()
  19. if initialLogger != secondLogger {
  20. t.Error("GetLogger() returned different loggers on subsequent calls")
  21. }
  22. }
  23. func TestSetLogger(t *testing.T) {
  24. var buf bytes.Buffer
  25. newLogger := zerolog.New(&buf).With().Str("test", "value").Logger()
  26. SetLogger(&newLogger)
  27. // Log a message using the global logger
  28. Infof("Test message")
  29. // Parse the logged message
  30. loggedData := parseLogMessage(t, buf.String())
  31. // Check if the "test" field is present in the logged message
  32. if value, exists := loggedData["test"]; !exists || value != "value" {
  33. t.Error("SetLogger() did not set the logger with expected context")
  34. }
  35. }
  36. func TestLoggerConsistency(t *testing.T) {
  37. var buf bytes.Buffer
  38. newLogger := zerolog.New(&buf).With().Str("test", "consistency").Logger()
  39. SetLogger(&newLogger)
  40. // Log a message using the global logger
  41. Infof("Consistency test message")
  42. // Parse the logged message
  43. loggedData := parseLogMessage(t, buf.String())
  44. // Check if the "test" field is present in the logged message
  45. if value, exists := loggedData["test"]; !exists || value != "consistency" {
  46. t.Error("Logger inconsistency: Updated logger does not have expected context")
  47. }
  48. }
  49. func parseLogMessage(t *testing.T, logMessage string) map[string]interface{} {
  50. var loggedData map[string]interface{}
  51. if err := json.Unmarshal([]byte(strings.TrimSpace(logMessage)), &loggedData); err != nil {
  52. t.Fatalf("Failed to parse logged message: %v", err)
  53. }
  54. return loggedData
  55. }
  56. func TestInitLogging(t *testing.T) {
  57. // Save original logger and restore it after tests
  58. originalLogger := log.Logger
  59. defer func() {
  60. log.Logger = originalLogger
  61. }()
  62. // Test cases
  63. tests := []struct {
  64. name string
  65. format string
  66. level string
  67. disableColor bool
  68. showLogLevelSetMessage bool
  69. expectedLevel zerolog.Level
  70. }{
  71. {
  72. name: "default settings",
  73. format: "pretty",
  74. level: "info",
  75. disableColor: false,
  76. showLogLevelSetMessage: true,
  77. expectedLevel: zerolog.InfoLevel,
  78. },
  79. {
  80. name: "json format",
  81. format: "json",
  82. level: "debug",
  83. disableColor: false,
  84. showLogLevelSetMessage: false,
  85. expectedLevel: zerolog.DebugLevel,
  86. },
  87. {
  88. name: "invalid level",
  89. format: "pretty",
  90. level: "invalid",
  91. disableColor: false,
  92. showLogLevelSetMessage: false,
  93. expectedLevel: zerolog.InfoLevel,
  94. },
  95. }
  96. for _, tt := range tests {
  97. t.Run(tt.name, func(t *testing.T) {
  98. viper.Set(flagFormat, tt.format)
  99. viper.Set(flagLevel, tt.level)
  100. viper.Set(flagDisableColor, tt.disableColor)
  101. InitLogging(tt.showLogLevelSetMessage)
  102. if zerolog.GlobalLevel() != tt.expectedLevel {
  103. t.Errorf("expected level %v, got %v", tt.expectedLevel, zerolog.GlobalLevel())
  104. }
  105. })
  106. }
  107. }
  108. func TestLogLevelManagement(t *testing.T) {
  109. // Save original logger and restore it after tests
  110. originalLogger := log.Logger
  111. defer func() {
  112. log.Logger = originalLogger
  113. }()
  114. tests := []struct {
  115. name string
  116. level string
  117. expectError bool
  118. }{
  119. {"valid level - debug", "debug", false},
  120. {"valid level - info", "info", false},
  121. {"valid level - warn", "warn", false},
  122. {"valid level - error", "error", false},
  123. {"invalid level", "invalid", true},
  124. }
  125. for _, tt := range tests {
  126. t.Run(tt.name, func(t *testing.T) {
  127. err := SetLogLevel(tt.level)
  128. if (err != nil) != tt.expectError {
  129. t.Errorf("SetLogLevel() error = %v, expectError %v", err, tt.expectError)
  130. }
  131. if !tt.expectError {
  132. currentLevel := GetLogLevel()
  133. if currentLevel != tt.level {
  134. t.Errorf("GetLogLevel() = %v, want %v", currentLevel, tt.level)
  135. }
  136. }
  137. })
  138. }
  139. }
  140. func TestLoggingFunctions(t *testing.T) {
  141. // Create a buffer to capture log output
  142. var buf bytes.Buffer
  143. logger := zerolog.New(&buf)
  144. SetLogger(&logger)
  145. // Set log level to trace to ensure all messages are captured
  146. zerolog.SetGlobalLevel(zerolog.TraceLevel)
  147. tests := []struct {
  148. name string
  149. logFunc func(string)
  150. logMsg string
  151. expected string
  152. }{
  153. {"Error", Error, "test error", "error"},
  154. {"Warn", Warn, "test warning", "warn"},
  155. {"Info", Info, "test info", "info"},
  156. {"Debug", Debug, "test debug", "debug"},
  157. {"Trace", Trace, "test trace", "trace"},
  158. }
  159. for _, tt := range tests {
  160. t.Run(tt.name, func(t *testing.T) {
  161. buf.Reset()
  162. tt.logFunc(tt.logMsg)
  163. output := buf.String()
  164. if !strings.Contains(output, tt.expected) {
  165. t.Errorf("expected log level %s in output, got: %s", tt.expected, output)
  166. }
  167. })
  168. }
  169. // Test Fatal separately since it calls os.Exit
  170. t.Run("Fatal", func(t *testing.T) {
  171. // Create a new buffer for Fatal test
  172. var fatalBuf bytes.Buffer
  173. fatalLogger := zerolog.New(&fatalBuf)
  174. SetLogger(&fatalLogger)
  175. // We can't actually test the Fatal function since it calls os.Exit
  176. // Instead, we'll verify that the Fatal function exists by checking its type
  177. // and that it can be assigned to a variable of the correct type
  178. var fatalFunc func(string) = Fatal
  179. if fatalFunc == nil {
  180. t.Error("Fatal function is nil")
  181. }
  182. })
  183. }
  184. func TestDedupedLogging(t *testing.T) {
  185. // Create a buffer to capture log output
  186. var buf bytes.Buffer
  187. logger := zerolog.New(&buf)
  188. SetLogger(&logger)
  189. tests := []struct {
  190. name string
  191. logFunc func(int, string, ...interface{})
  192. logTypeLimit int
  193. format string
  194. args []interface{}
  195. }{
  196. {
  197. name: "DedupedErrorf",
  198. logFunc: DedupedErrorf,
  199. logTypeLimit: 3,
  200. format: "test error %d",
  201. args: []interface{}{1},
  202. },
  203. {
  204. name: "DedupedWarningf",
  205. logFunc: DedupedWarningf,
  206. logTypeLimit: 2,
  207. format: "test warning %d",
  208. args: []interface{}{1},
  209. },
  210. {
  211. name: "DedupedInfof",
  212. logFunc: DedupedInfof,
  213. logTypeLimit: 4,
  214. format: "test info %d",
  215. args: []interface{}{1},
  216. },
  217. }
  218. for _, tt := range tests {
  219. t.Run(tt.name, func(t *testing.T) {
  220. buf.Reset()
  221. // Log up to the limit
  222. for i := 0; i < tt.logTypeLimit+1; i++ {
  223. tt.logFunc(tt.logTypeLimit, tt.format, tt.args...)
  224. }
  225. output := buf.String()
  226. // Count occurrences of the exact log message (excluding the suppression message)
  227. exactMsg := fmt.Sprintf(tt.format, tt.args...)
  228. count := strings.Count(output, exactMsg) - 1 // Subtract 1 for the suppression message
  229. if count != tt.logTypeLimit {
  230. t.Errorf("expected %d occurrences of log message, got %d", tt.logTypeLimit, count)
  231. }
  232. // Verify suppression message
  233. suppressionMsg := fmt.Sprintf("%s logged %d times: suppressing future logs", exactMsg, tt.logTypeLimit)
  234. if !strings.Contains(output, suppressionMsg) {
  235. t.Error("expected suppression message in output")
  236. }
  237. })
  238. }
  239. }
  240. func TestProfiling(t *testing.T) {
  241. // Create a buffer to capture log output
  242. var buf bytes.Buffer
  243. logger := zerolog.New(&buf)
  244. SetLogger(&logger)
  245. t.Run("Profilef", func(t *testing.T) {
  246. buf.Reset()
  247. Profilef("test profile %d", 1)
  248. output := buf.String()
  249. if !strings.Contains(output, "[Profiler]") {
  250. t.Error("expected [Profiler] in output")
  251. }
  252. })
  253. t.Run("Profile", func(t *testing.T) {
  254. buf.Reset()
  255. start := time.Now()
  256. time.Sleep(10 * time.Millisecond) // Ensure some time has passed
  257. Profile(start, "test operation")
  258. output := buf.String()
  259. if !strings.Contains(output, "test operation") {
  260. t.Error("expected operation name in output")
  261. }
  262. })
  263. t.Run("ProfileWithThreshold", func(t *testing.T) {
  264. buf.Reset()
  265. start := time.Now()
  266. time.Sleep(10 * time.Millisecond)
  267. ProfileWithThreshold(start, 5*time.Millisecond, "test operation")
  268. output := buf.String()
  269. if !strings.Contains(output, "test operation") {
  270. t.Error("expected operation name in output")
  271. }
  272. // Test with threshold not exceeded
  273. buf.Reset()
  274. start = time.Now()
  275. ProfileWithThreshold(start, 100*time.Millisecond, "test operation")
  276. output = buf.String()
  277. if output != "" {
  278. t.Error("expected no output when threshold not exceeded")
  279. }
  280. })
  281. }
  282. func TestLoggerManagement(t *testing.T) {
  283. // Save original logger and restore it after tests
  284. originalLogger := log.Logger
  285. defer func() {
  286. log.Logger = originalLogger
  287. }()
  288. // Create a new logger with a unique field to identify it
  289. var buf bytes.Buffer
  290. newLogger := zerolog.New(&buf).With().Str("test_id", "unique_logger").Logger()
  291. // Test GetLogger
  292. currentLogger := GetLogger()
  293. if currentLogger == nil {
  294. t.Error("GetLogger() returned nil")
  295. }
  296. // Test SetLogger
  297. SetLogger(&newLogger)
  298. // Log a message and verify it contains our unique identifier
  299. Info("test message")
  300. output := buf.String()
  301. if !strings.Contains(output, "unique_logger") {
  302. t.Error("SetLogger() did not set the logger correctly")
  303. }
  304. }