diff --git a/gnet_test.go b/gnet_test.go index 22eae807b..abf5ee569 100644 --- a/gnet_test.go +++ b/gnet_test.go @@ -17,6 +17,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" + "golang.org/x/sync/errgroup" gerr "github.com/panjf2000/gnet/v2/pkg/errors" "github.com/panjf2000/gnet/v2/pkg/logging" @@ -1135,6 +1136,33 @@ func (s *testClosedWakeUpServer) OnClose(Conn, error) (action Action) { return } +type testMultiInstLoggerRaceServer struct { + *BuiltinEventEngine +} + +func (t *testMultiInstLoggerRaceServer) OnBoot(_ Engine) (action Action) { + return Shutdown +} + +func TestMultiInstLoggerRace(t *testing.T) { + logger1, _ := zap.NewDevelopment() + events1 := new(testMultiInstLoggerRaceServer) + g := errgroup.Group{} + g.Go(func() error { + err := Run(events1, "tulip://howdy", WithLogger(logger1.Sugar())) + return err + }) + + logger2, _ := zap.NewDevelopment() + events2 := new(testMultiInstLoggerRaceServer) + g.Go(func() error { + err := Run(events2, "tulip://howdy", WithLogger(logger2.Sugar())) + return err + }) + + assert.ErrorIs(t, g.Wait(), gerr.ErrUnsupportedProtocol) +} + var errIncompletePacket = errors.New("incomplete packet") type simServer struct { diff --git a/go.mod b/go.mod index 69962a960..f47d80576 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/panjf2000/gnet/v2 require ( - github.com/panjf2000/ants/v2 v2.7.4 + github.com/panjf2000/ants/v2 v2.8.1 github.com/stretchr/testify v1.8.2 github.com/valyala/bytebufferpool v1.0.0 go.uber.org/zap v1.21.0 diff --git a/go.sum b/go.sum index a1055fd27..f10e6e250 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/panjf2000/ants/v2 v2.7.4 h1:mJqMDtMckZltyL458pq81IGNfiDhEgzX5s/lhjwPWIM= -github.com/panjf2000/ants/v2 v2.7.4/go.mod h1:KIBmYG9QQX5U2qzFP/yQJaq/nSb6rahS9iEHkrCMgM8= +github.com/panjf2000/ants/v2 v2.8.1 h1:C+n/f++aiW8kHCExKlpX6X+okmxKXP7DWLutxuAPuwQ= +github.com/panjf2000/ants/v2 v2.8.1/go.mod h1:KIBmYG9QQX5U2qzFP/yQJaq/nSb6rahS9iEHkrCMgM8= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/pkg/logging/logger.go b/pkg/logging/logger.go index 784aba2ec..86ad17e93 100644 --- a/pkg/logging/logger.go +++ b/pkg/logging/logger.go @@ -50,6 +50,7 @@ import ( "errors" "os" "strconv" + "strings" "sync" "go.uber.org/zap" @@ -63,6 +64,7 @@ import ( type Flusher = func() error var ( + mu sync.RWMutex defaultLogger Logger defaultLoggingLevel Level defaultFlusher Flusher @@ -171,30 +173,28 @@ func getProdEncoder() zapcore.Encoder { // GetDefaultLogger returns the default logger. func GetDefaultLogger() Logger { + mu.RLock() + defer mu.RUnlock() return defaultLogger } // GetDefaultFlusher returns the default flusher. func GetDefaultFlusher() Flusher { + mu.RLock() + defer mu.RUnlock() return defaultFlusher } -var setupOnce sync.Once - // SetDefaultLoggerAndFlusher sets the default logger and its flusher. -// -// Note that this function should only be called once at the -// start of the program and not thereafter for the entire runtime, -// otherwise it will only keep the first setup. func SetDefaultLoggerAndFlusher(logger Logger, flusher Flusher) { - setupOnce.Do(func() { - defaultLogger, defaultFlusher = logger, flusher - }) + mu.Lock() + defaultLogger, defaultFlusher = logger, flusher + mu.Unlock() } // LogLevel tells what the default logging level is. func LogLevel() string { - return defaultLoggingLevel.String() + return strings.ToUpper(defaultLoggingLevel.String()) } // CreateLoggerAsLocalFile setups the logger by local file path. @@ -227,41 +227,55 @@ func CreateLoggerAsLocalFile(localFilePath string, logLevel Level) (logger Logge // Cleanup does something windup for logger, like closing, flushing, etc. func Cleanup() { + mu.RLock() if defaultFlusher != nil { _ = defaultFlusher() } + mu.RUnlock() } // Error prints err if it's not nil. func Error(err error) { if err != nil { + mu.RLock() defaultLogger.Errorf("error occurs during runtime, %v", err) + mu.RUnlock() } } // Debugf logs messages at DEBUG level. func Debugf(format string, args ...interface{}) { + mu.RLock() defaultLogger.Debugf(format, args...) + mu.RUnlock() } // Infof logs messages at INFO level. func Infof(format string, args ...interface{}) { + mu.RLock() defaultLogger.Infof(format, args...) + mu.RUnlock() } // Warnf logs messages at WARN level. func Warnf(format string, args ...interface{}) { + mu.RLock() defaultLogger.Warnf(format, args...) + mu.RUnlock() } // Errorf logs messages at ERROR level. func Errorf(format string, args ...interface{}) { + mu.RLock() defaultLogger.Errorf(format, args...) + mu.RUnlock() } // Fatalf logs messages at FATAL level. func Fatalf(format string, args ...interface{}) { + mu.RLock() defaultLogger.Fatalf(format, args...) + mu.RUnlock() } // Logger is used for logging formatted messages.