Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(log): GetLogger doesn't returns the same logger that was set before. #3420

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 28 additions & 36 deletions log/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,124 +4,116 @@ import (
"context"
"fmt"
"os"
"sync"
"sync/atomic"
)

// globalLogger is designed as a global logger in current process.
var global = &loggerAppliance{}
// global is a place to store global logger.
var global atomic.Value

// loggerAppliance is the proxy of `Logger` to
// make logger change will affect all sub-logger.
// loggerAppliance is a wrapper to make sure logger can be stored.
type loggerAppliance struct {
lock sync.Mutex
Logger
logger Logger
}

func init() {
global.SetLogger(DefaultLogger)
SetLogger(DefaultLogger)
}

func (a *loggerAppliance) SetLogger(in Logger) {
a.lock.Lock()
defer a.lock.Unlock()
a.Logger = in
}

// SetLogger should be called before any other log call.
// And it is NOT THREAD SAFE.
// SetLogger sets the global logger. This function should be called
// before any other log call.
func SetLogger(logger Logger) {
global.SetLogger(logger)
global.Store(loggerAppliance{logger: logger})
}

// GetLogger returns global logger appliance as logger in current process.
// GetLogger returns global logger.
func GetLogger() Logger {
return global
return global.Load().(loggerAppliance).logger
}

// Log Print log by level and keyvals.
func Log(level Level, keyvals ...interface{}) {
_ = global.Log(level, keyvals...)
_ = GetLogger().Log(level, keyvals...)
}

// Context with context logger.
func Context(ctx context.Context) *Helper {
return NewHelper(WithContext(ctx, global.Logger))
return NewHelper(WithContext(ctx, GetLogger()))
}

// Debug logs a message at debug level.
func Debug(a ...interface{}) {
_ = global.Log(LevelDebug, DefaultMessageKey, fmt.Sprint(a...))
_ = GetLogger().Log(LevelDebug, DefaultMessageKey, fmt.Sprint(a...))
}

// Debugf logs a message at debug level.
func Debugf(format string, a ...interface{}) {
_ = global.Log(LevelDebug, DefaultMessageKey, fmt.Sprintf(format, a...))
_ = GetLogger().Log(LevelDebug, DefaultMessageKey, fmt.Sprintf(format, a...))
}

// Debugw logs a message at debug level.
func Debugw(keyvals ...interface{}) {
_ = global.Log(LevelDebug, keyvals...)
_ = GetLogger().Log(LevelDebug, keyvals...)
}

// Info logs a message at info level.
func Info(a ...interface{}) {
_ = global.Log(LevelInfo, DefaultMessageKey, fmt.Sprint(a...))
_ = GetLogger().Log(LevelInfo, DefaultMessageKey, fmt.Sprint(a...))
}

// Infof logs a message at info level.
func Infof(format string, a ...interface{}) {
_ = global.Log(LevelInfo, DefaultMessageKey, fmt.Sprintf(format, a...))
_ = GetLogger().Log(LevelInfo, DefaultMessageKey, fmt.Sprintf(format, a...))
}

// Infow logs a message at info level.
func Infow(keyvals ...interface{}) {
_ = global.Log(LevelInfo, keyvals...)
_ = GetLogger().Log(LevelInfo, keyvals...)
}

// Warn logs a message at warn level.
func Warn(a ...interface{}) {
_ = global.Log(LevelWarn, DefaultMessageKey, fmt.Sprint(a...))
_ = GetLogger().Log(LevelWarn, DefaultMessageKey, fmt.Sprint(a...))
}

// Warnf logs a message at warnf level.
func Warnf(format string, a ...interface{}) {
_ = global.Log(LevelWarn, DefaultMessageKey, fmt.Sprintf(format, a...))
_ = GetLogger().Log(LevelWarn, DefaultMessageKey, fmt.Sprintf(format, a...))
}

// Warnw logs a message at warnf level.
func Warnw(keyvals ...interface{}) {
_ = global.Log(LevelWarn, keyvals...)
_ = GetLogger().Log(LevelWarn, keyvals...)
}

// Error logs a message at error level.
func Error(a ...interface{}) {
_ = global.Log(LevelError, DefaultMessageKey, fmt.Sprint(a...))
_ = GetLogger().Log(LevelError, DefaultMessageKey, fmt.Sprint(a...))
}

// Errorf logs a message at error level.
func Errorf(format string, a ...interface{}) {
_ = global.Log(LevelError, DefaultMessageKey, fmt.Sprintf(format, a...))
_ = GetLogger().Log(LevelError, DefaultMessageKey, fmt.Sprintf(format, a...))
}

// Errorw logs a message at error level.
func Errorw(keyvals ...interface{}) {
_ = global.Log(LevelError, keyvals...)
_ = GetLogger().Log(LevelError, keyvals...)
}

// Fatal logs a message at fatal level.
func Fatal(a ...interface{}) {
_ = global.Log(LevelFatal, DefaultMessageKey, fmt.Sprint(a...))
_ = GetLogger().Log(LevelFatal, DefaultMessageKey, fmt.Sprint(a...))
os.Exit(1)
}

// Fatalf logs a message at fatal level.
func Fatalf(format string, a ...interface{}) {
_ = global.Log(LevelFatal, DefaultMessageKey, fmt.Sprintf(format, a...))
_ = GetLogger().Log(LevelFatal, DefaultMessageKey, fmt.Sprintf(format, a...))
os.Exit(1)
}

// Fatalw logs a message at fatal level.
func Fatalw(keyvals ...interface{}) {
_ = global.Log(LevelFatal, keyvals...)
_ = GetLogger().Log(LevelFatal, keyvals...)
os.Exit(1)
}
54 changes: 35 additions & 19 deletions log/global_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import (
"bytes"
"context"
"fmt"
"os"
"strings"
"testing"
)

func TestGlobalLog(t *testing.T) {
defaultLogger := GetLogger()
t.Cleanup(func() { SetLogger(defaultLogger) })

buffer := &bytes.Buffer{}
logger := NewStdLogger(buffer)
SetLogger(logger)

if global.Logger != logger {
if GetLogger() != logger {
t.Error("GetLogger() is not equal to logger")
}

Expand Down Expand Up @@ -93,27 +95,41 @@ func TestGlobalLog(t *testing.T) {
}
}

func TestGlobalLogUpdate(t *testing.T) {
l := &loggerAppliance{}
l.SetLogger(NewStdLogger(os.Stdout))
LOG := NewHelper(l)
LOG.Info("Log to stdout")

buffer := &bytes.Buffer{}
l.SetLogger(NewStdLogger(buffer))
LOG.Info("Log to buffer")

expected := "INFO msg=Log to buffer\n"
if buffer.String() != expected {
t.Errorf("Expected: %s, got: %s", expected, buffer.String())
}
}

func TestGlobalContext(t *testing.T) {
defaultLogger := GetLogger()
t.Cleanup(func() { SetLogger(defaultLogger) })

buffer := &bytes.Buffer{}
SetLogger(NewStdLogger(buffer))
Context(context.Background()).Infof("111")
Context(context.Background()).Info("111")
if buffer.String() != "INFO msg=111\n" {
t.Errorf("Expected:%s, got:%s", "INFO msg=111", buffer.String())
}
}

type tidKey struct{}

func TestValuerUnderGlobalValue(t *testing.T) {
defaultLogger := GetLogger()
t.Cleanup(func() { SetLogger(defaultLogger) })

var tidValuer Valuer = func(ctx context.Context) any {
return ctx.Value(tidKey{})
}

var buf bytes.Buffer
l1 := NewStdLogger(&buf)
l2 := With(l1, "traceId", tidValuer)

SetLogger(l2)
l3 := GetLogger()

ctx := context.WithValue(context.Background(), tidKey{}, "123")
l4 := WithContext(ctx, l3)
_ = l4.Log(LevelInfo, "msg", "m")

want := "INFO traceId=123 msg=m\n"
if got := buf.String(); got != want {
t.Errorf("Expected:%q, got:%q", want, got)
}
}
Loading