rotatelogger_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. package logx
  2. import (
  3. "os"
  4. "path"
  5. "path/filepath"
  6. "syscall"
  7. "testing"
  8. "time"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/zeromicro/go-zero/core/fs"
  11. "github.com/zeromicro/go-zero/core/stringx"
  12. )
  13. func TestDailyRotateRuleMarkRotated(t *testing.T) {
  14. t.Run("daily rule", func(t *testing.T) {
  15. var rule DailyRotateRule
  16. rule.MarkRotated()
  17. assert.Equal(t, getNowDate(), rule.rotatedTime)
  18. })
  19. t.Run("daily rule", func(t *testing.T) {
  20. rule := DefaultRotateRule("test", "-", 1, false)
  21. _, ok := rule.(*DailyRotateRule)
  22. assert.True(t, ok)
  23. })
  24. }
  25. func TestDailyRotateRuleOutdatedFiles(t *testing.T) {
  26. t.Run("no files", func(t *testing.T) {
  27. var rule DailyRotateRule
  28. assert.Empty(t, rule.OutdatedFiles())
  29. rule.days = 1
  30. assert.Empty(t, rule.OutdatedFiles())
  31. rule.gzip = true
  32. assert.Empty(t, rule.OutdatedFiles())
  33. })
  34. t.Run("bad files", func(t *testing.T) {
  35. rule := DailyRotateRule{
  36. filename: "[a-z",
  37. }
  38. assert.Empty(t, rule.OutdatedFiles())
  39. rule.days = 1
  40. assert.Empty(t, rule.OutdatedFiles())
  41. rule.gzip = true
  42. assert.Empty(t, rule.OutdatedFiles())
  43. })
  44. t.Run("temp files", func(t *testing.T) {
  45. boundary := time.Now().Add(-time.Hour * time.Duration(hoursPerDay) * 2).Format(dateFormat)
  46. f1, err := os.CreateTemp(os.TempDir(), "go-zero-test-"+boundary)
  47. assert.NoError(t, err)
  48. _ = f1.Close()
  49. f2, err := os.CreateTemp(os.TempDir(), "go-zero-test-"+boundary)
  50. assert.NoError(t, err)
  51. _ = f2.Close()
  52. t.Cleanup(func() {
  53. _ = os.Remove(f1.Name())
  54. _ = os.Remove(f2.Name())
  55. })
  56. rule := DailyRotateRule{
  57. filename: path.Join(os.TempDir(), "go-zero-test-"),
  58. days: 1,
  59. }
  60. assert.NotEmpty(t, rule.OutdatedFiles())
  61. })
  62. }
  63. func TestDailyRotateRuleShallRotate(t *testing.T) {
  64. var rule DailyRotateRule
  65. rule.rotatedTime = time.Now().Add(time.Hour * 24).Format(dateFormat)
  66. assert.True(t, rule.ShallRotate(0))
  67. }
  68. func TestSizeLimitRotateRuleMarkRotated(t *testing.T) {
  69. t.Run("size limit rule", func(t *testing.T) {
  70. var rule SizeLimitRotateRule
  71. rule.MarkRotated()
  72. assert.Equal(t, getNowDateInRFC3339Format(), rule.rotatedTime)
  73. })
  74. t.Run("size limit rule", func(t *testing.T) {
  75. rule := NewSizeLimitRotateRule("foo", "-", 1, 1, 1, false)
  76. rule.MarkRotated()
  77. assert.Equal(t, getNowDateInRFC3339Format(), rule.(*SizeLimitRotateRule).rotatedTime)
  78. })
  79. }
  80. func TestSizeLimitRotateRuleOutdatedFiles(t *testing.T) {
  81. t.Run("no files", func(t *testing.T) {
  82. var rule SizeLimitRotateRule
  83. assert.Empty(t, rule.OutdatedFiles())
  84. rule.days = 1
  85. assert.Empty(t, rule.OutdatedFiles())
  86. rule.gzip = true
  87. assert.Empty(t, rule.OutdatedFiles())
  88. rule.maxBackups = 0
  89. assert.Empty(t, rule.OutdatedFiles())
  90. })
  91. t.Run("bad files", func(t *testing.T) {
  92. rule := SizeLimitRotateRule{
  93. DailyRotateRule: DailyRotateRule{
  94. filename: "[a-z",
  95. },
  96. }
  97. assert.Empty(t, rule.OutdatedFiles())
  98. rule.days = 1
  99. assert.Empty(t, rule.OutdatedFiles())
  100. rule.gzip = true
  101. assert.Empty(t, rule.OutdatedFiles())
  102. })
  103. t.Run("temp files", func(t *testing.T) {
  104. boundary := time.Now().Add(-time.Hour * time.Duration(hoursPerDay) * 2).Format(dateFormat)
  105. f1, err := os.CreateTemp(os.TempDir(), "go-zero-test-"+boundary)
  106. assert.NoError(t, err)
  107. f2, err := os.CreateTemp(os.TempDir(), "go-zero-test-"+boundary)
  108. assert.NoError(t, err)
  109. boundary1 := time.Now().Add(time.Hour * time.Duration(hoursPerDay) * 2).Format(dateFormat)
  110. f3, err := os.CreateTemp(os.TempDir(), "go-zero-test-"+boundary1)
  111. assert.NoError(t, err)
  112. t.Cleanup(func() {
  113. _ = f1.Close()
  114. _ = os.Remove(f1.Name())
  115. _ = f2.Close()
  116. _ = os.Remove(f2.Name())
  117. _ = f3.Close()
  118. _ = os.Remove(f3.Name())
  119. })
  120. rule := SizeLimitRotateRule{
  121. DailyRotateRule: DailyRotateRule{
  122. filename: path.Join(os.TempDir(), "go-zero-test-"),
  123. days: 1,
  124. },
  125. maxBackups: 3,
  126. }
  127. assert.NotEmpty(t, rule.OutdatedFiles())
  128. })
  129. t.Run("no backups", func(t *testing.T) {
  130. boundary := time.Now().Add(-time.Hour * time.Duration(hoursPerDay) * 2).Format(dateFormat)
  131. f1, err := os.CreateTemp(os.TempDir(), "go-zero-test-"+boundary)
  132. assert.NoError(t, err)
  133. f2, err := os.CreateTemp(os.TempDir(), "go-zero-test-"+boundary)
  134. assert.NoError(t, err)
  135. boundary1 := time.Now().Add(time.Hour * time.Duration(hoursPerDay) * 2).Format(dateFormat)
  136. f3, err := os.CreateTemp(os.TempDir(), "go-zero-test-"+boundary1)
  137. assert.NoError(t, err)
  138. t.Cleanup(func() {
  139. _ = f1.Close()
  140. _ = os.Remove(f1.Name())
  141. _ = f2.Close()
  142. _ = os.Remove(f2.Name())
  143. _ = f3.Close()
  144. _ = os.Remove(f3.Name())
  145. })
  146. rule := SizeLimitRotateRule{
  147. DailyRotateRule: DailyRotateRule{
  148. filename: path.Join(os.TempDir(), "go-zero-test-"),
  149. days: 1,
  150. },
  151. }
  152. assert.NotEmpty(t, rule.OutdatedFiles())
  153. logger := new(RotateLogger)
  154. logger.rule = &rule
  155. logger.maybeDeleteOutdatedFiles()
  156. assert.Empty(t, rule.OutdatedFiles())
  157. })
  158. }
  159. func TestSizeLimitRotateRuleShallRotate(t *testing.T) {
  160. var rule SizeLimitRotateRule
  161. rule.rotatedTime = time.Now().Add(time.Hour * 24).Format(fileTimeFormat)
  162. rule.maxSize = 0
  163. assert.False(t, rule.ShallRotate(0))
  164. rule.maxSize = 100
  165. assert.False(t, rule.ShallRotate(0))
  166. assert.True(t, rule.ShallRotate(101*megaBytes))
  167. }
  168. func TestRotateLoggerClose(t *testing.T) {
  169. t.Run("close", func(t *testing.T) {
  170. filename, err := fs.TempFilenameWithText("foo")
  171. assert.Nil(t, err)
  172. if len(filename) > 0 {
  173. defer os.Remove(filename)
  174. }
  175. logger, err := NewLogger(filename, new(DailyRotateRule), false)
  176. assert.Nil(t, err)
  177. _, err = logger.Write([]byte("foo"))
  178. assert.Nil(t, err)
  179. assert.Nil(t, logger.Close())
  180. })
  181. t.Run("close and write", func(t *testing.T) {
  182. logger := new(RotateLogger)
  183. logger.done = make(chan struct{})
  184. close(logger.done)
  185. _, err := logger.Write([]byte("foo"))
  186. assert.ErrorIs(t, err, ErrLogFileClosed)
  187. })
  188. }
  189. func TestRotateLoggerGetBackupFilename(t *testing.T) {
  190. filename, err := fs.TempFilenameWithText("foo")
  191. assert.Nil(t, err)
  192. if len(filename) > 0 {
  193. defer os.Remove(filename)
  194. }
  195. logger, err := NewLogger(filename, new(DailyRotateRule), false)
  196. assert.Nil(t, err)
  197. assert.True(t, len(logger.getBackupFilename()) > 0)
  198. logger.backup = ""
  199. assert.True(t, len(logger.getBackupFilename()) > 0)
  200. }
  201. func TestRotateLoggerMayCompressFile(t *testing.T) {
  202. old := os.Stdout
  203. os.Stdout = os.NewFile(0, os.DevNull)
  204. defer func() {
  205. os.Stdout = old
  206. }()
  207. filename, err := fs.TempFilenameWithText("foo")
  208. assert.Nil(t, err)
  209. if len(filename) > 0 {
  210. defer os.Remove(filename)
  211. }
  212. logger, err := NewLogger(filename, new(DailyRotateRule), false)
  213. assert.Nil(t, err)
  214. logger.maybeCompressFile(filename)
  215. _, err = os.Stat(filename)
  216. assert.Nil(t, err)
  217. }
  218. func TestRotateLoggerMayCompressFileTrue(t *testing.T) {
  219. old := os.Stdout
  220. os.Stdout = os.NewFile(0, os.DevNull)
  221. defer func() {
  222. os.Stdout = old
  223. }()
  224. filename, err := fs.TempFilenameWithText("foo")
  225. assert.Nil(t, err)
  226. logger, err := NewLogger(filename, new(DailyRotateRule), true)
  227. assert.Nil(t, err)
  228. if len(filename) > 0 {
  229. defer os.Remove(filepath.Base(logger.getBackupFilename()) + ".gz")
  230. }
  231. logger.maybeCompressFile(filename)
  232. _, err = os.Stat(filename)
  233. assert.NotNil(t, err)
  234. }
  235. func TestRotateLoggerRotate(t *testing.T) {
  236. filename, err := fs.TempFilenameWithText("foo")
  237. assert.Nil(t, err)
  238. logger, err := NewLogger(filename, new(DailyRotateRule), true)
  239. assert.Nil(t, err)
  240. if len(filename) > 0 {
  241. defer func() {
  242. os.Remove(logger.getBackupFilename())
  243. os.Remove(filepath.Base(logger.getBackupFilename()) + ".gz")
  244. }()
  245. }
  246. err = logger.rotate()
  247. switch v := err.(type) {
  248. case *os.LinkError:
  249. // avoid rename error on docker container
  250. assert.Equal(t, syscall.EXDEV, v.Err)
  251. case *os.PathError:
  252. // ignore remove error for tests,
  253. // files are cleaned in GitHub actions.
  254. assert.Equal(t, "remove", v.Op)
  255. default:
  256. assert.Nil(t, err)
  257. }
  258. }
  259. func TestRotateLoggerWrite(t *testing.T) {
  260. filename, err := fs.TempFilenameWithText("foo")
  261. assert.Nil(t, err)
  262. rule := new(DailyRotateRule)
  263. logger, err := NewLogger(filename, rule, true)
  264. assert.Nil(t, err)
  265. if len(filename) > 0 {
  266. defer func() {
  267. os.Remove(logger.getBackupFilename())
  268. os.Remove(filepath.Base(logger.getBackupFilename()) + ".gz")
  269. }()
  270. }
  271. // the following write calls cannot be changed to Write, because of DATA RACE.
  272. logger.write([]byte(`foo`))
  273. rule.rotatedTime = time.Now().Add(-time.Hour * 24).Format(dateFormat)
  274. logger.write([]byte(`bar`))
  275. logger.Close()
  276. logger.write([]byte(`baz`))
  277. }
  278. func TestLogWriterClose(t *testing.T) {
  279. assert.Nil(t, newLogWriter(nil).Close())
  280. }
  281. func TestRotateLoggerWithSizeLimitRotateRuleClose(t *testing.T) {
  282. filename, err := fs.TempFilenameWithText("foo")
  283. assert.Nil(t, err)
  284. if len(filename) > 0 {
  285. defer os.Remove(filename)
  286. }
  287. logger, err := NewLogger(filename, new(SizeLimitRotateRule), false)
  288. assert.Nil(t, err)
  289. _ = logger.Close()
  290. }
  291. func TestRotateLoggerGetBackupWithSizeLimitRotateRuleFilename(t *testing.T) {
  292. filename, err := fs.TempFilenameWithText("foo")
  293. assert.Nil(t, err)
  294. if len(filename) > 0 {
  295. defer os.Remove(filename)
  296. }
  297. logger, err := NewLogger(filename, new(SizeLimitRotateRule), false)
  298. assert.Nil(t, err)
  299. assert.True(t, len(logger.getBackupFilename()) > 0)
  300. logger.backup = ""
  301. assert.True(t, len(logger.getBackupFilename()) > 0)
  302. }
  303. func TestRotateLoggerWithSizeLimitRotateRuleMayCompressFile(t *testing.T) {
  304. old := os.Stdout
  305. os.Stdout = os.NewFile(0, os.DevNull)
  306. defer func() {
  307. os.Stdout = old
  308. }()
  309. filename, err := fs.TempFilenameWithText("foo")
  310. assert.Nil(t, err)
  311. if len(filename) > 0 {
  312. defer os.Remove(filename)
  313. }
  314. logger, err := NewLogger(filename, new(SizeLimitRotateRule), false)
  315. assert.Nil(t, err)
  316. logger.maybeCompressFile(filename)
  317. _, err = os.Stat(filename)
  318. assert.Nil(t, err)
  319. }
  320. func TestRotateLoggerWithSizeLimitRotateRuleMayCompressFileTrue(t *testing.T) {
  321. old := os.Stdout
  322. os.Stdout = os.NewFile(0, os.DevNull)
  323. defer func() {
  324. os.Stdout = old
  325. }()
  326. filename, err := fs.TempFilenameWithText("foo")
  327. assert.Nil(t, err)
  328. logger, err := NewLogger(filename, new(SizeLimitRotateRule), true)
  329. assert.Nil(t, err)
  330. if len(filename) > 0 {
  331. defer os.Remove(filepath.Base(logger.getBackupFilename()) + ".gz")
  332. }
  333. logger.maybeCompressFile(filename)
  334. _, err = os.Stat(filename)
  335. assert.NotNil(t, err)
  336. }
  337. func TestRotateLoggerWithSizeLimitRotateRuleMayCompressFileFailed(t *testing.T) {
  338. old := os.Stdout
  339. os.Stdout = os.NewFile(0, os.DevNull)
  340. defer func() {
  341. os.Stdout = old
  342. }()
  343. filename := stringx.RandId()
  344. logger, err := NewLogger(filename, new(SizeLimitRotateRule), true)
  345. defer os.Remove(filename)
  346. if assert.NoError(t, err) {
  347. assert.NotPanics(t, func() {
  348. logger.maybeCompressFile(stringx.RandId())
  349. })
  350. }
  351. }
  352. func TestRotateLoggerWithSizeLimitRotateRuleRotate(t *testing.T) {
  353. filename, err := fs.TempFilenameWithText("foo")
  354. assert.Nil(t, err)
  355. logger, err := NewLogger(filename, new(SizeLimitRotateRule), true)
  356. assert.Nil(t, err)
  357. if len(filename) > 0 {
  358. defer func() {
  359. os.Remove(logger.getBackupFilename())
  360. os.Remove(filepath.Base(logger.getBackupFilename()) + ".gz")
  361. }()
  362. }
  363. err = logger.rotate()
  364. switch v := err.(type) {
  365. case *os.LinkError:
  366. // avoid rename error on docker container
  367. assert.Equal(t, syscall.EXDEV, v.Err)
  368. case *os.PathError:
  369. // ignore remove error for tests,
  370. // files are cleaned in GitHub actions.
  371. assert.Equal(t, "remove", v.Op)
  372. default:
  373. assert.Nil(t, err)
  374. }
  375. }
  376. func TestRotateLoggerWithSizeLimitRotateRuleWrite(t *testing.T) {
  377. filename, err := fs.TempFilenameWithText("foo")
  378. assert.Nil(t, err)
  379. rule := new(SizeLimitRotateRule)
  380. logger, err := NewLogger(filename, rule, true)
  381. assert.Nil(t, err)
  382. if len(filename) > 0 {
  383. defer func() {
  384. os.Remove(logger.getBackupFilename())
  385. os.Remove(filepath.Base(logger.getBackupFilename()) + ".gz")
  386. }()
  387. }
  388. // the following write calls cannot be changed to Write, because of DATA RACE.
  389. logger.write([]byte(`foo`))
  390. rule.rotatedTime = time.Now().Add(-time.Hour * 24).Format(dateFormat)
  391. logger.write([]byte(`bar`))
  392. logger.Close()
  393. logger.write([]byte(`baz`))
  394. }
  395. func BenchmarkRotateLogger(b *testing.B) {
  396. filename := "./test.log"
  397. filename2 := "./test2.log"
  398. dailyRotateRuleLogger, err1 := NewLogger(
  399. filename,
  400. DefaultRotateRule(
  401. filename,
  402. backupFileDelimiter,
  403. 1,
  404. true,
  405. ),
  406. true,
  407. )
  408. if err1 != nil {
  409. b.Logf("Failed to new daily rotate rule logger: %v", err1)
  410. b.FailNow()
  411. }
  412. sizeLimitRotateRuleLogger, err2 := NewLogger(
  413. filename2,
  414. NewSizeLimitRotateRule(
  415. filename,
  416. backupFileDelimiter,
  417. 1,
  418. 100,
  419. 10,
  420. true,
  421. ),
  422. true,
  423. )
  424. if err2 != nil {
  425. b.Logf("Failed to new size limit rotate rule logger: %v", err1)
  426. b.FailNow()
  427. }
  428. defer func() {
  429. dailyRotateRuleLogger.Close()
  430. sizeLimitRotateRuleLogger.Close()
  431. os.Remove(filename)
  432. os.Remove(filename2)
  433. }()
  434. b.Run("daily rotate rule", func(b *testing.B) {
  435. for i := 0; i < b.N; i++ {
  436. dailyRotateRuleLogger.write([]byte("testing\ntesting\n"))
  437. }
  438. })
  439. b.Run("size limit rotate rule", func(b *testing.B) {
  440. for i := 0; i < b.N; i++ {
  441. sizeLimitRotateRuleLogger.write([]byte("testing\ntesting\n"))
  442. }
  443. })
  444. }