From f56df58fe8a8615c75214ebe3424be3764651461 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Tue, 14 Dec 2021 16:30:06 -0500 Subject: [PATCH] testing,log: add testing.T logger connector (#7447) --- libs/log/testing.go | 56 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/libs/log/testing.go b/libs/log/testing.go index 9894f6a50..b76bb77c6 100644 --- a/libs/log/testing.go +++ b/libs/log/testing.go @@ -1,10 +1,10 @@ package log import ( - "io" - "os" "sync" "testing" + + "github.com/rs/zerolog" ) var ( @@ -19,11 +19,11 @@ var ( // NOTE: // - A call to NewTestingLogger() must be made inside a test (not in the init func) // because verbose flag only set at the time of testing. +// - Repeated calls to this function within a single process will +// produce a single test log instance, and while the logger is safe +// for parallel use it it doesn't produce meaningful feedback for +// parallel tests. func TestingLogger() Logger { - return TestingLoggerWithOutput(os.Stdout) -} - -func TestingLoggerWithOutput(w io.Writer) Logger { testingLoggerMtx.Lock() defer testingLoggerMtx.Unlock() @@ -39,3 +39,47 @@ func TestingLoggerWithOutput(w io.Writer) Logger { return testingLogger } + +type testingWriter struct { + t testing.TB +} + +func (tw testingWriter) Write(in []byte) (int, error) { + tw.t.Log(string(in)) + return len(in), nil +} + +// NewTestingLogger converts a testing.T into a logging interface to +// make test failures and verbose provide better feedback associated +// with test failures. This logging instance is safe for use from +// multiple threads, but in general you should create one of these +// loggers ONCE for each *testing.T instance that you interact with. +// +// By default it collects only ERROR messages, or DEBUG messages in +// verbose mode, and relies on the underlying behavior of testing.T.Log() +func NewTestingLogger(t testing.TB) Logger { + level := LogLevelError + if testing.Verbose() { + level = LogLevelDebug + } + + return NewTestingLoggerWithLevel(t, level) +} + +// NewTestingLoggerWithLevel creates a testing logger instance at a +// specific level that wraps the behavior of testing.T.Log(). +func NewTestingLoggerWithLevel(t testing.TB, level string) Logger { + logLevel, err := zerolog.ParseLevel(level) + if err != nil { + t.Fatalf("failed to parse log level (%s): %v", level, err) + } + trace := false + if testing.Verbose() { + trace = true + } + + return defaultLogger{ + Logger: zerolog.New(newSyncWriter(testingWriter{t})).Level(logLevel), + trace: trace, + } +}