From 57f9f96a16a6388b3bc18c2a7f5538c9ce4d77fc Mon Sep 17 00:00:00 2001 From: water <672684719@qq.com> Date: Tue, 28 Jul 2026 18:13:35 +0800 Subject: [PATCH 1/4] fix: protect Logger.config with sync.RWMutex to prevent data race (#4795) --- os/glog/glog_logger.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/os/glog/glog_logger.go b/os/glog/glog_logger.go index b64a0ae1177..1ec2c457494 100644 --- a/os/glog/glog_logger.go +++ b/os/glog/glog_logger.go @@ -14,6 +14,7 @@ import ( "os" "runtime" "strings" + "sync" "time" "github.com/fatih/color" @@ -36,6 +37,7 @@ import ( type Logger struct { parent *Logger // Parent logger, if it is not empty, it means the logger is used in chaining function. config Config // Logger configuration. + mu sync.RWMutex } const ( @@ -76,6 +78,8 @@ func NewWithWriter(writer io.Writer) *Logger { // Clone returns a new logger, which a `shallow copy` of the current logger. // Note that the attribute `config` of the cloned one is the shallow copy of current one. func (l *Logger) Clone() *Logger { + l.mu.RLock() + defer l.mu.RUnlock() return &Logger{ config: l.config, parent: l, @@ -95,6 +99,8 @@ func (l *Logger) getFilePath(now time.Time) string { // print prints `s` to defined writer, logging file or passed `std`. func (l *Logger) print(ctx context.Context, level int, stack string, values ...any) { + l.mu.RLock() + defer l.mu.RUnlock() // Lazy initialize for rotation feature. // It uses atomic reading operation to enhance the performance checking. // It here uses CAP for performance and concurrent safety. @@ -222,6 +228,8 @@ func (l *Logger) print(ctx context.Context, level int, stack string, values ...a // doFinalPrint outputs the logging content according configuration. func (l *Logger) doFinalPrint(ctx context.Context, input *HandlerInput) *bytes.Buffer { + l.mu.RLock() + defer l.mu.RUnlock() var buffer *bytes.Buffer // Allow output to stdout? if l.config.StdoutPrint { @@ -369,10 +377,12 @@ func (l *Logger) printErr(ctx context.Context, level int, values ...any) { if l == nil { return } + l.mu.RLock() var stack string if l.config.StStatus == 1 { stack = l.GetStack() } + l.mu.RUnlock() // In matter of sequence, do not use stderr here, but use the same stdout. l.print(ctx, level, stack, values...) } @@ -395,6 +405,8 @@ func (l *Logger) PrintStack(ctx context.Context, skip ...int) { // GetStack returns the caller stack content, // the optional parameter `skip` specify the skipped stack offset from the end point. func (l *Logger) GetStack(skip ...int) string { + l.mu.RLock() + defer l.mu.RUnlock() stackSkip := l.config.StSkip if len(skip) > 0 { stackSkip += skip[0] From 55959920a1872107021724f55569fad8d5bce1f8 Mon Sep 17 00:00:00 2001 From: water <672684719@qq.com> Date: Tue, 28 Jul 2026 18:13:56 +0800 Subject: [PATCH 2/4] fix: protect Logger.config with sync.RWMutex to prevent data race (#4795) --- os/glog/glog_logger_config.go | 55 ++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/os/glog/glog_logger_config.go b/os/glog/glog_logger_config.go index ed1a5b0a7f9..869c35380fb 100644 --- a/os/glog/glog_logger_config.go +++ b/os/glog/glog_logger_config.go @@ -10,6 +10,7 @@ import ( "context" "io" "strings" + "sync" "time" "github.com/gogf/gf/v2/container/gtype" @@ -83,11 +84,15 @@ func DefaultConfig() Config { // GetConfig returns the configuration of current Logger. func (l *Logger) GetConfig() Config { + l.mu.RLock() + defer l.mu.RUnlock() return l.config } // SetConfig set configurations for the logger. func (l *Logger) SetConfig(config Config) error { + l.mu.Lock() + defer l.mu.Unlock() l.config = config // Necessary validation. if config.Path != "" { @@ -102,6 +107,8 @@ func (l *Logger) SetConfig(config Config) error { // SetConfigWithMap set configurations with map for the logger. func (l *Logger) SetConfigWithMap(m map[string]any) error { + l.mu.Lock() + defer l.mu.Unlock() if len(m) == 0 { return gerror.NewCode(gcode.CodeInvalidParameter, "configuration cannot be empty") } @@ -134,6 +141,8 @@ func (l *Logger) SetConfigWithMap(m map[string]any) error { // SetDebug enables/disables the debug level for logger. // The debug level is enabled in default. func (l *Logger) SetDebug(debug bool) { + l.mu.Lock() + defer l.mu.Unlock() if debug { l.config.Level = l.config.Level | LEVEL_DEBU } else { @@ -143,6 +152,8 @@ func (l *Logger) SetDebug(debug bool) { // SetAsync enables/disables async logging output feature. func (l *Logger) SetAsync(enabled bool) { + l.mu.Lock() + defer l.mu.Unlock() if enabled { l.config.Flags = l.config.Flags | F_ASYNC } else { @@ -152,16 +163,22 @@ func (l *Logger) SetAsync(enabled bool) { // SetFlags sets extra flags for logging output features. func (l *Logger) SetFlags(flags int) { + l.mu.Lock() + defer l.mu.Unlock() l.config.Flags = flags } // GetFlags returns the flags of logger. func (l *Logger) GetFlags() int { + l.mu.RLock() + defer l.mu.RUnlock() return l.config.Flags } // SetStack enables/disables the stack feature in failure logging outputs. func (l *Logger) SetStack(enabled bool) { + l.mu.Lock() + defer l.mu.Unlock() if enabled { l.config.StStatus = 1 } else { @@ -171,11 +188,15 @@ func (l *Logger) SetStack(enabled bool) { // SetStackSkip sets the stack offset from the end point. func (l *Logger) SetStackSkip(skip int) { + l.mu.Lock() + defer l.mu.Unlock() l.config.StSkip = skip } // SetStackFilter sets the stack filter from the end point. func (l *Logger) SetStackFilter(filter string) { + l.mu.Lock() + defer l.mu.Unlock() l.config.StFilter = filter } @@ -184,12 +205,16 @@ func (l *Logger) SetStackFilter(filter string) { // // Note that multiple calls of this function will overwrite the previous set context keys. func (l *Logger) SetCtxKeys(keys ...any) { + l.mu.Lock() + defer l.mu.Unlock() l.config.CtxKeys = keys } // AppendCtxKeys appends extra keys to logger. // It ignores the key if it is already appended to the logger previously. func (l *Logger) AppendCtxKeys(keys ...any) { + l.mu.Lock() + defer l.mu.Unlock() var isExist bool for _, key := range keys { isExist = false @@ -207,6 +232,8 @@ func (l *Logger) AppendCtxKeys(keys ...any) { // GetCtxKeys retrieves and returns the context keys for logging. func (l *Logger) GetCtxKeys() []any { + l.mu.RLock() + defer l.mu.RUnlock() return l.config.CtxKeys } @@ -215,12 +242,16 @@ func (l *Logger) GetCtxKeys() []any { // Developer can use customized logging `writer` to redirect logging output to another service, // eg: kafka, mysql, mongodb, etc. func (l *Logger) SetWriter(writer io.Writer) { + l.mu.Lock() + defer l.mu.Unlock() l.config.Writer = writer } // GetWriter returns the customized writer object, which implements the io.Writer interface. // It returns nil if no writer previously set. func (l *Logger) GetWriter() io.Writer { + l.mu.RLock() + defer l.mu.RUnlock() return l.config.Writer } @@ -234,6 +265,8 @@ func (l *Logger) SetPath(path string) error { return gerror.Wrapf(err, `Mkdir "%s" failed in PWD "%s"`, path, gfile.Pwd()) } } + l.mu.Lock() + defer l.mu.Unlock() l.config.Path = strings.TrimRight(path, gfile.Separator) return nil } @@ -241,6 +274,8 @@ func (l *Logger) SetPath(path string) error { // GetPath returns the logging directory path for file logging. // It returns empty string if no directory path set. func (l *Logger) GetPath() string { + l.mu.RLock() + defer l.mu.RUnlock() return l.config.Path } @@ -248,46 +283,64 @@ func (l *Logger) GetPath() string { // Datetime pattern can be used in `pattern`, eg: access-{Ymd}.log. // The default file name pattern is: Y-m-d.log, eg: 2018-01-01.log func (l *Logger) SetFile(pattern string) { + l.mu.Lock() + defer l.mu.Unlock() l.config.File = pattern } // SetTimeFormat sets the time format for the logging time. func (l *Logger) SetTimeFormat(timeFormat string) { + l.mu.Lock() + defer l.mu.Unlock() l.config.TimeFormat = timeFormat } // SetStdoutPrint sets whether output the logging contents to stdout, which is true in default. func (l *Logger) SetStdoutPrint(enabled bool) { + l.mu.Lock() + defer l.mu.Unlock() l.config.StdoutPrint = enabled } // SetHeaderPrint sets whether output header of the logging contents, which is true in default. func (l *Logger) SetHeaderPrint(enabled bool) { + l.mu.Lock() + defer l.mu.Unlock() l.config.HeaderPrint = enabled } // SetLevelPrint sets whether output level string of the logging contents, which is true in default. func (l *Logger) SetLevelPrint(enabled bool) { + l.mu.Lock() + defer l.mu.Unlock() l.config.LevelPrint = enabled } // SetPrefix sets prefix string for every logging content. // Prefix is part of header, which means if header output is shut, no prefix will be output. func (l *Logger) SetPrefix(prefix string) { + l.mu.Lock() + defer l.mu.Unlock() l.config.Prefix = prefix } // SetHandlers sets the logging handlers for current logger. func (l *Logger) SetHandlers(handlers ...Handler) { + l.mu.Lock() + defer l.mu.Unlock() l.config.Handlers = handlers } // SetWriterColorEnable enables file/writer logging with color. func (l *Logger) SetWriterColorEnable(enabled bool) { + l.mu.Lock() + defer l.mu.Unlock() l.config.WriterColorEnable = enabled } // SetStdoutColorDisabled disables stdout logging with color. func (l *Logger) SetStdoutColorDisabled(disabled bool) { + l.mu.Lock() + defer l.mu.Unlock() l.config.StdoutColorDisabled = disabled -} +} \ No newline at end of file From 7294d870bd24fccf2e740d1e6e2db6ca463ee5bd Mon Sep 17 00:00:00 2001 From: water <672684719@qq.com> Date: Tue, 28 Jul 2026 18:13:59 +0800 Subject: [PATCH 3/4] fix: protect Logger.config with sync.RWMutex to prevent data race (#4795) --- os/glog/glog_logger_level.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/os/glog/glog_logger_level.go b/os/glog/glog_logger_level.go index 5b4ecc88439..a0f54fd1bca 100644 --- a/os/glog/glog_logger_level.go +++ b/os/glog/glog_logger_level.go @@ -8,6 +8,7 @@ package glog import ( "strings" + "sync" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" @@ -66,16 +67,22 @@ var levelStringMap = map[string]int{ // Note that levels ` LEVEL_CRIT | LEVEL_PANI | LEVEL_FATA ` cannot be removed for logging content, // which are automatically added to levels. func (l *Logger) SetLevel(level int) { + l.mu.Lock() + defer l.mu.Unlock() l.config.Level = level | LEVEL_CRIT | LEVEL_PANI | LEVEL_FATA } // GetLevel returns the logging level value. func (l *Logger) GetLevel() int { + l.mu.RLock() + defer l.mu.RUnlock() return l.config.Level } // SetLevelStr sets the logging level by level string. func (l *Logger) SetLevelStr(levelStr string) error { + l.mu.Lock() + defer l.mu.Unlock() if level, ok := levelStringMap[strings.ToUpper(levelStr)]; ok { l.config.Level = level } else { @@ -86,11 +93,15 @@ func (l *Logger) SetLevelStr(levelStr string) error { // SetLevelPrefix sets the prefix string for specified level. func (l *Logger) SetLevelPrefix(level int, prefix string) { + l.mu.Lock() + defer l.mu.Unlock() l.config.LevelPrefixes[level] = prefix } // SetLevelPrefixes sets the level to prefix string mapping for the logger. func (l *Logger) SetLevelPrefixes(prefixes map[int]string) { + l.mu.Lock() + defer l.mu.Unlock() for k, v := range prefixes { l.config.LevelPrefixes[k] = v } @@ -98,14 +109,18 @@ func (l *Logger) SetLevelPrefixes(prefixes map[int]string) { // GetLevelPrefix returns the prefix string for specified level. func (l *Logger) GetLevelPrefix(level int) string { + l.mu.RLock() + defer l.mu.RUnlock() return l.config.LevelPrefixes[level] } // getLevelPrefixWithBrackets returns the prefix string with brackets for specified level. func (l *Logger) getLevelPrefixWithBrackets(level int) string { + l.mu.RLock() + defer l.mu.RUnlock() levelStr := "" if s, ok := l.config.LevelPrefixes[level]; ok { levelStr = "[" + s + "]" } return levelStr -} +} \ No newline at end of file From d5187f63087f6240df5f929efa97a8e83919a76a Mon Sep 17 00:00:00 2001 From: water <672684719@qq.com> Date: Tue, 28 Jul 2026 18:14:02 +0800 Subject: [PATCH 4/4] fix: protect Logger.config with sync.RWMutex to prevent data race (#4795) --- os/glog/glog_logger_api.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/os/glog/glog_logger_api.go b/os/glog/glog_logger_api.go index b66ee2a32ab..deaf1424cfd 100644 --- a/os/glog/glog_logger_api.go +++ b/os/glog/glog_logger_api.go @@ -146,5 +146,7 @@ func (l *Logger) checkLevel(level int) bool { if l == nil { return false } + l.mu.RLock() + defer l.mu.RUnlock() return l.config.Level&level > 0 }