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.

386 lines
8.9 KiB

  1. package logrus
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "strconv"
  6. "strings"
  7. "sync"
  8. "testing"
  9. "github.com/stretchr/testify/assert"
  10. )
  11. func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
  12. var buffer bytes.Buffer
  13. var fields Fields
  14. logger := New()
  15. logger.Out = &buffer
  16. logger.Formatter = new(JSONFormatter)
  17. log(logger)
  18. err := json.Unmarshal(buffer.Bytes(), &fields)
  19. assert.Nil(t, err)
  20. assertions(fields)
  21. }
  22. func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
  23. var buffer bytes.Buffer
  24. logger := New()
  25. logger.Out = &buffer
  26. logger.Formatter = &TextFormatter{
  27. DisableColors: true,
  28. }
  29. log(logger)
  30. fields := make(map[string]string)
  31. for _, kv := range strings.Split(buffer.String(), " ") {
  32. if !strings.Contains(kv, "=") {
  33. continue
  34. }
  35. kvArr := strings.Split(kv, "=")
  36. key := strings.TrimSpace(kvArr[0])
  37. val := kvArr[1]
  38. if kvArr[1][0] == '"' {
  39. var err error
  40. val, err = strconv.Unquote(val)
  41. assert.NoError(t, err)
  42. }
  43. fields[key] = val
  44. }
  45. assertions(fields)
  46. }
  47. func TestPrint(t *testing.T) {
  48. LogAndAssertJSON(t, func(log *Logger) {
  49. log.Print("test")
  50. }, func(fields Fields) {
  51. assert.Equal(t, fields["msg"], "test")
  52. assert.Equal(t, fields["level"], "info")
  53. })
  54. }
  55. func TestInfo(t *testing.T) {
  56. LogAndAssertJSON(t, func(log *Logger) {
  57. log.Info("test")
  58. }, func(fields Fields) {
  59. assert.Equal(t, fields["msg"], "test")
  60. assert.Equal(t, fields["level"], "info")
  61. })
  62. }
  63. func TestWarn(t *testing.T) {
  64. LogAndAssertJSON(t, func(log *Logger) {
  65. log.Warn("test")
  66. }, func(fields Fields) {
  67. assert.Equal(t, fields["msg"], "test")
  68. assert.Equal(t, fields["level"], "warning")
  69. })
  70. }
  71. func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
  72. LogAndAssertJSON(t, func(log *Logger) {
  73. log.Infoln("test", "test")
  74. }, func(fields Fields) {
  75. assert.Equal(t, fields["msg"], "test test")
  76. })
  77. }
  78. func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
  79. LogAndAssertJSON(t, func(log *Logger) {
  80. log.Infoln("test", 10)
  81. }, func(fields Fields) {
  82. assert.Equal(t, fields["msg"], "test 10")
  83. })
  84. }
  85. func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
  86. LogAndAssertJSON(t, func(log *Logger) {
  87. log.Infoln(10, 10)
  88. }, func(fields Fields) {
  89. assert.Equal(t, fields["msg"], "10 10")
  90. })
  91. }
  92. func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
  93. LogAndAssertJSON(t, func(log *Logger) {
  94. log.Infoln(10, 10)
  95. }, func(fields Fields) {
  96. assert.Equal(t, fields["msg"], "10 10")
  97. })
  98. }
  99. func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
  100. LogAndAssertJSON(t, func(log *Logger) {
  101. log.Info("test", 10)
  102. }, func(fields Fields) {
  103. assert.Equal(t, fields["msg"], "test10")
  104. })
  105. }
  106. func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
  107. LogAndAssertJSON(t, func(log *Logger) {
  108. log.Info("test", "test")
  109. }, func(fields Fields) {
  110. assert.Equal(t, fields["msg"], "testtest")
  111. })
  112. }
  113. func TestWithFieldsShouldAllowAssignments(t *testing.T) {
  114. var buffer bytes.Buffer
  115. var fields Fields
  116. logger := New()
  117. logger.Out = &buffer
  118. logger.Formatter = new(JSONFormatter)
  119. localLog := logger.WithFields(Fields{
  120. "key1": "value1",
  121. })
  122. localLog.WithField("key2", "value2").Info("test")
  123. err := json.Unmarshal(buffer.Bytes(), &fields)
  124. assert.Nil(t, err)
  125. assert.Equal(t, "value2", fields["key2"])
  126. assert.Equal(t, "value1", fields["key1"])
  127. buffer = bytes.Buffer{}
  128. fields = Fields{}
  129. localLog.Info("test")
  130. err = json.Unmarshal(buffer.Bytes(), &fields)
  131. assert.Nil(t, err)
  132. _, ok := fields["key2"]
  133. assert.Equal(t, false, ok)
  134. assert.Equal(t, "value1", fields["key1"])
  135. }
  136. func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
  137. LogAndAssertJSON(t, func(log *Logger) {
  138. log.WithField("msg", "hello").Info("test")
  139. }, func(fields Fields) {
  140. assert.Equal(t, fields["msg"], "test")
  141. })
  142. }
  143. func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
  144. LogAndAssertJSON(t, func(log *Logger) {
  145. log.WithField("msg", "hello").Info("test")
  146. }, func(fields Fields) {
  147. assert.Equal(t, fields["msg"], "test")
  148. assert.Equal(t, fields["fields.msg"], "hello")
  149. })
  150. }
  151. func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
  152. LogAndAssertJSON(t, func(log *Logger) {
  153. log.WithField("time", "hello").Info("test")
  154. }, func(fields Fields) {
  155. assert.Equal(t, fields["fields.time"], "hello")
  156. })
  157. }
  158. func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
  159. LogAndAssertJSON(t, func(log *Logger) {
  160. log.WithField("level", 1).Info("test")
  161. }, func(fields Fields) {
  162. assert.Equal(t, fields["level"], "info")
  163. assert.Equal(t, fields["fields.level"], 1.0) // JSON has floats only
  164. })
  165. }
  166. func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
  167. LogAndAssertText(t, func(log *Logger) {
  168. ll := log.WithField("herp", "derp")
  169. ll.Info("hello")
  170. ll.Info("bye")
  171. }, func(fields map[string]string) {
  172. for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
  173. if _, ok := fields[fieldName]; ok {
  174. t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
  175. }
  176. }
  177. })
  178. }
  179. func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
  180. var buffer bytes.Buffer
  181. var fields Fields
  182. logger := New()
  183. logger.Out = &buffer
  184. logger.Formatter = new(JSONFormatter)
  185. llog := logger.WithField("context", "eating raw fish")
  186. llog.Info("looks delicious")
  187. err := json.Unmarshal(buffer.Bytes(), &fields)
  188. assert.NoError(t, err, "should have decoded first message")
  189. assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
  190. assert.Equal(t, fields["msg"], "looks delicious")
  191. assert.Equal(t, fields["context"], "eating raw fish")
  192. buffer.Reset()
  193. llog.Warn("omg it is!")
  194. err = json.Unmarshal(buffer.Bytes(), &fields)
  195. assert.NoError(t, err, "should have decoded second message")
  196. assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
  197. assert.Equal(t, fields["msg"], "omg it is!")
  198. assert.Equal(t, fields["context"], "eating raw fish")
  199. assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
  200. }
  201. func TestConvertLevelToString(t *testing.T) {
  202. assert.Equal(t, "debug", DebugLevel.String())
  203. assert.Equal(t, "info", InfoLevel.String())
  204. assert.Equal(t, "warning", WarnLevel.String())
  205. assert.Equal(t, "error", ErrorLevel.String())
  206. assert.Equal(t, "fatal", FatalLevel.String())
  207. assert.Equal(t, "panic", PanicLevel.String())
  208. }
  209. func TestParseLevel(t *testing.T) {
  210. l, err := ParseLevel("panic")
  211. assert.Nil(t, err)
  212. assert.Equal(t, PanicLevel, l)
  213. l, err = ParseLevel("PANIC")
  214. assert.Nil(t, err)
  215. assert.Equal(t, PanicLevel, l)
  216. l, err = ParseLevel("fatal")
  217. assert.Nil(t, err)
  218. assert.Equal(t, FatalLevel, l)
  219. l, err = ParseLevel("FATAL")
  220. assert.Nil(t, err)
  221. assert.Equal(t, FatalLevel, l)
  222. l, err = ParseLevel("error")
  223. assert.Nil(t, err)
  224. assert.Equal(t, ErrorLevel, l)
  225. l, err = ParseLevel("ERROR")
  226. assert.Nil(t, err)
  227. assert.Equal(t, ErrorLevel, l)
  228. l, err = ParseLevel("warn")
  229. assert.Nil(t, err)
  230. assert.Equal(t, WarnLevel, l)
  231. l, err = ParseLevel("WARN")
  232. assert.Nil(t, err)
  233. assert.Equal(t, WarnLevel, l)
  234. l, err = ParseLevel("warning")
  235. assert.Nil(t, err)
  236. assert.Equal(t, WarnLevel, l)
  237. l, err = ParseLevel("WARNING")
  238. assert.Nil(t, err)
  239. assert.Equal(t, WarnLevel, l)
  240. l, err = ParseLevel("info")
  241. assert.Nil(t, err)
  242. assert.Equal(t, InfoLevel, l)
  243. l, err = ParseLevel("INFO")
  244. assert.Nil(t, err)
  245. assert.Equal(t, InfoLevel, l)
  246. l, err = ParseLevel("debug")
  247. assert.Nil(t, err)
  248. assert.Equal(t, DebugLevel, l)
  249. l, err = ParseLevel("DEBUG")
  250. assert.Nil(t, err)
  251. assert.Equal(t, DebugLevel, l)
  252. l, err = ParseLevel("invalid")
  253. assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
  254. }
  255. func TestGetSetLevelRace(t *testing.T) {
  256. wg := sync.WaitGroup{}
  257. for i := 0; i < 100; i++ {
  258. wg.Add(1)
  259. go func(i int) {
  260. defer wg.Done()
  261. if i%2 == 0 {
  262. SetLevel(InfoLevel)
  263. } else {
  264. GetLevel()
  265. }
  266. }(i)
  267. }
  268. wg.Wait()
  269. }
  270. func TestLoggingRace(t *testing.T) {
  271. logger := New()
  272. var wg sync.WaitGroup
  273. wg.Add(100)
  274. for i := 0; i < 100; i++ {
  275. go func() {
  276. logger.Info("info")
  277. wg.Done()
  278. }()
  279. }
  280. wg.Wait()
  281. }
  282. // Compile test
  283. func TestLogrusInterface(t *testing.T) {
  284. var buffer bytes.Buffer
  285. fn := func(l FieldLogger) {
  286. b := l.WithField("key", "value")
  287. b.Debug("Test")
  288. }
  289. // test logger
  290. logger := New()
  291. logger.Out = &buffer
  292. fn(logger)
  293. // test Entry
  294. e := logger.WithField("another", "value")
  295. fn(e)
  296. }
  297. // Implements io.Writer using channels for synchronization, so we can wait on
  298. // the Entry.Writer goroutine to write in a non-racey way. This does assume that
  299. // there is a single call to Logger.Out for each message.
  300. type channelWriter chan []byte
  301. func (cw channelWriter) Write(p []byte) (int, error) {
  302. cw <- p
  303. return len(p), nil
  304. }
  305. func TestEntryWriter(t *testing.T) {
  306. cw := channelWriter(make(chan []byte, 1))
  307. log := New()
  308. log.Out = cw
  309. log.Formatter = new(JSONFormatter)
  310. log.WithField("foo", "bar").WriterLevel(WarnLevel).Write([]byte("hello\n"))
  311. bs := <-cw
  312. var fields Fields
  313. err := json.Unmarshal(bs, &fields)
  314. assert.Nil(t, err)
  315. assert.Equal(t, fields["foo"], "bar")
  316. assert.Equal(t, fields["level"], "warning")
  317. }