github.com/whoyao/protocol@v0.0.0-20230519045905-2d8ace718ca5/logger/logger.go (about)

     1  package logger
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/go-logr/logr"
     7  	"go.uber.org/zap"
     8  	"go.uber.org/zap/zapcore"
     9  )
    10  
    11  var (
    12  	discardLogger        = logr.Discard()
    13  	defaultLogger Logger = LogRLogger(discardLogger)
    14  	pkgLogger     Logger = LogRLogger(discardLogger)
    15  )
    16  
    17  // InitFromConfig initializes a Zap-based logger
    18  func InitFromConfig(conf Config, name string) {
    19  	l, err := NewZapLogger(&conf)
    20  	if err == nil {
    21  		SetLogger(l, name)
    22  	}
    23  }
    24  
    25  // GetLogger returns the logger that was set with SetLogger with an extra depth of 1
    26  func GetLogger() Logger {
    27  	return defaultLogger
    28  }
    29  
    30  // SetLogger lets you use a custom logger. Pass in a logr.Logger with default depth
    31  func SetLogger(l Logger, name string) {
    32  	defaultLogger = l.WithCallDepth(1).WithName(name)
    33  	// pkg wrapper needs to drop two levels of depth
    34  	pkgLogger = l.WithCallDepth(2).WithName(name)
    35  }
    36  
    37  func Debugw(msg string, keysAndValues ...interface{}) {
    38  	pkgLogger.Debugw(msg, keysAndValues...)
    39  }
    40  
    41  func Infow(msg string, keysAndValues ...interface{}) {
    42  	pkgLogger.Infow(msg, keysAndValues...)
    43  }
    44  
    45  func Warnw(msg string, err error, keysAndValues ...interface{}) {
    46  	pkgLogger.Warnw(msg, err, keysAndValues...)
    47  }
    48  
    49  func Errorw(msg string, err error, keysAndValues ...interface{}) {
    50  	pkgLogger.Errorw(msg, err, keysAndValues...)
    51  }
    52  
    53  func ParseZapLevel(level string) zapcore.Level {
    54  	lvl := zapcore.InfoLevel
    55  	if level != "" {
    56  		_ = lvl.UnmarshalText([]byte(level))
    57  	}
    58  	return lvl
    59  }
    60  
    61  type Logger interface {
    62  	Debugw(msg string, keysAndValues ...interface{})
    63  	Infow(msg string, keysAndValues ...interface{})
    64  	Warnw(msg string, err error, keysAndValues ...interface{})
    65  	Errorw(msg string, err error, keysAndValues ...interface{})
    66  	WithValues(keysAndValues ...interface{}) Logger
    67  	WithName(name string) Logger
    68  	WithCallDepth(depth int) Logger
    69  	WithItemSampler() Logger
    70  	// WithoutSampler returns the original logger without sampling
    71  	WithoutSampler() Logger
    72  }
    73  
    74  type ZapLogger struct {
    75  	zap *zap.SugaredLogger
    76  	// store original logger without sampling to avoid multiple samplers
    77  	unsampled      *zap.SugaredLogger
    78  	SampleDuration time.Duration
    79  	SampleInitial  int
    80  	SampleInterval int
    81  }
    82  
    83  func NewZapLogger(conf *Config) (*ZapLogger, error) {
    84  	lvl := ParseZapLevel(conf.Level)
    85  	zapConfig := zap.Config{
    86  		Level:            zap.NewAtomicLevelAt(lvl),
    87  		Development:      false,
    88  		Encoding:         "console",
    89  		EncoderConfig:    zap.NewDevelopmentEncoderConfig(),
    90  		OutputPaths:      []string{"stderr"},
    91  		ErrorOutputPaths: []string{"stderr"},
    92  	}
    93  	if conf.JSON {
    94  		zapConfig.Encoding = "json"
    95  		zapConfig.EncoderConfig = zap.NewProductionEncoderConfig()
    96  	}
    97  	l, err := zapConfig.Build()
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	zl := &ZapLogger{
   102  		unsampled:      l.Sugar(),
   103  		SampleDuration: time.Duration(conf.ItemSampleSeconds) * time.Second,
   104  		SampleInitial:  conf.ItemSampleInitial,
   105  		SampleInterval: conf.ItemSampleInterval,
   106  	}
   107  
   108  	if conf.Sample {
   109  		// use a sampling logger for the main logger
   110  		samplingConf := &zap.SamplingConfig{
   111  			Initial:    conf.SampleInitial,
   112  			Thereafter: conf.SampleInterval,
   113  		}
   114  		// sane defaults
   115  		if samplingConf.Initial == 0 {
   116  			samplingConf.Initial = 20
   117  		}
   118  		if samplingConf.Thereafter == 0 {
   119  			samplingConf.Thereafter = 100
   120  		}
   121  		zl.zap = l.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core {
   122  			return zapcore.NewSamplerWithOptions(
   123  				core,
   124  				time.Second,
   125  				samplingConf.Initial,
   126  				samplingConf.Thereafter,
   127  			)
   128  		})).Sugar()
   129  	} else {
   130  		zl.zap = zl.unsampled
   131  	}
   132  	return zl, nil
   133  }
   134  
   135  func (l *ZapLogger) ToZap() *zap.SugaredLogger {
   136  	return l.zap
   137  }
   138  
   139  func (l *ZapLogger) Debugw(msg string, keysAndValues ...interface{}) {
   140  	l.zap.Debugw(msg, keysAndValues...)
   141  }
   142  
   143  func (l *ZapLogger) Infow(msg string, keysAndValues ...interface{}) {
   144  	l.zap.Infow(msg, keysAndValues...)
   145  }
   146  
   147  func (l *ZapLogger) Warnw(msg string, err error, keysAndValues ...interface{}) {
   148  	if err != nil {
   149  		keysAndValues = append(keysAndValues, "error", err)
   150  	}
   151  	l.zap.Warnw(msg, keysAndValues...)
   152  }
   153  
   154  func (l *ZapLogger) Errorw(msg string, err error, keysAndValues ...interface{}) {
   155  	if err != nil {
   156  		keysAndValues = append(keysAndValues, "error", err)
   157  	}
   158  	l.zap.Errorw(msg, keysAndValues...)
   159  }
   160  
   161  func (l *ZapLogger) WithValues(keysAndValues ...interface{}) Logger {
   162  	dup := *l
   163  	dup.zap = l.zap.With(keysAndValues...)
   164  	// mirror unsampled logger too
   165  	if l.unsampled == l.zap {
   166  		dup.unsampled = dup.zap
   167  	} else {
   168  		dup.unsampled = l.unsampled.With(keysAndValues...)
   169  	}
   170  	return &dup
   171  }
   172  
   173  func (l *ZapLogger) WithName(name string) Logger {
   174  	dup := *l
   175  	dup.zap = l.zap.Named(name)
   176  	if l.unsampled == l.zap {
   177  		dup.unsampled = dup.zap
   178  	} else {
   179  		dup.unsampled = l.unsampled.Named(name)
   180  	}
   181  	return &dup
   182  }
   183  
   184  func (l *ZapLogger) WithCallDepth(depth int) Logger {
   185  	dup := *l
   186  	dup.zap = l.zap.WithOptions(zap.AddCallerSkip(depth))
   187  	if l.unsampled == l.zap {
   188  		dup.unsampled = dup.zap
   189  	} else {
   190  		dup.unsampled = l.unsampled.WithOptions(zap.AddCallerSkip(depth))
   191  	}
   192  	return &dup
   193  }
   194  
   195  func (l *ZapLogger) WithItemSampler() Logger {
   196  	if l.SampleDuration == 0 {
   197  		return l
   198  	}
   199  	dup := *l
   200  	dup.zap = l.unsampled.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core {
   201  		return zapcore.NewSamplerWithOptions(
   202  			core,
   203  			l.SampleDuration,
   204  			l.SampleInitial,
   205  			l.SampleInterval,
   206  		)
   207  	}))
   208  	return &dup
   209  }
   210  
   211  func (l *ZapLogger) WithoutSampler() Logger {
   212  	if l.SampleDuration == 0 {
   213  		return l
   214  	}
   215  	dup := *l
   216  	dup.zap = l.unsampled
   217  	return &dup
   218  }
   219  
   220  type LogRLogger logr.Logger
   221  
   222  func (l LogRLogger) toLogr() logr.Logger {
   223  	if logr.Logger(l).GetSink() == nil {
   224  		return discardLogger
   225  	}
   226  	return logr.Logger(l)
   227  }
   228  
   229  func (l LogRLogger) Debugw(msg string, keysAndValues ...interface{}) {
   230  	l.toLogr().V(1).Info(msg, keysAndValues...)
   231  }
   232  
   233  func (l LogRLogger) Infow(msg string, keysAndValues ...interface{}) {
   234  	l.toLogr().Info(msg, keysAndValues...)
   235  }
   236  
   237  func (l LogRLogger) Warnw(msg string, err error, keysAndValues ...interface{}) {
   238  	if err != nil {
   239  		keysAndValues = append(keysAndValues, "error", err)
   240  	}
   241  	l.toLogr().Info(msg, keysAndValues...)
   242  }
   243  
   244  func (l LogRLogger) Errorw(msg string, err error, keysAndValues ...interface{}) {
   245  	l.toLogr().Error(err, msg, keysAndValues...)
   246  }
   247  
   248  func (l LogRLogger) WithValues(keysAndValues ...interface{}) Logger {
   249  	return LogRLogger(l.toLogr().WithValues(keysAndValues...))
   250  }
   251  
   252  func (l LogRLogger) WithName(name string) Logger {
   253  	return LogRLogger(l.toLogr().WithName(name))
   254  }
   255  
   256  func (l LogRLogger) WithCallDepth(depth int) Logger {
   257  	return LogRLogger(l.toLogr().WithCallDepth(depth))
   258  }
   259  
   260  func (l LogRLogger) WithItemSampler() Logger {
   261  	// logr does not support sampling
   262  	return l
   263  }
   264  
   265  func (l LogRLogger) WithoutSampler() Logger {
   266  	return l
   267  }