diff --git a/_examples/logging/request-logger/accesslog-formatter/main.go b/_examples/logging/request-logger/accesslog-formatter/main.go index 851cee19..5e0bfe04 100644 --- a/_examples/logging/request-logger/accesslog-formatter/main.go +++ b/_examples/logging/request-logger/accesslog-formatter/main.go @@ -1,4 +1,4 @@ -// Package main shows to create a quite fast custom Log Formatter. +// Package main shows how to create a quite fast custom Log Formatter. // Note that, this example requires a little more knowledge about Go. package main diff --git a/middleware/accesslog/accesslog.go b/middleware/accesslog/accesslog.go index 31dbcb1d..ea916970 100644 --- a/middleware/accesslog/accesslog.go +++ b/middleware/accesslog/accesslog.go @@ -114,6 +114,9 @@ type AccessLog struct { // File type destinations are automatically added. Flushers []Flusher Closers []io.Closer + // Outputs that support the Truncate method. + BufferTruncaters []BufferTruncater + FileTruncaters []FileTruncater // If not empty then overrides the time.Now to this custom clocker's `Now` method, // useful for testing (see `TClock`) and @@ -361,6 +364,14 @@ func (ac *AccessLog) SetOutput(writers ...io.Writer) *AccessLog { if closer, ok := w.(io.Closer); ok { ac.Closers = append(ac.Closers, closer) } + + if truncater, ok := w.(BufferTruncater); ok { + ac.BufferTruncaters = append(ac.BufferTruncaters, truncater) + } + + if truncater, ok := w.(FileTruncater); ok { + ac.FileTruncaters = append(ac.FileTruncaters, truncater) + } } // ac.bufWriter = bufio.NewWriterSize(ac.Writer, 4096) @@ -420,6 +431,39 @@ func (ac *AccessLog) Flush() (err error) { return } +// Truncate if the output is a buffer, then +// it discards all but the first n unread bytes. +// See `TruncateFile` for a file size. +// +// It panics if n is negative or greater than the length of the buffer. +func (ac *AccessLog) Truncate(n int) { + ac.mu.Lock() // Lock as we do with all write operations. + for _, truncater := range ac.BufferTruncaters { + truncater.Truncate(n) + } + ac.mu.Unlock() +} + +// TruncateFile changes the size of the internal file, directly. +// It does not change the I/O offset. +// If there is an error, it will be of type *PathError. +func (ac *AccessLog) TruncateFile(size int64) (err error) { + ac.mu.Lock() + for _, truncater := range ac.FileTruncaters { + tErr := truncater.Truncate(size) + if tErr != nil { + if err == nil { + err = tErr + } else { + err = fmt.Errorf("%v, %v", err, tErr) + } + } + } + ac.mu.Unlock() + + return +} + // SetFormatter sets a custom formatter to print the logs. // Any custom output writers should be // already registered before calling this method. diff --git a/middleware/accesslog/log.go b/middleware/accesslog/log.go index 684675eb..517df92c 100644 --- a/middleware/accesslog/log.go +++ b/middleware/accesslog/log.go @@ -169,10 +169,16 @@ type ( Format(log *Log) (bool, error) } - // Flusher can be implemented by a Formatter + // Flusher can be implemented by a Writer or Formatter // to call its Flush method on AccessLog.Close // and on panic errors. Flusher interface{ Flush() error } + // BufferTruncater can be implemented by writers + // that support buffering. + BufferTruncater interface{ Truncate(n int) } + // FileTruncater can be implemented by files + // that can support runtime size change. + FileTruncater interface{ Truncate(size int64) error } ) var (