From 86e029fbb3633ad856bd40b67604e32aab341bc4 Mon Sep 17 00:00:00 2001 From: Inhere Date: Tue, 26 Mar 2024 16:36:11 +0800 Subject: [PATCH] :bug: fix: fix the rotating file name is error on use rotatefile.EveryDay. see issues #138 --- rotatefile/config.go | 21 ++++++++++----------- rotatefile/config_test.go | 6 +++--- rotatefile/issues_test.go | 14 +++++++------- rotatefile/writer.go | 21 ++++++++++----------- 4 files changed, 30 insertions(+), 32 deletions(-) diff --git a/rotatefile/config.go b/rotatefile/config.go index 54488fb..16df927 100644 --- a/rotatefile/config.go +++ b/rotatefile/config.go @@ -29,7 +29,7 @@ const ( // - "error.log.20201223_1523" type RotateTime int -// built in rotate time consts +// built in rotate time constants const ( EveryDay RotateTime = timex.OneDaySec EveryHour RotateTime = timex.OneHourSec @@ -39,38 +39,37 @@ const ( EverySecond RotateTime = 1 // only use for tests ) -// Interval get check interval time +// Interval get check interval time. unit is seconds. func (rt RotateTime) Interval() int64 { return int64(rt) } // FirstCheckTime for rotate file. -// will automatically align the time from the start of each hour. -func (rt RotateTime) FirstCheckTime(now time.Time) int64 { +// - will automatically align the time from the start of each hour. +func (rt RotateTime) FirstCheckTime(now time.Time) time.Time { interval := rt.Interval() switch rt.level() { case levelDay: - return timex.DayEnd(now).Unix() + return timex.DayEnd(now) case levelHour: // should check on H:59:59.500 - return timex.HourStart(now).Add(timex.OneHour - 500*time.Millisecond).Unix() + return timex.HourStart(now).Add(timex.OneHour - 500*time.Millisecond) case levelMin: // eg: minutes=5 minutes := int(interval / 60) nextMin := now.Minute() + minutes - // eg: now.Minute()=57, nextMin=62. - // will rotate at next hour start. + // will rotate at next hour start. eg: now.Minute()=57, nextMin=62. if nextMin >= 60 { - return timex.HourStart(now).Add(timex.OneHour).Unix() + return timex.HourStart(now).Add(timex.OneHour) } // eg: now.Minute()=37, nextMin=42, will get nextDur=40 nextDur := time.Duration(nextMin).Round(time.Duration(minutes)) - return timex.HourStart(now).Add(nextDur).Unix() + return timex.HourStart(now).Add(nextDur) default: // levelSec - return now.Unix() + interval + return now.Add(time.Duration(interval) * time.Second) } } diff --git a/rotatefile/config_test.go b/rotatefile/config_test.go index 973dce6..f520508 100644 --- a/rotatefile/config_test.go +++ b/rotatefile/config_test.go @@ -50,7 +50,7 @@ func TestRotateTime_TimeFormat(t *testing.T) { rt := rotatefile.EveryDay assert.Eq(t, "20060102", rt.TimeFormat()) ft := rt.FirstCheckTime(now.T()) - assert.Eq(t, now.DayEnd().Unix(), ft) + assert.True(t, now.DayEnd().Equal(ft)) rt = rotatefile.EveryHour assert.Eq(t, "20060102_1500", rt.TimeFormat()) @@ -58,12 +58,12 @@ func TestRotateTime_TimeFormat(t *testing.T) { rt = rotatefile.Every15Min assert.Eq(t, "20060102_1504", rt.TimeFormat()) ft = rt.FirstCheckTime(now.T()) - assert.Gt(t, ft, 0) + assert.Gt(t, ft.Unix(), 0) rt = rotatefile.EverySecond assert.Eq(t, "20060102_150405", rt.TimeFormat()) ft = rt.FirstCheckTime(now.T()) - assert.Eq(t, now.Unix()+rt.Interval(), ft) + assert.Eq(t, now.Unix()+rt.Interval(), ft.Unix()) } func TestRotateTime_String(t *testing.T) { diff --git a/rotatefile/issues_test.go b/rotatefile/issues_test.go index 0d953ea..60f1105 100644 --- a/rotatefile/issues_test.go +++ b/rotatefile/issues_test.go @@ -15,7 +15,7 @@ import ( func TestIssues_138(t *testing.T) { logfile := "testdata/rotate_day.log" - mt := newMockTime("2023-11-16 23:59:58") + mt := newMockTime("2023-11-16 23:59:55") w, err := rotatefile.NewWriterWith(rotatefile.WithDebugMode, func(c *rotatefile.Config) { c.TimeClock = mt // c.MaxSize = 128 @@ -26,11 +26,13 @@ func TestIssues_138(t *testing.T) { assert.NoErr(t, err) defer w.MustClose() - for i := 0; i < 5; i++ { + for i := 0; i < 15; i++ { dt := mt.Datetime() _, err = w.WriteString(dt + " [INFO] this is a log message, idx=" + mathutil.String(i) + "\n") assert.NoErr(t, err) - mt.Add(time.Second) // add one second + // increase time + mt.Add(time.Second * 3) + // mt.Add(time.Millisecond * 300) } // Out: rotate_day.log, rotate_day.log.20231116 @@ -40,12 +42,10 @@ func TestIssues_138(t *testing.T) { // check contents assert.True(t, fsutil.IsFile(logfile)) s := fsutil.ReadString(logfile) - assert.StrContains(t, s, "2023-11-17 00:00:01 [INFO]") - assert.StrNoContains(t, s, "2023-11-16") + assert.StrContains(t, s, "2023-11-17 00:00") oldFile := logfile + ".20231116" assert.True(t, fsutil.IsFile(oldFile)) s = fsutil.ReadString(oldFile) - assert.StrContains(t, s, "2023-11-16 23:59:59 [INFO]") - assert.StrNoContains(t, s, "2023-11-17") + assert.StrContains(t, s, "2023-11-16 23:") } diff --git a/rotatefile/writer.go b/rotatefile/writer.go index 8160d6f..bef686a 100644 --- a/rotatefile/writer.go +++ b/rotatefile/writer.go @@ -39,9 +39,9 @@ type Writer struct { rotateNum uint // rotate times number // context use for rotating file by time - suffixFormat string // the rotating file name suffix. eg: "20210102", "20210102_1500" - checkInterval int64 // check interval seconds. - nextRotatingAt int64 + suffixFormat string // the rotating file name suffix. eg: "20210102", "20210102_1500" + checkInterval int64 // check interval seconds. + nextRotatingAt time.Time // next rotating time } // NewWriter create rotate write with config and init it. @@ -74,12 +74,11 @@ func (d *Writer) init() error { // calc and storage next rotating time if d.checkInterval > 0 { - nowTime := d.cfg.TimeClock.Now() + now := d.cfg.TimeClock.Now() // next rotating time - d.nextRotatingAt = d.cfg.RotateTime.FirstCheckTime(nowTime) - + d.nextRotatingAt = d.cfg.RotateTime.FirstCheckTime(now) if d.cfg.RotateMode == ModeCreate { - logfile = d.cfg.Filepath + "." + nowTime.Format(d.suffixFormat) + logfile = d.cfg.Filepath + "." + now.Format(d.suffixFormat) } } @@ -185,17 +184,17 @@ func (d *Writer) doRotate() (err error) { // TIP: should only call on d.checkInterval > 0 func (d *Writer) rotatingByTime() error { now := d.cfg.TimeClock.Now() - if d.nextRotatingAt > now.Unix() { + if now.Before(d.nextRotatingAt) { return nil } // generate new file path. // eg: /tmp/error.log => /tmp/error.log.20220423_1600 - file := d.cfg.Filepath + "." + now.Format(d.suffixFormat) + file := d.cfg.Filepath + "." + d.nextRotatingAt.Format(d.suffixFormat) err := d.rotatingFile(file, false) - // storage next rotating time - d.nextRotatingAt = now.Unix() + d.checkInterval + // calc and storage next rotating time + d.nextRotatingAt = d.nextRotatingAt.Add(time.Duration(d.checkInterval) * time.Second) return err }