Skip to content

Commit

Permalink
Add CombineWriteSyncers (#346)
Browse files Browse the repository at this point in the history
Split `zap.Open` into two functions, thereby exposing the tee-and-lock logic for direct use with `WriteSyncer`s.
  • Loading branch information
suyash authored and akshayjshah committed Mar 8, 2017
1 parent 4e517d3 commit 179e456
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 7 deletions.
21 changes: 14 additions & 7 deletions writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,13 @@ import (
// 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) {
if len(paths) == 0 {
return zapcore.AddSync(ioutil.Discard), func() {}, nil
}

writers, close, err := open(paths)
if len(writers) == 1 {
return zapcore.Lock(writers[0]), close, err
if err != nil {
return nil, nil, err
}
return zapcore.Lock(zapcore.NewMultiWriteSyncer(writers...)), close, err

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

func open(paths []string) ([]zapcore.WriteSyncer, func(), error) {
Expand Down Expand Up @@ -76,3 +74,12 @@ func open(paths []string) ([]zapcore.WriteSyncer, func(), error) {
}
return writers, close, errs.AsError()
}

// CombineWriteSyncers combines the passed set of WriteSyncer objects into a
// locked WriteSyncer.
func CombineWriteSyncers(writers ...zapcore.WriteSyncer) zapcore.WriteSyncer {
if len(writers) == 0 {
return zapcore.AddSync(ioutil.Discard)
}
return zapcore.Lock(zapcore.NewMultiWriteSyncer(writers...))
}
20 changes: 20 additions & 0 deletions writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,23 @@ func TestOpen(t *testing.T) {
assert.Equal(t, tt.filenames, names, "Opened unexpected files given paths %v.", tt.paths)
}
}

type testWriter struct {
expected string
t testing.TB
}

func (w *testWriter) Write(actual []byte) (int, error) {
assert.Equal(w.t, []byte(w.expected), actual, "Unexpected write error.")
return len(actual), nil
}

func (w *testWriter) Sync() error {
return nil
}

func TestCombineWriteSyncers(t *testing.T) {
tw := &testWriter{"test", t}
w := CombineWriteSyncers(tw)
w.Write([]byte("test"))
}
3 changes: 3 additions & 0 deletions zapcore/write_syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ type multiWriteSyncer []WriteSyncer
// NewMultiWriteSyncer creates a WriteSyncer that duplicates its writes
// and sync calls, much like io.MultiWriter.
func NewMultiWriteSyncer(ws ...WriteSyncer) WriteSyncer {
if len(ws) == 1 {
return ws[0]
}
// Copy to protect against https://github.com/golang/go/issues/7809
return multiWriteSyncer(append([]WriteSyncer(nil), ws...))
}
Expand Down
10 changes: 10 additions & 0 deletions zapcore/write_syncer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ func TestAddSyncWriter(t *testing.T) {
assert.NoError(t, ws.Sync(), "Unexpected error calling a no-op Sync method.")
}

func TestNewMultiWriteSyncerWorksForSingleWriter(t *testing.T) {
w := &testutils.Buffer{}

ws := NewMultiWriteSyncer(w)
assert.Equal(t, w, ws, "Expected NewMultiWriteSyncer to return the same WriteSyncer object for a single argument.")

ws.Sync()
assert.True(t, w.Called(), "Expected Sync to be called on the created WriteSyncer")
}

func TestMultiWriteSyncerWritesBoth(t *testing.T) {
first := &bytes.Buffer{}
second := &bytes.Buffer{}
Expand Down

0 comments on commit 179e456

Please sign in to comment.