@@ -22,12 +22,12 @@ package testlogger
2222
2323import (
2424 "fmt"
25+ "go.uber.org/cadence/internal/common"
2526 "slices"
2627 "strings"
2728 "sync"
2829
2930 "github.com/stretchr/testify/require"
30- "go.uber.org/atomic"
3131 "go.uber.org/zap"
3232 "go.uber.org/zap/zapcore"
3333 "go.uber.org/zap/zaptest"
@@ -58,10 +58,11 @@ func NewZap(t TestingT) *zap.Logger {
5858 logAfterComplete , err := zap .NewDevelopment ()
5959 require .NoError (t , err , "could not build a fallback zap logger" )
6060 replaced := & fallbackTestCore {
61+ mu : & sync.RWMutex {},
6162 t : t ,
6263 fallback : logAfterComplete .Core (),
6364 testing : zaptest .NewLogger (t ).Core (),
64- completed : & atomic. Bool {} ,
65+ completed : common . PtrOf ( false ) ,
6566 }
6667
6768 t .Cleanup (replaced .UseFallback ) // switch to fallback before ending the test
@@ -81,30 +82,38 @@ func NewObserved(t TestingT) (*zap.Logger, *observer.ObservedLogs) {
8182}
8283
8384type fallbackTestCore struct {
84- sync.Mutex
85+ mu * sync.RWMutex
8586 t TestingT
8687 fallback zapcore.Core
8788 testing zapcore.Core
88- completed * atomic. Bool
89+ completed * bool
8990}
9091
9192var _ zapcore.Core = (* fallbackTestCore )(nil )
9293
9394func (f * fallbackTestCore ) UseFallback () {
94- f .completed .Store (true )
95+ f .mu .Lock ()
96+ defer f .mu .Unlock ()
97+ * f .completed = true
9598}
9699
97100func (f * fallbackTestCore ) Enabled (level zapcore.Level ) bool {
98- if f .completed .Load () {
101+ f .mu .RLock ()
102+ defer f .mu .RUnlock ()
103+ if f .completed != nil && * f .completed {
99104 return f .fallback .Enabled (level )
100105 }
101106 return f .testing .Enabled (level )
102107}
103108
104109func (f * fallbackTestCore ) With (fields []zapcore.Field ) zapcore.Core {
110+ f .mu .Lock ()
111+ defer f .mu .Unlock ()
112+
105113 // need to copy and defer, else the returned core will be used at an
106114 // arbitrarily later point in time, possibly after the test has completed.
107115 return & fallbackTestCore {
116+ mu : f .mu ,
108117 t : f .t ,
109118 fallback : f .fallback .With (fields ),
110119 testing : f .testing .With (fields ),
@@ -113,6 +122,8 @@ func (f *fallbackTestCore) With(fields []zapcore.Field) zapcore.Core {
113122}
114123
115124func (f * fallbackTestCore ) Check (entry zapcore.Entry , checked * zapcore.CheckedEntry ) * zapcore.CheckedEntry {
125+ f .mu .RLock ()
126+ defer f .mu .RUnlock ()
116127 // see other Check impls, all look similar.
117128 // this defers the "where to log" decision to Write, as `f` is the core that will write.
118129 if f .fallback .Enabled (entry .Level ) {
@@ -122,7 +133,10 @@ func (f *fallbackTestCore) Check(entry zapcore.Entry, checked *zapcore.CheckedEn
122133}
123134
124135func (f * fallbackTestCore ) Write (entry zapcore.Entry , fields []zapcore.Field ) error {
125- if f .completed .Load () {
136+ f .mu .RLock ()
137+ defer f .mu .RUnlock ()
138+
139+ if common .ValueFromPtr (f .completed ) {
126140 entry .Message = fmt .Sprintf ("COULD FAIL TEST %q, logged too late: %v" , f .t .Name (), entry .Message )
127141
128142 hasStack := slices .ContainsFunc (fields , func (field zapcore.Field ) bool {
@@ -134,14 +148,14 @@ func (f *fallbackTestCore) Write(entry zapcore.Entry, fields []zapcore.Field) er
134148 }
135149 return f .fallback .Write (entry , fields )
136150 }
137- // Ensure no concurrent writes to the test logger.
138- f .Lock ()
139- defer f .Unlock ()
140151 return f .testing .Write (entry , fields )
141152}
142153
143154func (f * fallbackTestCore ) Sync () error {
144- if f .completed .Load () {
155+ f .mu .RLock ()
156+ defer f .mu .RUnlock ()
157+
158+ if common .ValueFromPtr (f .completed ) {
145159 return f .fallback .Sync ()
146160 }
147161 return f .testing .Sync ()
0 commit comments