70 lines
1.3 KiB
Go
70 lines
1.3 KiB
Go
package log
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"sync"
|
|
)
|
|
|
|
type WriteSyncer interface {
|
|
io.Writer
|
|
Sync() error
|
|
}
|
|
|
|
// WrapOsFile wraps an *os.File in a WriteSyncer.
|
|
//
|
|
// To support multithreaded logging and to support
|
|
// flushing the buffer before the program exits.
|
|
func WrapOsFile(f *os.File) WriteSyncer {
|
|
return Lock(f)
|
|
}
|
|
|
|
// AddSync converts an io.Writer to a WriteSyncer. It attempts to be
|
|
// intelligent: if the concrete type of the io.Writer implements WriteSyncer,
|
|
// we'll use the existing Sync method. If it doesn't, we'll add a no-op Sync.
|
|
func AddSync(w io.Writer) WriteSyncer {
|
|
switch w := w.(type) {
|
|
case WriteSyncer:
|
|
return w
|
|
default:
|
|
return writerWrapper{w}
|
|
}
|
|
}
|
|
|
|
type lockedWriteSyncer struct {
|
|
sync.Mutex
|
|
ws WriteSyncer
|
|
}
|
|
|
|
// Lock wraps a WriteSyncer in a mutex to make it safe for concurrent use. In
|
|
// particular, *os.Files must be locked before use.
|
|
func Lock(ws WriteSyncer) WriteSyncer {
|
|
if _, ok := ws.(*lockedWriteSyncer); ok {
|
|
// no need to layer on another lock
|
|
return ws
|
|
}
|
|
return &lockedWriteSyncer{ws: ws}
|
|
}
|
|
|
|
func (s *lockedWriteSyncer) Write(bs []byte) (int, error) {
|
|
s.Lock()
|
|
n, err := s.ws.Write(bs)
|
|
s.Unlock()
|
|
return n, err
|
|
}
|
|
|
|
func (s *lockedWriteSyncer) Sync() error {
|
|
s.Lock()
|
|
err := s.ws.Sync()
|
|
s.Unlock()
|
|
return err
|
|
}
|
|
|
|
type writerWrapper struct {
|
|
io.Writer
|
|
}
|
|
|
|
func (w writerWrapper) Sync() error {
|
|
return nil
|
|
}
|