Skip to content

Commit

Permalink
Make zaptest.NewTestingWriter public (#1399)
Browse files Browse the repository at this point in the history
**Add more flexibility in configuring zap logger for tests.**

The default `zapcore.Core`, which is created in `zaptest.NewLogger()`
may not be suitable for all use-cases.

```
func NewLogger(t TestingT, opts ...LoggerOption) *zap.Logger {
...
	return zap.New(
		zapcore.NewCore(
			zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()),
			writer,
			cfg.Level,
		),
		zapOptions...,
	)
```

E.g., we may need custom encoder or encoder config.

This PR allows us to do such customization:
```
writer := zaptest.NewTestingWriter(t)
core := zapcore.NewCore(encoder, writer, level)
logger := zap.New(core, zap.AddCaller())
```
  • Loading branch information
dimmo authored Jan 31, 2024
1 parent 70f61bb commit 27b96e3
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 11 deletions.
37 changes: 27 additions & 10 deletions zaptest/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func NewLogger(t TestingT, opts ...LoggerOption) *zap.Logger {
o.applyLoggerOption(&cfg)
}

writer := newTestingWriter(t)
writer := NewTestingWriter(t)
zapOptions := []zap.Option{
// Send zap errors to the same writer and mark the test as failed if
// that happens.
Expand All @@ -100,27 +100,43 @@ func NewLogger(t TestingT, opts ...LoggerOption) *zap.Logger {
)
}

// testingWriter is a WriteSyncer that writes to the given testing.TB.
type testingWriter struct {
// TestingWriter is a WriteSyncer that writes to the given testing.TB.
type TestingWriter struct {
t TestingT

// If true, the test will be marked as failed if this testingWriter is
// If true, the test will be marked as failed if this TestingWriter is
// ever used.
markFailed bool
}

func newTestingWriter(t TestingT) testingWriter {
return testingWriter{t: t}
// NewTestingWriter builds a new TestingWriter that writes to the given
// testing.TB.
//
// Use this if you need more flexibility when creating *zap.Logger
// than zaptest.NewLogger() provides.
//
// E.g., if you want to use custom core with zaptest.TestingWriter:
//
// encoder := newCustomEncoder()
// writer := zaptest.NewTestingWriter(t)
// level := zap.NewAtomicLevelAt(zapcore.DebugLevel)
//
// core := newCustomCore(encoder, writer, level)
//
// logger := zap.New(core, zap.AddCaller())
func NewTestingWriter(t TestingT) TestingWriter {
return TestingWriter{t: t}
}

// WithMarkFailed returns a copy of this testingWriter with markFailed set to
// WithMarkFailed returns a copy of this TestingWriter with markFailed set to
// the provided value.
func (w testingWriter) WithMarkFailed(v bool) testingWriter {
func (w TestingWriter) WithMarkFailed(v bool) TestingWriter {
w.markFailed = v
return w
}

func (w testingWriter) Write(p []byte) (n int, err error) {
// Write writes bytes from p to the underlying testing.TB.
func (w TestingWriter) Write(p []byte) (n int, err error) {
n = len(p)

// Strip trailing newline because t.Log always adds one.
Expand All @@ -135,6 +151,7 @@ func (w testingWriter) Write(p []byte) (n int, err error) {
return n, nil
}

func (w testingWriter) Sync() error {
// Sync commits the current contents (a no-op for TestingWriter).
func (w TestingWriter) Sync() error {
return nil
}
2 changes: 1 addition & 1 deletion zaptest/logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func TestTestLoggerSupportsWrappedZapOptions(t *testing.T) {

func TestTestingWriter(t *testing.T) {
ts := newTestLogSpy(t)
w := newTestingWriter(ts)
w := NewTestingWriter(ts)

n, err := io.WriteString(w, "hello\n\n")
assert.NoError(t, err, "WriteString must not fail")
Expand Down

0 comments on commit 27b96e3

Please sign in to comment.