richlogger_test.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. package logx
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "strings"
  8. "sync/atomic"
  9. "testing"
  10. "time"
  11. "github.com/stretchr/testify/assert"
  12. "go.opentelemetry.io/otel"
  13. sdktrace "go.opentelemetry.io/otel/sdk/trace"
  14. )
  15. func TestTraceLog(t *testing.T) {
  16. SetLevel(InfoLevel)
  17. w := new(mockWriter)
  18. old := writer.Swap(w)
  19. writer.lock.RLock()
  20. defer func() {
  21. writer.lock.RUnlock()
  22. writer.Store(old)
  23. }()
  24. otp := otel.GetTracerProvider()
  25. tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
  26. otel.SetTracerProvider(tp)
  27. defer otel.SetTracerProvider(otp)
  28. ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
  29. defer span.End()
  30. WithContext(ctx).Info(testlog)
  31. validate(t, w.String(), true, true)
  32. }
  33. func TestTraceError(t *testing.T) {
  34. w := new(mockWriter)
  35. old := writer.Swap(w)
  36. writer.lock.RLock()
  37. defer func() {
  38. writer.lock.RUnlock()
  39. writer.Store(old)
  40. }()
  41. otp := otel.GetTracerProvider()
  42. tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
  43. otel.SetTracerProvider(tp)
  44. defer otel.SetTracerProvider(otp)
  45. ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
  46. defer span.End()
  47. var nilCtx context.Context
  48. l := WithContext(context.Background())
  49. l = l.WithContext(nilCtx)
  50. l = l.WithContext(ctx)
  51. SetLevel(ErrorLevel)
  52. l.WithDuration(time.Second).Error(testlog)
  53. validate(t, w.String(), true, true)
  54. w.Reset()
  55. l.WithDuration(time.Second).Errorf(testlog)
  56. validate(t, w.String(), true, true)
  57. w.Reset()
  58. l.WithDuration(time.Second).Errorv(testlog)
  59. validate(t, w.String(), true, true)
  60. w.Reset()
  61. l.WithDuration(time.Second).Errorw(testlog, Field("basket", "ball"))
  62. validate(t, w.String(), true, true)
  63. assert.True(t, strings.Contains(w.String(), "basket"), w.String())
  64. assert.True(t, strings.Contains(w.String(), "ball"), w.String())
  65. }
  66. func TestTraceInfo(t *testing.T) {
  67. w := new(mockWriter)
  68. old := writer.Swap(w)
  69. writer.lock.RLock()
  70. defer func() {
  71. writer.lock.RUnlock()
  72. writer.Store(old)
  73. }()
  74. otp := otel.GetTracerProvider()
  75. tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
  76. otel.SetTracerProvider(tp)
  77. defer otel.SetTracerProvider(otp)
  78. ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
  79. defer span.End()
  80. SetLevel(InfoLevel)
  81. l := WithContext(ctx)
  82. l.WithDuration(time.Second).Info(testlog)
  83. validate(t, w.String(), true, true)
  84. w.Reset()
  85. l.WithDuration(time.Second).Infof(testlog)
  86. validate(t, w.String(), true, true)
  87. w.Reset()
  88. l.WithDuration(time.Second).Infov(testlog)
  89. validate(t, w.String(), true, true)
  90. w.Reset()
  91. l.WithDuration(time.Second).Infow(testlog, Field("basket", "ball"))
  92. validate(t, w.String(), true, true)
  93. assert.True(t, strings.Contains(w.String(), "basket"), w.String())
  94. assert.True(t, strings.Contains(w.String(), "ball"), w.String())
  95. }
  96. func TestTraceInfoConsole(t *testing.T) {
  97. old := atomic.SwapUint32(&encoding, jsonEncodingType)
  98. defer atomic.StoreUint32(&encoding, old)
  99. w := new(mockWriter)
  100. o := writer.Swap(w)
  101. writer.lock.RLock()
  102. defer func() {
  103. writer.lock.RUnlock()
  104. writer.Store(o)
  105. }()
  106. otp := otel.GetTracerProvider()
  107. tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
  108. otel.SetTracerProvider(tp)
  109. defer otel.SetTracerProvider(otp)
  110. ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
  111. defer span.End()
  112. l := WithContext(ctx)
  113. SetLevel(InfoLevel)
  114. l.WithDuration(time.Second).Info(testlog)
  115. validate(t, w.String(), true, true)
  116. w.Reset()
  117. l.WithDuration(time.Second).Infof(testlog)
  118. validate(t, w.String(), true, true)
  119. w.Reset()
  120. l.WithDuration(time.Second).Infov(testlog)
  121. validate(t, w.String(), true, true)
  122. }
  123. func TestTraceSlow(t *testing.T) {
  124. w := new(mockWriter)
  125. old := writer.Swap(w)
  126. writer.lock.RLock()
  127. defer func() {
  128. writer.lock.RUnlock()
  129. writer.Store(old)
  130. }()
  131. otp := otel.GetTracerProvider()
  132. tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
  133. otel.SetTracerProvider(tp)
  134. defer otel.SetTracerProvider(otp)
  135. ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
  136. defer span.End()
  137. l := WithContext(ctx)
  138. SetLevel(InfoLevel)
  139. l.WithDuration(time.Second).Slow(testlog)
  140. assert.True(t, strings.Contains(w.String(), traceKey))
  141. assert.True(t, strings.Contains(w.String(), spanKey))
  142. w.Reset()
  143. l.WithDuration(time.Second).Slowf(testlog)
  144. validate(t, w.String(), true, true)
  145. w.Reset()
  146. l.WithDuration(time.Second).Slowv(testlog)
  147. validate(t, w.String(), true, true)
  148. w.Reset()
  149. l.WithDuration(time.Second).Sloww(testlog, Field("basket", "ball"))
  150. validate(t, w.String(), true, true)
  151. assert.True(t, strings.Contains(w.String(), "basket"), w.String())
  152. assert.True(t, strings.Contains(w.String(), "ball"), w.String())
  153. }
  154. func TestTraceWithoutContext(t *testing.T) {
  155. w := new(mockWriter)
  156. old := writer.Swap(w)
  157. writer.lock.RLock()
  158. defer func() {
  159. writer.lock.RUnlock()
  160. writer.Store(old)
  161. }()
  162. l := WithContext(context.Background())
  163. SetLevel(InfoLevel)
  164. l.WithDuration(time.Second).Info(testlog)
  165. validate(t, w.String(), false, false)
  166. w.Reset()
  167. l.WithDuration(time.Second).Infof(testlog)
  168. validate(t, w.String(), false, false)
  169. }
  170. func TestLogWithFields(t *testing.T) {
  171. w := new(mockWriter)
  172. old := writer.Swap(w)
  173. writer.lock.RLock()
  174. defer func() {
  175. writer.lock.RUnlock()
  176. writer.Store(old)
  177. }()
  178. ctx := ContextWithFields(context.Background(), Field("foo", "bar"))
  179. l := WithContext(ctx)
  180. SetLevel(InfoLevel)
  181. l.Info(testlog)
  182. var val mockValue
  183. assert.Nil(t, json.Unmarshal([]byte(w.String()), &val))
  184. assert.Equal(t, "bar", val.Foo)
  185. }
  186. func TestLogWithCallerSkip(t *testing.T) {
  187. w := new(mockWriter)
  188. old := writer.Swap(w)
  189. writer.lock.RLock()
  190. defer func() {
  191. writer.lock.RUnlock()
  192. writer.Store(old)
  193. }()
  194. l := WithCallerSkip(1).WithCallerSkip(0)
  195. p := func(v string) {
  196. l.Info(v)
  197. }
  198. file, line := getFileLine()
  199. p(testlog)
  200. assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
  201. w.Reset()
  202. l = WithCallerSkip(0).WithCallerSkip(1)
  203. file, line = getFileLine()
  204. p(testlog)
  205. assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
  206. }
  207. func validate(t *testing.T, body string, expectedTrace, expectedSpan bool) {
  208. var val mockValue
  209. dec := json.NewDecoder(strings.NewReader(body))
  210. for {
  211. var doc mockValue
  212. err := dec.Decode(&doc)
  213. if err == io.EOF {
  214. // all done
  215. break
  216. }
  217. if err != nil {
  218. continue
  219. }
  220. val = doc
  221. }
  222. assert.Equal(t, expectedTrace, len(val.Trace) > 0, body)
  223. assert.Equal(t, expectedSpan, len(val.Span) > 0, body)
  224. }
  225. type mockValue struct {
  226. Trace string `json:"trace"`
  227. Span string `json:"span"`
  228. Foo string `json:"foo"`
  229. }