Skip to content

Commit

Permalink
👔 up: add new handler option: TimeClock, fix some test error
Browse files Browse the repository at this point in the history
- add rotatefile.MockClocker for mock test rotating file
  • Loading branch information
inhere committed Mar 26, 2024
1 parent 86e029f commit 70031a7
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 87 deletions.
39 changes: 23 additions & 16 deletions handler/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/gookit/slog/rotatefile"
)

// the buff mode consts
// the buff mode constants
const (
BuffModeLine = "line"
BuffModeBite = "bite"
Expand Down Expand Up @@ -59,6 +59,9 @@ type Config struct {
// RotateMode for rotate file by time. default rotatefile.ModeRename
RotateMode rotatefile.RotateMode `json:"rotate_mode" yaml:"rotate_mode"`

// TimeClock for rotate file by time.
TimeClock rotatefile.Clocker `json:"-" yaml:"-"`

// MaxSize on rotate file by size, unit is bytes.
MaxSize uint64 `json:"max_size" yaml:"max_size"`

Expand Down Expand Up @@ -148,7 +151,7 @@ func (c *Config) CreateHandler() (*SyncCloseHandler, error) {
// RotateWriter build rotate writer by config
func (c *Config) RotateWriter() (output SyncCloseWriter, err error) {
if c.MaxSize == 0 && c.RotateTime == 0 {
return nil, errorx.Raw("slog: cannot create rotate writer, MaxSize and RotateTime both is 0")
return nil, errorx.E("slog: cannot create rotate writer, MaxSize and RotateTime both is 0")
}

return c.CreateWriter()
Expand All @@ -163,7 +166,7 @@ func (c *Config) CreateWriter() (output SyncCloseWriter, err error) {
c.FilePerm = rotatefile.DefaultFilePerm
}

// create a rotate config.
// create a rotated writer by config.
if c.MaxSize > 0 || c.RotateTime > 0 {
rc := rotatefile.EmptyConfigWith()

Expand All @@ -184,10 +187,13 @@ func (c *Config) CreateWriter() (output SyncCloseWriter, err error) {
if c.RenameFunc != nil {
rc.RenameFunc = c.RenameFunc
}
if c.TimeClock != nil {
rc.TimeClock = c.TimeClock
}

// create a rotating writer
output, err = rc.Create()
} else {
// create a file writer
output, err = fsutil.OpenAppendFile(c.Logfile, c.FilePerm)
}

Expand All @@ -209,10 +215,6 @@ type flushSyncCloseWriter interface {

// wrap buffer for the writer
func (c *Config) wrapBuffer(w io.Writer) (bw flushSyncCloseWriter) {
// if c.BuffSize == 0 {
// panic("slog: buff size cannot be zero on wrap buffer")
// }

if c.BuffMode == BuffModeLine {
bw = bufwrite.NewLineWriterSize(w, c.BuffSize)
} else {
Expand Down Expand Up @@ -264,47 +266,52 @@ func WithLevelNames(names []string) ConfigFn {
}
}

// WithRotateTime setting
// WithRotateTime setting rotate time
func WithRotateTime(rt rotatefile.RotateTime) ConfigFn {
return func(c *Config) { c.RotateTime = rt }
}

// WithRotateMode setting
// WithRotateMode setting rotate mode
func WithRotateMode(m rotatefile.RotateMode) ConfigFn {
return func(c *Config) { c.RotateMode = m }
}

// WithTimeClock setting
func WithTimeClock(clock rotatefile.Clocker) ConfigFn {
return func(c *Config) { c.TimeClock = clock }
}

// WithBackupNum setting
func WithBackupNum(n uint) ConfigFn {
return func(c *Config) { c.BackupNum = n }
}

// WithBackupTime setting
// WithBackupTime setting backup time
func WithBackupTime(bt uint) ConfigFn {
return func(c *Config) { c.BackupTime = bt }
}

// WithBuffMode setting
// WithBuffMode setting buffer mode
func WithBuffMode(buffMode string) ConfigFn {
return func(c *Config) { c.BuffMode = buffMode }
}

// WithBuffSize setting
// WithBuffSize setting buffer size
func WithBuffSize(buffSize int) ConfigFn {
return func(c *Config) { c.BuffSize = buffSize }
}

// WithMaxSize setting
// WithMaxSize setting max size for rotate file
func WithMaxSize(maxSize uint64) ConfigFn {
return func(c *Config) { c.MaxSize = maxSize }
}

// WithCompress setting
// WithCompress setting compress
func WithCompress(compress bool) ConfigFn {
return func(c *Config) { c.Compress = compress }
}

// WithUseJSON setting
// WithUseJSON setting use json format
func WithUseJSON(useJSON bool) ConfigFn {
return func(c *Config) { c.UseJSON = useJSON }
}
55 changes: 12 additions & 43 deletions handler/rotatefile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,40 +88,26 @@ func TestNewSizeRotateFileHandler(t *testing.T) {

func TestNewTimeRotateFileHandler_EveryDay(t *testing.T) {
logfile := "./testdata/time-rotate_EveryDay.log"
newFile := logfile + timex.Now().DateFormat(".Ymd")

sec := -2
// set current time to today 23:59:57
testClock := func() time.Time {
// dump.P(sec)
return timex.Now().DayEnd().AddSeconds(sec).Time
}
assert.Eq(t, "23:59:57", timex.Date(testClock(), "H:I:S"))

// backup
bckFn := rotatefile.DefaultTimeClockFn
rotatefile.DefaultTimeClockFn = testClock
defer func() {
rotatefile.DefaultTimeClockFn = bckFn
}()
newFile := logfile + ".20221116"

clock := rotatefile.NewMockClock("2022-11-16 23:59:57")
options := []handler.ConfigFn{
handler.WithBuffSize(128),
handler.WithTimeClock(clock),
}

h := handler.MustTimeRotateFile(logfile, handler.EveryDay, options...)
assert.True(t, fsutil.IsFile(logfile))

l := slog.NewWithHandlers(h)
l.ReportCaller = true
l.TimeClock = testClock
l.TimeClock = clock.Now

for i := 0; i < 4; i++ {
for i := 0; i < 6; i++ {
l.WithData(sampleData).Info("the th:", i, "info message")
l.Warnf("the th:%d warn message text", i)
sec++
fmt.Println("log number ", (i+1)*2)
// time.Sleep(time.Second * 1)
clock.Add(time.Second * 1)
}

l.MustClose()
Expand All @@ -130,29 +116,12 @@ func TestNewTimeRotateFileHandler_EveryDay(t *testing.T) {
}

func TestNewTimeRotateFileHandler_EveryHour(t *testing.T) {
clock := rotatefile.NewMockClock("2022-04-28 20:59:58")
logfile := "./testdata/time-rotate_EveryHour.log"
assert.NoErr(t, fsutil.DeleteIfExist(logfile))

hourStart := timex.Now().HourStart()
newFile := logfile + hourStart.DateFormat(".Ymd_H00")
assert.NoErr(t, fsutil.DeleteIfFileExist(newFile))

sec := -2
// set current time to hour end 59:58
testClock := func() time.Time {
// dump.P(sec)
return hourStart.AddHour(1).AddSeconds(sec).Time
}
assert.Eq(t, "59:58", timex.Date(testClock(), "I:S"))

// backup
bckFn := rotatefile.DefaultTimeClockFn
rotatefile.DefaultTimeClockFn = testClock
defer func() {
rotatefile.DefaultTimeClockFn = bckFn
}()
newFile := logfile + timex.DateFormat(clock.Now(), ".Ymd_H00")

options := []handler.ConfigFn{
handler.WithTimeClock(clock),
handler.WithBuffSize(0),
}
h, err := handler.NewTimeRotateFile(logfile, rotatefile.EveryHour, options...)
Expand All @@ -162,13 +131,13 @@ func TestNewTimeRotateFileHandler_EveryHour(t *testing.T) {

l := slog.NewWithHandlers(h)
l.ReportCaller = true
l.TimeClock = testClock
l.TimeClock = clock.Now

for i := 0; i < 3; i++ {
for i := 0; i < 6; i++ {
l.WithData(sampleData).Info("the th:", i, "info message")
l.Warnf("the th:%d warn message text", i)
sec++
fmt.Println("log number ", (i+1)*2)
clock.Add(time.Second * 1)
}
l.MustClose()

Expand Down
2 changes: 1 addition & 1 deletion handler/write_close_flusher.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func FlushCloserWithLevels(out FlushCloseWriter, levels []slog.Level) *FlushClos
//
// Usage:
//
// buf := new(bytes.Buffer)
// buf := new(byteutil.Buffer)
// h := handler.NewFlushCloseHandler(&buf, slog.AllLevels)
//
// f, err := os.OpenFile("my.log", ...)
Expand Down
2 changes: 1 addition & 1 deletion rotatefile/issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
func TestIssues_138(t *testing.T) {
logfile := "testdata/rotate_day.log"

mt := newMockTime("2023-11-16 23:59:55")
mt := rotatefile.NewMockClock("2023-11-16 23:59:55")
w, err := rotatefile.NewWriterWith(rotatefile.WithDebugMode, func(c *rotatefile.Config) {
c.TimeClock = mt
// c.MaxSize = 128
Expand Down
29 changes: 29 additions & 0 deletions rotatefile/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import (
"io"
"io/fs"
"os"
"time"

"github.com/gookit/goutil"
"github.com/gookit/goutil/fsutil"
"github.com/gookit/goutil/timex"
)

const compressSuffix = ".gz"
Expand Down Expand Up @@ -82,3 +85,29 @@ func (fis modTimeFInfos) Swap(i, j int) {
func (fis modTimeFInfos) Len() int {
return len(fis)
}

// MockClocker mock clock for test
type MockClocker struct {
tt time.Time
}

// NewMockClock create a mock time instance from datetime string.
func NewMockClock(datetime string) *MockClocker {
nt := goutil.Must(timex.FromString(datetime))
return &MockClocker{tt: nt.Time}
}

// Now get current time.
func (mt *MockClocker) Now() time.Time {
return mt.tt
}

// Add progresses time by the given duration.
func (mt *MockClocker) Add(d time.Duration) {
mt.tt = mt.tt.Add(d)
}

// Datetime returns the current time in the format "2006-01-02 15:04:05".
func (mt *MockClocker) Datetime() string {
return mt.tt.Format("2006-01-02 15:04:05")
}
26 changes: 0 additions & 26 deletions rotatefile/writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ import (
"testing"
"time"

"github.com/gookit/goutil"
"github.com/gookit/goutil/dump"
"github.com/gookit/goutil/fsutil"
"github.com/gookit/goutil/mathutil"
"github.com/gookit/goutil/testutil/assert"
"github.com/gookit/goutil/timex"
"github.com/gookit/slog/rotatefile"
)

Expand Down Expand Up @@ -140,27 +138,3 @@ func (c constantClock) Now() time.Time { return time.Time(c) }
func (c constantClock) NewTicker(d time.Duration) *time.Ticker {
return &time.Ticker{}
}

type mockTime struct {
tt time.Time
}

// newMockTime create a mock time instance from datetime string.
func newMockTime(datetime string) *mockTime {
nt := goutil.Must(timex.FromString(datetime))
return &mockTime{tt: nt.Time}
}

func (mt *mockTime) Now() time.Time {
return mt.tt
}

// Add progresses time by the given duration.
func (mt *mockTime) Add(d time.Duration) {
mt.tt = mt.tt.Add(d)
}

// Datetime returns the current time in the format "2006-01-02 15:04:05".
func (mt *mockTime) Datetime() string {
return mt.tt.Format("2006-01-02 15:04:05")
}

0 comments on commit 70031a7

Please sign in to comment.