richlogger_test.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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 TestTraceDebug(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("foo").Start(context.Background(), "bar")
  46. defer span.End()
  47. l := WithContext(ctx)
  48. SetLevel(DebugLevel)
  49. l.WithDuration(time.Second).Debug(testlog)
  50. assert.True(t, strings.Contains(w.String(), traceKey))
  51. assert.True(t, strings.Contains(w.String(), spanKey))
  52. w.Reset()
  53. l.WithDuration(time.Second).Debugf(testlog)
  54. validate(t, w.String(), true, true)
  55. w.Reset()
  56. l.WithDuration(time.Second).Debugv(testlog)
  57. validate(t, w.String(), true, true)
  58. w.Reset()
  59. l.WithDuration(time.Second).Debugw(testlog, Field("foo", "bar"))
  60. validate(t, w.String(), true, true)
  61. assert.True(t, strings.Contains(w.String(), "foo"), w.String())
  62. assert.True(t, strings.Contains(w.String(), "bar"), w.String())
  63. }
  64. func TestTraceError(t *testing.T) {
  65. w := new(mockWriter)
  66. old := writer.Swap(w)
  67. writer.lock.RLock()
  68. defer func() {
  69. writer.lock.RUnlock()
  70. writer.Store(old)
  71. }()
  72. otp := otel.GetTracerProvider()
  73. tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
  74. otel.SetTracerProvider(tp)
  75. defer otel.SetTracerProvider(otp)
  76. ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
  77. defer span.End()
  78. var nilCtx context.Context
  79. l := WithContext(context.Background())
  80. l = l.WithContext(nilCtx)
  81. l = l.WithContext(ctx)
  82. SetLevel(ErrorLevel)
  83. l.WithDuration(time.Second).Error(testlog)
  84. validate(t, w.String(), true, true)
  85. w.Reset()
  86. l.WithDuration(time.Second).Errorf(testlog)
  87. validate(t, w.String(), true, true)
  88. w.Reset()
  89. l.WithDuration(time.Second).Errorv(testlog)
  90. validate(t, w.String(), true, true)
  91. w.Reset()
  92. l.WithDuration(time.Second).Errorw(testlog, Field("basket", "ball"))
  93. validate(t, w.String(), true, true)
  94. assert.True(t, strings.Contains(w.String(), "basket"), w.String())
  95. assert.True(t, strings.Contains(w.String(), "ball"), w.String())
  96. }
  97. func TestTraceInfo(t *testing.T) {
  98. w := new(mockWriter)
  99. old := writer.Swap(w)
  100. writer.lock.RLock()
  101. defer func() {
  102. writer.lock.RUnlock()
  103. writer.Store(old)
  104. }()
  105. otp := otel.GetTracerProvider()
  106. tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
  107. otel.SetTracerProvider(tp)
  108. defer otel.SetTracerProvider(otp)
  109. ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
  110. defer span.End()
  111. SetLevel(InfoLevel)
  112. l := WithContext(ctx)
  113. l.WithDuration(time.Second).Info(testlog)
  114. validate(t, w.String(), true, true)
  115. w.Reset()
  116. l.WithDuration(time.Second).Infof(testlog)
  117. validate(t, w.String(), true, true)
  118. w.Reset()
  119. l.WithDuration(time.Second).Infov(testlog)
  120. validate(t, w.String(), true, true)
  121. w.Reset()
  122. l.WithDuration(time.Second).Infow(testlog, Field("basket", "ball"))
  123. validate(t, w.String(), true, true)
  124. assert.True(t, strings.Contains(w.String(), "basket"), w.String())
  125. assert.True(t, strings.Contains(w.String(), "ball"), w.String())
  126. }
  127. func TestTraceInfoConsole(t *testing.T) {
  128. old := atomic.SwapUint32(&encoding, jsonEncodingType)
  129. defer atomic.StoreUint32(&encoding, old)
  130. w := new(mockWriter)
  131. o := writer.Swap(w)
  132. writer.lock.RLock()
  133. defer func() {
  134. writer.lock.RUnlock()
  135. writer.Store(o)
  136. }()
  137. otp := otel.GetTracerProvider()
  138. tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
  139. otel.SetTracerProvider(tp)
  140. defer otel.SetTracerProvider(otp)
  141. ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
  142. defer span.End()
  143. l := WithContext(ctx)
  144. SetLevel(InfoLevel)
  145. l.WithDuration(time.Second).Info(testlog)
  146. validate(t, w.String(), true, true)
  147. w.Reset()
  148. l.WithDuration(time.Second).Infof(testlog)
  149. validate(t, w.String(), true, true)
  150. w.Reset()
  151. l.WithDuration(time.Second).Infov(testlog)
  152. validate(t, w.String(), true, true)
  153. }
  154. func TestTraceSlow(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. otp := otel.GetTracerProvider()
  163. tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
  164. otel.SetTracerProvider(tp)
  165. defer otel.SetTracerProvider(otp)
  166. ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id")
  167. defer span.End()
  168. l := WithContext(ctx)
  169. SetLevel(InfoLevel)
  170. l.WithDuration(time.Second).Slow(testlog)
  171. assert.True(t, strings.Contains(w.String(), traceKey))
  172. assert.True(t, strings.Contains(w.String(), spanKey))
  173. w.Reset()
  174. l.WithDuration(time.Second).Slowf(testlog)
  175. validate(t, w.String(), true, true)
  176. w.Reset()
  177. l.WithDuration(time.Second).Slowv(testlog)
  178. validate(t, w.String(), true, true)
  179. w.Reset()
  180. l.WithDuration(time.Second).Sloww(testlog, Field("basket", "ball"))
  181. validate(t, w.String(), true, true)
  182. assert.True(t, strings.Contains(w.String(), "basket"), w.String())
  183. assert.True(t, strings.Contains(w.String(), "ball"), w.String())
  184. }
  185. func TestTraceWithoutContext(t *testing.T) {
  186. w := new(mockWriter)
  187. old := writer.Swap(w)
  188. writer.lock.RLock()
  189. defer func() {
  190. writer.lock.RUnlock()
  191. writer.Store(old)
  192. }()
  193. l := WithContext(context.Background())
  194. SetLevel(InfoLevel)
  195. l.WithDuration(time.Second).Info(testlog)
  196. validate(t, w.String(), false, false)
  197. w.Reset()
  198. l.WithDuration(time.Second).Infof(testlog)
  199. validate(t, w.String(), false, false)
  200. }
  201. func TestLogWithFields(t *testing.T) {
  202. w := new(mockWriter)
  203. old := writer.Swap(w)
  204. writer.lock.RLock()
  205. defer func() {
  206. writer.lock.RUnlock()
  207. writer.Store(old)
  208. }()
  209. ctx := ContextWithFields(context.Background(), Field("foo", "bar"))
  210. l := WithContext(ctx)
  211. SetLevel(InfoLevel)
  212. l.Info(testlog)
  213. var val mockValue
  214. assert.Nil(t, json.Unmarshal([]byte(w.String()), &val))
  215. assert.Equal(t, "bar", val.Foo)
  216. }
  217. func TestLogWithCallerSkip(t *testing.T) {
  218. w := new(mockWriter)
  219. old := writer.Swap(w)
  220. writer.lock.RLock()
  221. defer func() {
  222. writer.lock.RUnlock()
  223. writer.Store(old)
  224. }()
  225. l := WithCallerSkip(1).WithCallerSkip(0)
  226. p := func(v string) {
  227. l.Info(v)
  228. }
  229. file, line := getFileLine()
  230. p(testlog)
  231. assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
  232. w.Reset()
  233. l = WithCallerSkip(0).WithCallerSkip(1)
  234. file, line = getFileLine()
  235. p(testlog)
  236. assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
  237. }
  238. func TestLoggerWithFields(t *testing.T) {
  239. w := new(mockWriter)
  240. old := writer.Swap(w)
  241. writer.lock.RLock()
  242. defer func() {
  243. writer.lock.RUnlock()
  244. writer.Store(old)
  245. }()
  246. l := WithContext(context.Background()).WithFields(Field("foo", "bar"))
  247. l.Info(testlog)
  248. var val mockValue
  249. assert.Nil(t, json.Unmarshal([]byte(w.String()), &val))
  250. assert.Equal(t, "bar", val.Foo)
  251. }
  252. func validate(t *testing.T, body string, expectedTrace, expectedSpan bool) {
  253. var val mockValue
  254. dec := json.NewDecoder(strings.NewReader(body))
  255. for {
  256. var doc mockValue
  257. err := dec.Decode(&doc)
  258. if err == io.EOF {
  259. // all done
  260. break
  261. }
  262. if err != nil {
  263. continue
  264. }
  265. val = doc
  266. }
  267. assert.Equal(t, expectedTrace, len(val.Trace) > 0, body)
  268. assert.Equal(t, expectedSpan, len(val.Span) > 0, body)
  269. }
  270. type mockValue struct {
  271. Trace string `json:"trace"`
  272. Span string `json:"span"`
  273. Foo string `json:"foo"`
  274. }