logs_test.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. package logx
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "log"
  8. "os"
  9. "reflect"
  10. "runtime"
  11. "strings"
  12. "sync"
  13. "sync/atomic"
  14. "testing"
  15. "time"
  16. "github.com/stretchr/testify/assert"
  17. )
  18. var (
  19. s = []byte("Sending #11 notification (id: 1451875113812010473) in #1 connection")
  20. pool = make(chan []byte, 1)
  21. _ Writer = (*mockWriter)(nil)
  22. )
  23. type mockWriter struct {
  24. lock sync.Mutex
  25. builder strings.Builder
  26. }
  27. func (mw *mockWriter) Alert(v interface{}) {
  28. mw.lock.Lock()
  29. defer mw.lock.Unlock()
  30. output(&mw.builder, levelAlert, v)
  31. }
  32. func (mw *mockWriter) Error(v interface{}, fields ...LogField) {
  33. mw.lock.Lock()
  34. defer mw.lock.Unlock()
  35. output(&mw.builder, levelError, v, fields...)
  36. }
  37. func (mw *mockWriter) Info(v interface{}, fields ...LogField) {
  38. mw.lock.Lock()
  39. defer mw.lock.Unlock()
  40. output(&mw.builder, levelInfo, v, fields...)
  41. }
  42. func (mw *mockWriter) Severe(v interface{}) {
  43. mw.lock.Lock()
  44. defer mw.lock.Unlock()
  45. output(&mw.builder, levelSevere, v)
  46. }
  47. func (mw *mockWriter) Slow(v interface{}, fields ...LogField) {
  48. mw.lock.Lock()
  49. defer mw.lock.Unlock()
  50. output(&mw.builder, levelSlow, v, fields...)
  51. }
  52. func (mw *mockWriter) Stack(v interface{}) {
  53. mw.lock.Lock()
  54. defer mw.lock.Unlock()
  55. output(&mw.builder, levelError, v)
  56. }
  57. func (mw *mockWriter) Stat(v interface{}, fields ...LogField) {
  58. mw.lock.Lock()
  59. defer mw.lock.Unlock()
  60. output(&mw.builder, levelStat, v, fields...)
  61. }
  62. func (mw *mockWriter) Close() error {
  63. return nil
  64. }
  65. func (mw *mockWriter) Contains(text string) bool {
  66. mw.lock.Lock()
  67. defer mw.lock.Unlock()
  68. return strings.Contains(mw.builder.String(), text)
  69. }
  70. func (mw *mockWriter) Reset() {
  71. mw.lock.Lock()
  72. defer mw.lock.Unlock()
  73. mw.builder.Reset()
  74. }
  75. func (mw *mockWriter) String() string {
  76. mw.lock.Lock()
  77. defer mw.lock.Unlock()
  78. return mw.builder.String()
  79. }
  80. func TestField(t *testing.T) {
  81. tests := []struct {
  82. name string
  83. f LogField
  84. want map[string]interface{}
  85. }{
  86. {
  87. name: "error",
  88. f: Field("foo", errors.New("bar")),
  89. want: map[string]interface{}{
  90. "foo": "bar",
  91. },
  92. },
  93. {
  94. name: "errors",
  95. f: Field("foo", []error{errors.New("bar"), errors.New("baz")}),
  96. want: map[string]interface{}{
  97. "foo": []interface{}{"bar", "baz"},
  98. },
  99. },
  100. {
  101. name: "strings",
  102. f: Field("foo", []string{"bar", "baz"}),
  103. want: map[string]interface{}{
  104. "foo": []interface{}{"bar", "baz"},
  105. },
  106. },
  107. {
  108. name: "duration",
  109. f: Field("foo", time.Second),
  110. want: map[string]interface{}{
  111. "foo": "1s",
  112. },
  113. },
  114. {
  115. name: "durations",
  116. f: Field("foo", []time.Duration{time.Second, 2 * time.Second}),
  117. want: map[string]interface{}{
  118. "foo": []interface{}{"1s", "2s"},
  119. },
  120. },
  121. {
  122. name: "times",
  123. f: Field("foo", []time.Time{
  124. time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC),
  125. time.Date(2020, time.January, 2, 0, 0, 0, 0, time.UTC),
  126. }),
  127. want: map[string]interface{}{
  128. "foo": []interface{}{"2020-01-01 00:00:00 +0000 UTC", "2020-01-02 00:00:00 +0000 UTC"},
  129. },
  130. },
  131. {
  132. name: "stringer",
  133. f: Field("foo", ValStringer{val: "bar"}),
  134. want: map[string]interface{}{
  135. "foo": "bar",
  136. },
  137. },
  138. {
  139. name: "stringers",
  140. f: Field("foo", []fmt.Stringer{ValStringer{val: "bar"}, ValStringer{val: "baz"}}),
  141. want: map[string]interface{}{
  142. "foo": []interface{}{"bar", "baz"},
  143. },
  144. },
  145. }
  146. for _, test := range tests {
  147. test := test
  148. t.Run(test.name, func(t *testing.T) {
  149. w := new(mockWriter)
  150. old := writer.Swap(w)
  151. defer writer.Store(old)
  152. Infow("foo", test.f)
  153. validateFields(t, w.String(), test.want)
  154. })
  155. }
  156. }
  157. func TestFileLineFileMode(t *testing.T) {
  158. w := new(mockWriter)
  159. old := writer.Swap(w)
  160. defer writer.Store(old)
  161. file, line := getFileLine()
  162. Error("anything")
  163. assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
  164. file, line = getFileLine()
  165. Errorf("anything %s", "format")
  166. assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
  167. }
  168. func TestFileLineConsoleMode(t *testing.T) {
  169. w := new(mockWriter)
  170. old := writer.Swap(w)
  171. defer writer.Store(old)
  172. file, line := getFileLine()
  173. Error("anything")
  174. assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
  175. w.Reset()
  176. file, line = getFileLine()
  177. Errorf("anything %s", "format")
  178. assert.True(t, w.Contains(fmt.Sprintf("%s:%d", file, line+1)))
  179. }
  180. func TestStructedLogAlert(t *testing.T) {
  181. w := new(mockWriter)
  182. old := writer.Swap(w)
  183. defer writer.Store(old)
  184. doTestStructedLog(t, levelAlert, w, func(v ...interface{}) {
  185. Alert(fmt.Sprint(v...))
  186. })
  187. }
  188. func TestStructedLogError(t *testing.T) {
  189. w := new(mockWriter)
  190. old := writer.Swap(w)
  191. defer writer.Store(old)
  192. doTestStructedLog(t, levelError, w, func(v ...interface{}) {
  193. Error(v...)
  194. })
  195. }
  196. func TestStructedLogErrorf(t *testing.T) {
  197. w := new(mockWriter)
  198. old := writer.Swap(w)
  199. defer writer.Store(old)
  200. doTestStructedLog(t, levelError, w, func(v ...interface{}) {
  201. Errorf("%s", fmt.Sprint(v...))
  202. })
  203. }
  204. func TestStructedLogErrorv(t *testing.T) {
  205. w := new(mockWriter)
  206. old := writer.Swap(w)
  207. defer writer.Store(old)
  208. doTestStructedLog(t, levelError, w, func(v ...interface{}) {
  209. Errorv(fmt.Sprint(v...))
  210. })
  211. }
  212. func TestStructedLogErrorw(t *testing.T) {
  213. w := new(mockWriter)
  214. old := writer.Swap(w)
  215. defer writer.Store(old)
  216. doTestStructedLog(t, levelError, w, func(v ...interface{}) {
  217. Errorw(fmt.Sprint(v...), Field("foo", "bar"))
  218. })
  219. }
  220. func TestStructedLogInfo(t *testing.T) {
  221. w := new(mockWriter)
  222. old := writer.Swap(w)
  223. defer writer.Store(old)
  224. doTestStructedLog(t, levelInfo, w, func(v ...interface{}) {
  225. Info(v...)
  226. })
  227. }
  228. func TestStructedLogInfof(t *testing.T) {
  229. w := new(mockWriter)
  230. old := writer.Swap(w)
  231. defer writer.Store(old)
  232. doTestStructedLog(t, levelInfo, w, func(v ...interface{}) {
  233. Infof("%s", fmt.Sprint(v...))
  234. })
  235. }
  236. func TestStructedLogInfov(t *testing.T) {
  237. w := new(mockWriter)
  238. old := writer.Swap(w)
  239. defer writer.Store(old)
  240. doTestStructedLog(t, levelInfo, w, func(v ...interface{}) {
  241. Infov(fmt.Sprint(v...))
  242. })
  243. }
  244. func TestStructedLogInfow(t *testing.T) {
  245. w := new(mockWriter)
  246. old := writer.Swap(w)
  247. defer writer.Store(old)
  248. doTestStructedLog(t, levelInfo, w, func(v ...interface{}) {
  249. Infow(fmt.Sprint(v...), Field("foo", "bar"))
  250. })
  251. }
  252. func TestStructedLogInfoConsoleAny(t *testing.T) {
  253. w := new(mockWriter)
  254. old := writer.Swap(w)
  255. defer writer.Store(old)
  256. doTestStructedLogConsole(t, w, func(v ...interface{}) {
  257. old := atomic.LoadUint32(&encoding)
  258. atomic.StoreUint32(&encoding, plainEncodingType)
  259. defer func() {
  260. atomic.StoreUint32(&encoding, old)
  261. }()
  262. Infov(v)
  263. })
  264. }
  265. func TestStructedLogInfoConsoleAnyString(t *testing.T) {
  266. w := new(mockWriter)
  267. old := writer.Swap(w)
  268. defer writer.Store(old)
  269. doTestStructedLogConsole(t, w, func(v ...interface{}) {
  270. old := atomic.LoadUint32(&encoding)
  271. atomic.StoreUint32(&encoding, plainEncodingType)
  272. defer func() {
  273. atomic.StoreUint32(&encoding, old)
  274. }()
  275. Infov(fmt.Sprint(v...))
  276. })
  277. }
  278. func TestStructedLogInfoConsoleAnyError(t *testing.T) {
  279. w := new(mockWriter)
  280. old := writer.Swap(w)
  281. defer writer.Store(old)
  282. doTestStructedLogConsole(t, w, func(v ...interface{}) {
  283. old := atomic.LoadUint32(&encoding)
  284. atomic.StoreUint32(&encoding, plainEncodingType)
  285. defer func() {
  286. atomic.StoreUint32(&encoding, old)
  287. }()
  288. Infov(errors.New(fmt.Sprint(v...)))
  289. })
  290. }
  291. func TestStructedLogInfoConsoleAnyStringer(t *testing.T) {
  292. w := new(mockWriter)
  293. old := writer.Swap(w)
  294. defer writer.Store(old)
  295. doTestStructedLogConsole(t, w, func(v ...interface{}) {
  296. old := atomic.LoadUint32(&encoding)
  297. atomic.StoreUint32(&encoding, plainEncodingType)
  298. defer func() {
  299. atomic.StoreUint32(&encoding, old)
  300. }()
  301. Infov(ValStringer{
  302. val: fmt.Sprint(v...),
  303. })
  304. })
  305. }
  306. func TestStructedLogInfoConsoleText(t *testing.T) {
  307. w := new(mockWriter)
  308. old := writer.Swap(w)
  309. defer writer.Store(old)
  310. doTestStructedLogConsole(t, w, func(v ...interface{}) {
  311. old := atomic.LoadUint32(&encoding)
  312. atomic.StoreUint32(&encoding, plainEncodingType)
  313. defer func() {
  314. atomic.StoreUint32(&encoding, old)
  315. }()
  316. Info(fmt.Sprint(v...))
  317. })
  318. }
  319. func TestStructedLogSlow(t *testing.T) {
  320. w := new(mockWriter)
  321. old := writer.Swap(w)
  322. defer writer.Store(old)
  323. doTestStructedLog(t, levelSlow, w, func(v ...interface{}) {
  324. Slow(v...)
  325. })
  326. }
  327. func TestStructedLogSlowf(t *testing.T) {
  328. w := new(mockWriter)
  329. old := writer.Swap(w)
  330. defer writer.Store(old)
  331. doTestStructedLog(t, levelSlow, w, func(v ...interface{}) {
  332. Slowf(fmt.Sprint(v...))
  333. })
  334. }
  335. func TestStructedLogSlowv(t *testing.T) {
  336. w := new(mockWriter)
  337. old := writer.Swap(w)
  338. defer writer.Store(old)
  339. doTestStructedLog(t, levelSlow, w, func(v ...interface{}) {
  340. Slowv(fmt.Sprint(v...))
  341. })
  342. }
  343. func TestStructedLogSloww(t *testing.T) {
  344. w := new(mockWriter)
  345. old := writer.Swap(w)
  346. defer writer.Store(old)
  347. doTestStructedLog(t, levelSlow, w, func(v ...interface{}) {
  348. Sloww(fmt.Sprint(v...), Field("foo", time.Second))
  349. })
  350. }
  351. func TestStructedLogStat(t *testing.T) {
  352. w := new(mockWriter)
  353. old := writer.Swap(w)
  354. defer writer.Store(old)
  355. doTestStructedLog(t, levelStat, w, func(v ...interface{}) {
  356. Stat(v...)
  357. })
  358. }
  359. func TestStructedLogStatf(t *testing.T) {
  360. w := new(mockWriter)
  361. old := writer.Swap(w)
  362. defer writer.Store(old)
  363. doTestStructedLog(t, levelStat, w, func(v ...interface{}) {
  364. Statf(fmt.Sprint(v...))
  365. })
  366. }
  367. func TestStructedLogSevere(t *testing.T) {
  368. w := new(mockWriter)
  369. old := writer.Swap(w)
  370. defer writer.Store(old)
  371. doTestStructedLog(t, levelSevere, w, func(v ...interface{}) {
  372. Severe(v...)
  373. })
  374. }
  375. func TestStructedLogSeveref(t *testing.T) {
  376. w := new(mockWriter)
  377. old := writer.Swap(w)
  378. defer writer.Store(old)
  379. doTestStructedLog(t, levelSevere, w, func(v ...interface{}) {
  380. Severef(fmt.Sprint(v...))
  381. })
  382. }
  383. func TestStructedLogWithDuration(t *testing.T) {
  384. const message = "hello there"
  385. w := new(mockWriter)
  386. old := writer.Swap(w)
  387. defer writer.Store(old)
  388. WithDuration(time.Second).Info(message)
  389. var entry map[string]interface{}
  390. if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
  391. t.Error(err)
  392. }
  393. assert.Equal(t, levelInfo, entry[levelKey])
  394. assert.Equal(t, message, entry[contentKey])
  395. assert.Equal(t, "1000.0ms", entry[durationKey])
  396. }
  397. func TestSetLevel(t *testing.T) {
  398. SetLevel(ErrorLevel)
  399. const message = "hello there"
  400. w := new(mockWriter)
  401. old := writer.Swap(w)
  402. defer writer.Store(old)
  403. Info(message)
  404. assert.Equal(t, 0, w.builder.Len())
  405. }
  406. func TestSetLevelTwiceWithMode(t *testing.T) {
  407. testModes := []string{
  408. "mode",
  409. "console",
  410. "volumn",
  411. }
  412. w := new(mockWriter)
  413. old := writer.Swap(w)
  414. defer writer.Store(old)
  415. for _, mode := range testModes {
  416. testSetLevelTwiceWithMode(t, mode, w)
  417. }
  418. }
  419. func TestSetLevelWithDuration(t *testing.T) {
  420. SetLevel(ErrorLevel)
  421. const message = "hello there"
  422. w := new(mockWriter)
  423. old := writer.Swap(w)
  424. defer writer.Store(old)
  425. WithDuration(time.Second).Info(message)
  426. assert.Equal(t, 0, w.builder.Len())
  427. }
  428. func TestErrorfWithWrappedError(t *testing.T) {
  429. SetLevel(ErrorLevel)
  430. const message = "there"
  431. w := new(mockWriter)
  432. old := writer.Swap(w)
  433. defer writer.Store(old)
  434. Errorf("hello %w", errors.New(message))
  435. assert.True(t, strings.Contains(w.String(), "hello there"))
  436. }
  437. func TestMustNil(t *testing.T) {
  438. Must(nil)
  439. }
  440. func TestSetup(t *testing.T) {
  441. defer func() {
  442. SetLevel(InfoLevel)
  443. atomic.StoreUint32(&encoding, jsonEncodingType)
  444. }()
  445. MustSetup(LogConf{
  446. ServiceName: "any",
  447. Mode: "console",
  448. TimeFormat: timeFormat,
  449. })
  450. MustSetup(LogConf{
  451. ServiceName: "any",
  452. Mode: "file",
  453. Path: os.TempDir(),
  454. })
  455. MustSetup(LogConf{
  456. ServiceName: "any",
  457. Mode: "volume",
  458. Path: os.TempDir(),
  459. })
  460. MustSetup(LogConf{
  461. ServiceName: "any",
  462. Mode: "console",
  463. TimeFormat: timeFormat,
  464. })
  465. MustSetup(LogConf{
  466. ServiceName: "any",
  467. Mode: "console",
  468. Encoding: plainEncoding,
  469. })
  470. defer os.RemoveAll("CD01CB7D-2705-4F3F-889E-86219BF56F10")
  471. assert.NotNil(t, setupWithVolume(LogConf{}))
  472. assert.Nil(t, setupWithVolume(LogConf{
  473. ServiceName: "CD01CB7D-2705-4F3F-889E-86219BF56F10",
  474. }))
  475. assert.Nil(t, setupWithVolume(LogConf{
  476. ServiceName: "CD01CB7D-2705-4F3F-889E-86219BF56F10",
  477. Rotation: sizeRotationRule,
  478. }))
  479. assert.NotNil(t, setupWithFiles(LogConf{}))
  480. assert.Nil(t, setupWithFiles(LogConf{
  481. ServiceName: "any",
  482. Path: os.TempDir(),
  483. Compress: true,
  484. KeepDays: 1,
  485. }))
  486. setupLogLevel(LogConf{
  487. Level: levelInfo,
  488. })
  489. setupLogLevel(LogConf{
  490. Level: levelError,
  491. })
  492. setupLogLevel(LogConf{
  493. Level: levelSevere,
  494. })
  495. _, err := createOutput("")
  496. assert.NotNil(t, err)
  497. Disable()
  498. SetLevel(InfoLevel)
  499. atomic.StoreUint32(&encoding, jsonEncodingType)
  500. }
  501. func TestDisable(t *testing.T) {
  502. Disable()
  503. var opt logOptions
  504. WithKeepDays(1)(&opt)
  505. WithGzip()(&opt)
  506. WithMaxBackups(1)(&opt)
  507. WithMaxSize(1024)(&opt)
  508. assert.Nil(t, Close())
  509. assert.Nil(t, Close())
  510. }
  511. func TestDisableStat(t *testing.T) {
  512. DisableStat()
  513. const message = "hello there"
  514. w := new(mockWriter)
  515. old := writer.Swap(w)
  516. defer writer.Store(old)
  517. Stat(message)
  518. assert.Equal(t, 0, w.builder.Len())
  519. }
  520. func TestSetWriter(t *testing.T) {
  521. atomic.StoreUint32(&disableLog, 0)
  522. Reset()
  523. SetWriter(nopWriter{})
  524. assert.NotNil(t, writer.Load())
  525. assert.True(t, writer.Load() == nopWriter{})
  526. mocked := new(mockWriter)
  527. SetWriter(mocked)
  528. assert.Equal(t, mocked, writer.Load())
  529. }
  530. func TestWithGzip(t *testing.T) {
  531. fn := WithGzip()
  532. var opt logOptions
  533. fn(&opt)
  534. assert.True(t, opt.gzipEnabled)
  535. }
  536. func TestWithKeepDays(t *testing.T) {
  537. fn := WithKeepDays(1)
  538. var opt logOptions
  539. fn(&opt)
  540. assert.Equal(t, 1, opt.keepDays)
  541. }
  542. func BenchmarkCopyByteSliceAppend(b *testing.B) {
  543. for i := 0; i < b.N; i++ {
  544. var buf []byte
  545. buf = append(buf, getTimestamp()...)
  546. buf = append(buf, ' ')
  547. buf = append(buf, s...)
  548. _ = buf
  549. }
  550. }
  551. func BenchmarkCopyByteSliceAllocExactly(b *testing.B) {
  552. for i := 0; i < b.N; i++ {
  553. now := []byte(getTimestamp())
  554. buf := make([]byte, len(now)+1+len(s))
  555. n := copy(buf, now)
  556. buf[n] = ' '
  557. copy(buf[n+1:], s)
  558. }
  559. }
  560. func BenchmarkCopyByteSlice(b *testing.B) {
  561. var buf []byte
  562. for i := 0; i < b.N; i++ {
  563. buf = make([]byte, len(s))
  564. copy(buf, s)
  565. }
  566. fmt.Fprint(io.Discard, buf)
  567. }
  568. func BenchmarkCopyOnWriteByteSlice(b *testing.B) {
  569. var buf []byte
  570. for i := 0; i < b.N; i++ {
  571. size := len(s)
  572. buf = s[:size:size]
  573. }
  574. fmt.Fprint(io.Discard, buf)
  575. }
  576. func BenchmarkCacheByteSlice(b *testing.B) {
  577. for i := 0; i < b.N; i++ {
  578. dup := fetch()
  579. copy(dup, s)
  580. put(dup)
  581. }
  582. }
  583. func BenchmarkLogs(b *testing.B) {
  584. b.ReportAllocs()
  585. log.SetOutput(io.Discard)
  586. for i := 0; i < b.N; i++ {
  587. Info(i)
  588. }
  589. }
  590. func fetch() []byte {
  591. select {
  592. case b := <-pool:
  593. return b
  594. default:
  595. }
  596. return make([]byte, 4096)
  597. }
  598. func getFileLine() (string, int) {
  599. _, file, line, _ := runtime.Caller(1)
  600. short := file
  601. for i := len(file) - 1; i > 0; i-- {
  602. if file[i] == '/' {
  603. short = file[i+1:]
  604. break
  605. }
  606. }
  607. return short, line
  608. }
  609. func put(b []byte) {
  610. select {
  611. case pool <- b:
  612. default:
  613. }
  614. }
  615. func doTestStructedLog(t *testing.T, level string, w *mockWriter, write func(...interface{})) {
  616. const message = "hello there"
  617. write(message)
  618. var entry map[string]interface{}
  619. if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
  620. t.Error(err)
  621. }
  622. assert.Equal(t, level, entry[levelKey])
  623. val, ok := entry[contentKey]
  624. assert.True(t, ok)
  625. assert.True(t, strings.Contains(val.(string), message))
  626. }
  627. func doTestStructedLogConsole(t *testing.T, w *mockWriter, write func(...interface{})) {
  628. const message = "hello there"
  629. write(message)
  630. assert.True(t, strings.Contains(w.String(), message))
  631. }
  632. func testSetLevelTwiceWithMode(t *testing.T, mode string, w *mockWriter) {
  633. writer.Store(nil)
  634. SetUp(LogConf{
  635. Mode: mode,
  636. Level: "error",
  637. Path: "/dev/null",
  638. })
  639. SetUp(LogConf{
  640. Mode: mode,
  641. Level: "info",
  642. Path: "/dev/null",
  643. })
  644. const message = "hello there"
  645. Info(message)
  646. assert.Equal(t, 0, w.builder.Len())
  647. Infof(message)
  648. assert.Equal(t, 0, w.builder.Len())
  649. ErrorStack(message)
  650. assert.Equal(t, 0, w.builder.Len())
  651. ErrorStackf(message)
  652. assert.Equal(t, 0, w.builder.Len())
  653. }
  654. type ValStringer struct {
  655. val string
  656. }
  657. func (v ValStringer) String() string {
  658. return v.val
  659. }
  660. func validateFields(t *testing.T, content string, fields map[string]interface{}) {
  661. var m map[string]interface{}
  662. if err := json.Unmarshal([]byte(content), &m); err != nil {
  663. t.Error(err)
  664. }
  665. for k, v := range fields {
  666. if reflect.TypeOf(v).Kind() == reflect.Slice {
  667. assert.EqualValues(t, v, m[k])
  668. } else {
  669. assert.Equal(t, v, m[k], content)
  670. }
  671. }
  672. }