logs_test.go 17 KB

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