Repository: uber-go/zap
File: writer.go (Go)

Code before:
//
// Passing no paths returns a no-op WriteSyncer. The special paths "stdout" and
// "stderr" are interpreted as os.Stdout and os.Stderr, respectively.
func Open(paths ...string) (zapcore.WriteSyncer, func(), error) {
	writers, close, err := open(paths)
	if err != nil {
		return nil, nil, err
	}

	writer := CombineWriteSyncers(writers...)
	return writer, close, nil
}

func open(paths []string) ([]zapcore.WriteSyncer, func(), error) {
	var openErr error
	writers := make([]zapcore.WriteSyncer, 0, len(paths))
	closers := make([]io.Closer, 0, len(paths))
	close := func() {
		for _, c := range closers {
			c.Close()
		}
	}
	for _, path := range paths {
		if sink, err := NewSink(path); err == nil {
			writers = append(writers, sink)
			closers = append(closers, sink)
			continue
		} else if err == errSinkNotFound {
			f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
			openErr = multierr.Append(openErr, err)
			if err == nil {
				writers = append(writers, f)
				closers = append(closers, f)
			}
		} else {
			openErr = multierr.Append(openErr, err)
		}
	}

	if openErr != nil {
		close()
		return writers, nil, openErr
	}

	return writers, close, nil
}

// CombineWriteSyncers is a utility that combines multiple WriteSyncers into a
// single, locked WriteSyncer. If no inputs are supplied, it returns a no-op
// WriteSyncer.
//

Review comment (refactor):
I kept the two lists, `writers` and `closers`, because I didn't want to be too aggressive with the refactor and change the return value of 
`func open(paths []string) ([]zapcore.WriteSyncer, func(), error)`
to
`func open(paths []string) ([]Sink, func(), error)`

It would have rippled out to affect a few other funcs and we would have needed an array of `[]zapcore.WriteSyncer` for `CombineWriteSyncers` anyways.

Code after:
//
// Passing no paths returns a no-op WriteSyncer. The special paths "stdout" and
// "stderr" are interpreted as os.Stdout and os.Stderr, respectively.
func Open(paths ...string) (zapcore.WriteSyncer, func(), error) {
	writers, close, err := open(paths)
	if err != nil {
		return nil, nil, err
	}

	writer := CombineWriteSyncers(writers...)
	return writer, close, nil
}

func open(paths []string) ([]zapcore.WriteSyncer, func(), error) {
	var openErr error
	writers := make([]zapcore.WriteSyncer, 0, len(paths))
	closers := make([]io.Closer, 0, len(paths))
	close := func() {
		for _, c := range closers {
			c.Close()
		}
	}
	for _, path := range paths {
		sink, err := newSink(path)
		if err == nil {
			// Using a registered sink constructor.
			writers = append(writers, sink)
			closers = append(closers, sink)
			continue
		}
		if _, ok := err.(*errSinkNotFound); ok {
			// No named sink constructor, use key as path to log file.
			f, e := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
			openErr = multierr.Append(openErr, e)
			if e == nil {
				writers = append(writers, f)
				closers = append(closers, f)
			}
			continue
		}
		// Sink constructor failed.
		openErr = multierr.Append(openErr, err)
	}

	if openErr != nil {
		close()
		return writers, nil, openErr
	}

	return writers, close, nil
}