Skip to content

Commit

Permalink
bug: make logging package concurrent-safe
Browse files Browse the repository at this point in the history
Fixes #486
  • Loading branch information
panjf2000 committed Jul 20, 2023
1 parent 6534df2 commit 8b78aff
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 10 deletions.
28 changes: 28 additions & 0 deletions gnet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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.Error(t, g.Wait())
}

var errIncompletePacket = errors.New("incomplete packet")

type simServer struct {
Expand Down
34 changes: 24 additions & 10 deletions pkg/logging/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import (
"errors"
"os"
"strconv"
"strings"
"sync"

"go.uber.org/zap"
Expand All @@ -63,6 +64,7 @@ import (
type Flusher = func() error

var (
mu sync.RWMutex
defaultLogger Logger
defaultLoggingLevel Level
defaultFlusher Flusher
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 8b78aff

Please sign in to comment.