diff --git a/example_test.go b/example_test.go index 4c2c685..4c0a969 100644 --- a/example_test.go +++ b/example_test.go @@ -1,6 +1,10 @@ package slog_test import ( + "fmt" + "sync" + "time" + "github.com/gookit/slog" "github.com/gookit/slog/handler" ) @@ -56,3 +60,25 @@ func ExampleNew() { mylog.Warn("warning log message") mylog.Infof("info log %s", "message") } + +func ExampleFlushDaemon() { + wg := sync.WaitGroup{} + wg.Add(1) + + go slog.FlushDaemon(func() { + fmt.Println("flush daemon stopped") + wg.Done() + }) + + go func() { + // mock app running + time.Sleep(time.Second * 2) + + // stop daemon + fmt.Println("stop flush daemon") + slog.StopDaemon() + }() + + // wait for stop + wg.Wait() +} diff --git a/logger.go b/logger.go index 5cb7fe9..26bc307 100644 --- a/logger.go +++ b/logger.go @@ -24,6 +24,7 @@ type Logger struct { recordPool sync.Pool // handlers on exit. exitHandlers []func() + quitDaemon chan struct{} // // logger options @@ -31,6 +32,8 @@ type Logger struct { // ChannelName log channel name, default is DefaultChannelName ChannelName string + // FlushInterval flush interval time. default is defaultFlushInterval=30s + FlushInterval time.Duration // LowerLevelName use lower level name LowerLevelName bool // ReportCaller on write log record @@ -76,6 +79,8 @@ func NewWithName(name string, fns ...LoggerFn) *Logger { ReportCaller: true, CallerSkip: 6, TimeClock: DefaultClockFn, + // flush interval time + FlushInterval: defaultFlushInterval, } logger.recordPool.New = func() any { @@ -149,21 +154,44 @@ func (l *Logger) Name() string { return l.name } // --------------------------------------------------------------------------- // -const flushInterval = 30 * time.Second +const defaultFlushInterval = 30 * time.Second // FlushDaemon run flush handle on daemon // -// Usage: -// -// go slog.FlushDaemon() -func (l *Logger) FlushDaemon() { - for range time.NewTicker(flushInterval).C { - if err := l.lockAndFlushAll(); err != nil { - printlnStderr("slog.FlushDaemon: daemon flush logs error: ", err) +// Usage please refer to the FlushDaemon() on package. +func (l *Logger) FlushDaemon(onStops ...func()) { + l.quitDaemon = make(chan struct{}) + if l.FlushInterval <= 0 { + l.FlushInterval = defaultFlushInterval + } + + // create a ticker + tk := time.NewTicker(l.FlushInterval) + defer tk.Stop() + + for { + select { + case <-tk.C: + if err := l.lockAndFlushAll(); err != nil { + printlnStderr("slog.FlushDaemon: daemon flush logs error: ", err) + } + case <-l.quitDaemon: + for _, fn := range onStops { + fn() + } + return } } } +// StopDaemon stop flush daemon +func (l *Logger) StopDaemon() { + if l.quitDaemon == nil { + panic("cannot quit daemon, please call FlushDaemon() first") + } + close(l.quitDaemon) +} + // FlushTimeout flush logs on limit time. // // refer from glog package diff --git a/slog.go b/slog.go index 361f2dd..cd1886a 100644 --- a/slog.go +++ b/slog.go @@ -80,14 +80,17 @@ func MustFlush() { goutil.PanicErr(Flush()) } // FlushTimeout flush logs with timeout. func FlushTimeout(timeout time.Duration) { std.FlushTimeout(timeout) } -// FlushDaemon run flush handle on daemon +// FlushDaemon run flush handle on daemon. // -// Usage: -// -// go slog.FlushDaemon() -func FlushDaemon() { std.FlushDaemon() } +// Usage please see ExampleFlushDaemon() +func FlushDaemon(onStops ...func()) { + std.FlushDaemon(onStops...) +} + +// StopDaemon stop flush daemon +func StopDaemon() { std.StopDaemon() } -// SetLogLevel for the std logger +// SetLogLevel max level for the std logger func SetLogLevel(l Level) { std.Level = l } // SetFormatter to std logger diff --git a/slog_test.go b/slog_test.go index e0f0f7c..49b1f27 100644 --- a/slog_test.go +++ b/slog_test.go @@ -5,7 +5,9 @@ import ( "errors" "fmt" "strconv" + "sync" "testing" + "time" "github.com/gookit/goutil/byteutil" "github.com/gookit/goutil/errorx" @@ -64,6 +66,39 @@ func TestTextFormatNoColor(t *testing.T) { func TestFlushDaemon(t *testing.T) { defer slog.Reset() + + buf := byteutil.NewBuffer() + slog.Configure(func(l *slog.SugaredLogger) { + l.FlushInterval = timex.Millisecond * 100 + l.Output = buf + }) + + wg := sync.WaitGroup{} + wg.Add(1) + + go slog.FlushDaemon(func() { + fmt.Println("flush daemon stopped") + wg.Done() + }) + + go func() { + // mock app running + time.Sleep(time.Second * 1) + + // stop daemon + fmt.Println("stop flush daemon") + slog.StopDaemon() + }() + + slog.Info("print log message") + + wg.Wait() + + fmt.Print(buf.ResetGet()) +} + +func TestFlushTimeout(t *testing.T) { + defer slog.Reset() slog.Info("print log message") slog.FlushTimeout(timex.Second * 1) }