logs_test.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. package logx
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io/ioutil"
  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 logEntry
  390. if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
  391. t.Error(err)
  392. }
  393. assert.Equal(t, levelInfo, entry.Level)
  394. assert.Equal(t, message, entry.Content)
  395. assert.Equal(t, "1000.0ms", entry.Duration)
  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. })
  449. MustSetup(LogConf{
  450. ServiceName: "any",
  451. Mode: "file",
  452. Path: os.TempDir(),
  453. })
  454. MustSetup(LogConf{
  455. ServiceName: "any",
  456. Mode: "volume",
  457. Path: os.TempDir(),
  458. })
  459. MustSetup(LogConf{
  460. ServiceName: "any",
  461. Mode: "console",
  462. TimeFormat: timeFormat,
  463. })
  464. MustSetup(LogConf{
  465. ServiceName: "any",
  466. Mode: "console",
  467. Encoding: plainEncoding,
  468. })
  469. assert.NotNil(t, setupWithVolume(LogConf{}))
  470. assert.NotNil(t, setupWithFiles(LogConf{}))
  471. assert.Nil(t, setupWithFiles(LogConf{
  472. ServiceName: "any",
  473. Path: os.TempDir(),
  474. Compress: true,
  475. KeepDays: 1,
  476. }))
  477. setupLogLevel(LogConf{
  478. Level: levelInfo,
  479. })
  480. setupLogLevel(LogConf{
  481. Level: levelError,
  482. })
  483. setupLogLevel(LogConf{
  484. Level: levelSevere,
  485. })
  486. _, err := createOutput("")
  487. assert.NotNil(t, err)
  488. Disable()
  489. SetLevel(InfoLevel)
  490. atomic.StoreUint32(&encoding, jsonEncodingType)
  491. }
  492. func TestDisable(t *testing.T) {
  493. Disable()
  494. var opt logOptions
  495. WithKeepDays(1)(&opt)
  496. WithGzip()(&opt)
  497. assert.Nil(t, Close())
  498. assert.Nil(t, Close())
  499. }
  500. func TestDisableStat(t *testing.T) {
  501. DisableStat()
  502. const message = "hello there"
  503. w := new(mockWriter)
  504. old := writer.Swap(w)
  505. defer writer.Store(old)
  506. Stat(message)
  507. assert.Equal(t, 0, w.builder.Len())
  508. }
  509. func TestSetWriter(t *testing.T) {
  510. Reset()
  511. SetWriter(nopWriter{})
  512. assert.NotNil(t, writer.Load())
  513. assert.True(t, writer.Load() == nopWriter{})
  514. SetWriter(new(mockWriter))
  515. assert.True(t, writer.Load() == nopWriter{})
  516. }
  517. func TestWithGzip(t *testing.T) {
  518. fn := WithGzip()
  519. var opt logOptions
  520. fn(&opt)
  521. assert.True(t, opt.gzipEnabled)
  522. }
  523. func TestWithKeepDays(t *testing.T) {
  524. fn := WithKeepDays(1)
  525. var opt logOptions
  526. fn(&opt)
  527. assert.Equal(t, 1, opt.keepDays)
  528. }
  529. func BenchmarkCopyByteSliceAppend(b *testing.B) {
  530. for i := 0; i < b.N; i++ {
  531. var buf []byte
  532. buf = append(buf, getTimestamp()...)
  533. buf = append(buf, ' ')
  534. buf = append(buf, s...)
  535. _ = buf
  536. }
  537. }
  538. func BenchmarkCopyByteSliceAllocExactly(b *testing.B) {
  539. for i := 0; i < b.N; i++ {
  540. now := []byte(getTimestamp())
  541. buf := make([]byte, len(now)+1+len(s))
  542. n := copy(buf, now)
  543. buf[n] = ' '
  544. copy(buf[n+1:], s)
  545. }
  546. }
  547. func BenchmarkCopyByteSlice(b *testing.B) {
  548. var buf []byte
  549. for i := 0; i < b.N; i++ {
  550. buf = make([]byte, len(s))
  551. copy(buf, s)
  552. }
  553. fmt.Fprint(ioutil.Discard, buf)
  554. }
  555. func BenchmarkCopyOnWriteByteSlice(b *testing.B) {
  556. var buf []byte
  557. for i := 0; i < b.N; i++ {
  558. size := len(s)
  559. buf = s[:size:size]
  560. }
  561. fmt.Fprint(ioutil.Discard, buf)
  562. }
  563. func BenchmarkCacheByteSlice(b *testing.B) {
  564. for i := 0; i < b.N; i++ {
  565. dup := fetch()
  566. copy(dup, s)
  567. put(dup)
  568. }
  569. }
  570. func BenchmarkLogs(b *testing.B) {
  571. b.ReportAllocs()
  572. log.SetOutput(ioutil.Discard)
  573. for i := 0; i < b.N; i++ {
  574. Info(i)
  575. }
  576. }
  577. func fetch() []byte {
  578. select {
  579. case b := <-pool:
  580. return b
  581. default:
  582. }
  583. return make([]byte, 4096)
  584. }
  585. func getFileLine() (string, int) {
  586. _, file, line, _ := runtime.Caller(1)
  587. short := file
  588. for i := len(file) - 1; i > 0; i-- {
  589. if file[i] == '/' {
  590. short = file[i+1:]
  591. break
  592. }
  593. }
  594. return short, line
  595. }
  596. func put(b []byte) {
  597. select {
  598. case pool <- b:
  599. default:
  600. }
  601. }
  602. func doTestStructedLog(t *testing.T, level string, w *mockWriter, write func(...interface{})) {
  603. const message = "hello there"
  604. write(message)
  605. fmt.Println(w.String())
  606. var entry logEntry
  607. if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
  608. t.Error(err)
  609. }
  610. assert.Equal(t, level, entry.Level)
  611. val, ok := entry.Content.(string)
  612. assert.True(t, ok)
  613. assert.True(t, strings.Contains(val, message))
  614. }
  615. func doTestStructedLogConsole(t *testing.T, w *mockWriter, write func(...interface{})) {
  616. const message = "hello there"
  617. write(message)
  618. assert.True(t, strings.Contains(w.String(), message))
  619. }
  620. func testSetLevelTwiceWithMode(t *testing.T, mode string, w *mockWriter) {
  621. writer.Store(nil)
  622. SetUp(LogConf{
  623. Mode: mode,
  624. Level: "error",
  625. Path: "/dev/null",
  626. })
  627. SetUp(LogConf{
  628. Mode: mode,
  629. Level: "info",
  630. Path: "/dev/null",
  631. })
  632. const message = "hello there"
  633. Info(message)
  634. assert.Equal(t, 0, w.builder.Len())
  635. Infof(message)
  636. assert.Equal(t, 0, w.builder.Len())
  637. ErrorStack(message)
  638. assert.Equal(t, 0, w.builder.Len())
  639. ErrorStackf(message)
  640. assert.Equal(t, 0, w.builder.Len())
  641. }
  642. type ValStringer struct {
  643. val string
  644. }
  645. func (v ValStringer) String() string {
  646. return v.val
  647. }
  648. func validateFields(t *testing.T, content string, fields map[string]interface{}) {
  649. var m map[string]interface{}
  650. if err := json.Unmarshal([]byte(content), &m); err != nil {
  651. t.Error(err)
  652. }
  653. for k, v := range fields {
  654. if reflect.TypeOf(v).Kind() == reflect.Slice {
  655. assert.EqualValues(t, v, m[k])
  656. } else {
  657. assert.Equal(t, v, m[k], content)
  658. }
  659. }
  660. }