log_test.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. package log
  2. import (
  3. "bytes"
  4. "github.com/stretchr/testify/require"
  5. "os"
  6. "testing"
  7. "time"
  8. )
  9. func TestMain(m *testing.M) {
  10. exitCode := m.Run()
  11. resetState()
  12. SetLevel(ErrorLevel) // For other modules!
  13. os.Exit(exitCode)
  14. }
  15. func TestLog_TagContextFieldFields(t *testing.T) {
  16. t.Cleanup(resetState)
  17. v := &fakeVisitor{
  18. UserID: "u_abc",
  19. IP: "1.2.3.4",
  20. }
  21. err := &fakeError{
  22. Code: 123,
  23. Message: "some error",
  24. }
  25. var out bytes.Buffer
  26. SetOutput(&out)
  27. SetFormat(JSONFormat)
  28. SetLevelOverride("tag", "stripe", DebugLevel)
  29. Tag("mytag").
  30. Field("field2", 123).
  31. Field("field1", "value1").
  32. Time(time.Unix(123, 999000000).UTC()).
  33. Info("hi there %s", "phil")
  34. Tag("not-stripe").
  35. Debug("this message will not appear")
  36. With(v).
  37. Fields(Context{
  38. "stripe_customer_id": "acct_123",
  39. "stripe_subscription_id": "sub_123",
  40. }).
  41. Tag("stripe").
  42. Err(err).
  43. Time(time.Unix(456, 123000000).UTC()).
  44. Debug("Subscription status %s", "active")
  45. expected := `{"time":"1970-01-01T00:02:03.999Z","level":"INFO","message":"hi there phil","field1":"value1","field2":123,"tag":"mytag"}
  46. {"time":"1970-01-01T00:07:36.123Z","level":"DEBUG","message":"Subscription status active","error":"some error","error_code":123,"stripe_customer_id":"acct_123","stripe_subscription_id":"sub_123","tag":"stripe","user_id":"u_abc","visitor_ip":"1.2.3.4"}
  47. `
  48. require.Equal(t, expected, out.String())
  49. }
  50. func TestLog_NoAllocIfNotPrinted(t *testing.T) {
  51. t.Cleanup(resetState)
  52. v := &fakeVisitor{
  53. UserID: "u_abc",
  54. IP: "1.2.3.4",
  55. }
  56. var out bytes.Buffer
  57. SetOutput(&out)
  58. SetFormat(JSONFormat)
  59. // Do not log, do not call contexters (because global level is INFO)
  60. v.contextCalled = false
  61. ev := With(v)
  62. ev.Debug("some message")
  63. require.False(t, v.contextCalled)
  64. require.Equal(t, "", ev.Timestamp)
  65. require.Equal(t, Level(0), ev.Level)
  66. require.Equal(t, "", ev.Message)
  67. require.Nil(t, ev.fields)
  68. // Logged because info level, contexters called
  69. v.contextCalled = false
  70. ev = With(v).Time(time.Unix(1111, 0).UTC())
  71. ev.Info("some message")
  72. require.True(t, v.contextCalled)
  73. require.NotNil(t, ev.fields)
  74. require.Equal(t, "1.2.3.4", ev.fields["visitor_ip"])
  75. // Not logged, but contexters called, because overrides exist
  76. SetLevel(DebugLevel)
  77. SetLevelOverride("tag", "overridetag", TraceLevel)
  78. v.contextCalled = false
  79. ev = Tag("sometag").Field("field", "value").With(v).Time(time.Unix(123, 0).UTC())
  80. ev.Trace("some debug message")
  81. require.True(t, v.contextCalled) // If there are overrides, we must call the context to determine the filter fields
  82. require.Equal(t, "", ev.Timestamp)
  83. require.Equal(t, Level(0), ev.Level)
  84. require.Equal(t, "", ev.Message)
  85. require.Equal(t, 4, len(ev.fields))
  86. require.Equal(t, "value", ev.fields["field"])
  87. require.Equal(t, "sometag", ev.fields["tag"])
  88. // Logged because of override tag, and contexters called
  89. v.contextCalled = false
  90. ev = Tag("overridetag").Field("field", "value").With(v).Time(time.Unix(123, 0).UTC())
  91. ev.Trace("some trace message")
  92. require.True(t, v.contextCalled)
  93. require.Equal(t, "1970-01-01T00:02:03Z", ev.Timestamp)
  94. require.Equal(t, TraceLevel, ev.Level)
  95. require.Equal(t, "some trace message", ev.Message)
  96. // Logged because of field override, and contexters called
  97. ResetLevelOverrides()
  98. SetLevelOverride("visitor_ip", "1.2.3.4", TraceLevel)
  99. v.contextCalled = false
  100. ev = With(v).Time(time.Unix(124, 0).UTC())
  101. ev.Trace("some trace message with override")
  102. require.True(t, v.contextCalled)
  103. require.Equal(t, "1970-01-01T00:02:04Z", ev.Timestamp)
  104. require.Equal(t, TraceLevel, ev.Level)
  105. require.Equal(t, "some trace message with override", ev.Message)
  106. expected := `{"time":"1970-01-01T00:18:31Z","level":"INFO","message":"some message","user_id":"u_abc","visitor_ip":"1.2.3.4"}
  107. {"time":"1970-01-01T00:02:03Z","level":"TRACE","message":"some trace message","field":"value","tag":"overridetag","user_id":"u_abc","visitor_ip":"1.2.3.4"}
  108. {"time":"1970-01-01T00:02:04Z","level":"TRACE","message":"some trace message with override","user_id":"u_abc","visitor_ip":"1.2.3.4"}
  109. `
  110. require.Equal(t, expected, out.String())
  111. }
  112. type fakeError struct {
  113. Code int
  114. Message string
  115. }
  116. func (e fakeError) Error() string {
  117. return e.Message
  118. }
  119. func (e fakeError) Context() Context {
  120. return Context{
  121. "error": e.Message,
  122. "error_code": e.Code,
  123. }
  124. }
  125. type fakeVisitor struct {
  126. UserID string
  127. IP string
  128. contextCalled bool
  129. }
  130. func (v *fakeVisitor) Context() Context {
  131. v.contextCalled = true
  132. return Context{
  133. "user_id": v.UserID,
  134. "visitor_ip": v.IP,
  135. }
  136. }
  137. func resetState() {
  138. SetLevel(DefaultLevel)
  139. SetFormat(DefaultFormat)
  140. SetOutput(DefaultOutput)
  141. ResetLevelOverrides()
  142. }