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 }