type WriteSyncer … // 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 { … } type lockedWriteSyncer … // 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 { … } func (s *lockedWriteSyncer) Write(bs []byte) (int, error) { … } func (s *lockedWriteSyncer) Sync() error { … } type writerWrapper … func (w writerWrapper) Sync() error { … } type multiWriteSyncer … // NewMultiWriteSyncer creates a WriteSyncer that duplicates its writes // and sync calls, much like io.MultiWriter. func NewMultiWriteSyncer(ws ...WriteSyncer) WriteSyncer { … } // See https://golang.org/src/io/multi.go // When not all underlying syncers write the same number of bytes, // the smallest number is returned even though Write() is called on // all of them. func (ws multiWriteSyncer) Write(p []byte) (int, error) { … } func (ws multiWriteSyncer) Sync() error { … }