diff --git a/README.md b/README.md index be4ad1c..5b54a37 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ Result: ``` ## 4.3. FileAppender -LogEventをファイルに出力します。内部で4096Byteをデフォルトでバッファし、容量超えた場合にFlushを行います。 +LogEventをファイルに出力します。内部で4096Byteをデフォルトでバッファし、容量超えた場合か一定時間ごとにFlushを行います。 また、バッファの内容はAppenderもしくはLoggerのCloserによってFlushされます。 アプリケーションの終了時やpanicリカバリーのタイミングでcloseを実行し、バッファが確実に出力されるように実装してください。 diff --git a/appender_file.go b/appender_file.go index 3442e3d..c477fd0 100644 --- a/appender_file.go +++ b/appender_file.go @@ -1,39 +1,35 @@ package golog import ( + "context" "fmt" "os" "sync" + "time" ) // defaultBufferSize const defaultBufferSize = 4096 +const defaultFlushInterval = time.Minute * 5 + // FileAppender type FileAppender struct { file *os.File bufferedWriter *bufferedWriter mu *sync.Mutex activated bool + ticker *time.Ticker + stopTicker context.CancelFunc } // NewFileAppender returns new FileAppender func NewFileAppender(fileName string) (asyncFileAppender *FileAppender, err error) { - file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - return nil, err - } - - return &FileAppender{ - file: file, - bufferedWriter: newBufferedWriter(file, withBufferSize(defaultBufferSize)), - mu: new(sync.Mutex), - activated: true, - }, nil + return NewFileAppenderWithBufferSizeAndFlushInterval(fileName, defaultBufferSize, defaultFlushInterval) } -// NewFileAppender returns new FileAppender -func NewFileAppenderWithBufferSize(fileName string, bufferSize int) (asyncFileAppender *FileAppender, err error) { +// NewFileAppenderWithBufferSizeAndFlushInterval returns new FileAppender +func NewFileAppenderWithBufferSizeAndFlushInterval(fileName string, bufferSize int, flushInterval time.Duration) (asyncFileAppender *FileAppender, err error) { file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) if err != nil { return nil, err @@ -44,12 +40,34 @@ func NewFileAppenderWithBufferSize(fileName string, bufferSize int) (asyncFileAp size = bufferSize } - return &FileAppender{ + ctx, cancel := context.WithCancel(context.Background()) + appender := &FileAppender{ file: file, bufferedWriter: newBufferedWriter(file, withBufferSize(size)), mu: new(sync.Mutex), activated: true, - }, nil + ticker: time.NewTicker(flushInterval), + stopTicker: cancel, + } + + go func() { + for { + select { + case <-appender.ticker.C: + case <-ctx.Done(): + } + appender.mu.Lock() + if !appender.activated { + appender.ticker.Stop() + appender.mu.Unlock() + return + } + appender.bufferedWriter.Flush() + appender.mu.Unlock() + } + }() + + return appender, nil } // Write implements io.Write @@ -67,8 +85,9 @@ func (appender *FileAppender) Write(data []byte) (n int, err error) { func (appender *FileAppender) Close() error { appender.mu.Lock() defer func() { - appender.mu.Unlock() appender.activated = false + appender.stopTicker() + appender.mu.Unlock() }() if appender.activated { diff --git a/appender_file_rotatable.go b/appender_file_rotatable.go index 5860095..46f8126 100644 --- a/appender_file_rotatable.go +++ b/appender_file_rotatable.go @@ -5,6 +5,7 @@ import ( "os/signal" "sync" "syscall" + "time" ) // RotatableFileAppender RotatableFileAppender struct @@ -20,8 +21,13 @@ func NewRotatableFileAppender(fileName string) (asyncFileAppender *RotatableFile // NewRotatableFileAppenderWithBufferSize returns new FileAppender func NewRotatableFileAppenderWithBufferSize(fileName string, bufferSize int) (asyncFileAppender *RotatableFileAppender, err error) { + return NewRotatableFileAppenderWithBufferSizeAndFlushInterval(fileName, bufferSize, defaultFlushInterval) +} + +// NewRotatableFileAppenderWithBufferSizeAndFlushInterval returns new FileAppender +func NewRotatableFileAppenderWithBufferSizeAndFlushInterval(fileName string, bufferSize int, flushInterval time.Duration) (asyncFileAppender *RotatableFileAppender, err error) { - fileAppender, err := NewFileAppenderWithBufferSize(fileName, bufferSize) + fileAppender, err := NewFileAppenderWithBufferSizeAndFlushInterval(fileName, bufferSize, flushInterval) if err != nil { return nil, err } @@ -41,7 +47,7 @@ func NewRotatableFileAppenderWithBufferSize(fileName string, bufferSize int) (as appender.FileAppender.Close() - newAppender, err := NewFileAppenderWithBufferSize(fileName, bufferSize) + newAppender, err := NewFileAppenderWithBufferSizeAndFlushInterval(fileName, bufferSize, flushInterval) if err != nil { panic(err) }