logs_test.go 17 KB

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