trpc.group/trpc-go/trpc-go@v1.0.3/log/zaplogger.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package log
    15  
    16  import (
    17  	"fmt"
    18  	"os"
    19  	"strconv"
    20  	"time"
    21  
    22  	"trpc.group/trpc-go/trpc-go/internal/report"
    23  	"trpc.group/trpc-go/trpc-go/log/rollwriter"
    24  
    25  	"go.uber.org/zap"
    26  	"go.uber.org/zap/zapcore"
    27  )
    28  
    29  var defaultConfig = []OutputConfig{
    30  	{
    31  		Writer:    "console",
    32  		Level:     "debug",
    33  		Formatter: "console",
    34  	},
    35  }
    36  
    37  // Some ZapCore constants.
    38  const (
    39  	ConsoleZapCore = "console"
    40  	FileZapCore    = "file"
    41  )
    42  
    43  // Levels is the map from string to zapcore.Level.
    44  var Levels = map[string]zapcore.Level{
    45  	"":      zapcore.DebugLevel,
    46  	"trace": zapcore.DebugLevel,
    47  	"debug": zapcore.DebugLevel,
    48  	"info":  zapcore.InfoLevel,
    49  	"warn":  zapcore.WarnLevel,
    50  	"error": zapcore.ErrorLevel,
    51  	"fatal": zapcore.FatalLevel,
    52  }
    53  
    54  var levelToZapLevel = map[Level]zapcore.Level{
    55  	LevelTrace: zapcore.DebugLevel,
    56  	LevelDebug: zapcore.DebugLevel,
    57  	LevelInfo:  zapcore.InfoLevel,
    58  	LevelWarn:  zapcore.WarnLevel,
    59  	LevelError: zapcore.ErrorLevel,
    60  	LevelFatal: zapcore.FatalLevel,
    61  }
    62  
    63  var zapLevelToLevel = map[zapcore.Level]Level{
    64  	zapcore.DebugLevel: LevelDebug,
    65  	zapcore.InfoLevel:  LevelInfo,
    66  	zapcore.WarnLevel:  LevelWarn,
    67  	zapcore.ErrorLevel: LevelError,
    68  	zapcore.FatalLevel: LevelFatal,
    69  }
    70  
    71  // NewZapLog creates a trpc default Logger from zap whose caller skip is set to 2.
    72  func NewZapLog(c Config) Logger {
    73  	return NewZapLogWithCallerSkip(c, 2)
    74  }
    75  
    76  // NewZapLogWithCallerSkip creates a trpc default Logger from zap.
    77  func NewZapLogWithCallerSkip(cfg Config, callerSkip int) Logger {
    78  	var (
    79  		cores  []zapcore.Core
    80  		levels []zap.AtomicLevel
    81  	)
    82  	for _, c := range cfg {
    83  		writer := GetWriter(c.Writer)
    84  		if writer == nil {
    85  			panic("log: writer core: " + c.Writer + " no registered")
    86  		}
    87  		decoder := &Decoder{OutputConfig: &c}
    88  		if err := writer.Setup(c.Writer, decoder); err != nil {
    89  			panic("log: writer core: " + c.Writer + " setup fail: " + err.Error())
    90  		}
    91  		cores = append(cores, decoder.Core)
    92  		levels = append(levels, decoder.ZapLevel)
    93  	}
    94  	return &zapLog{
    95  		levels: levels,
    96  		logger: zap.New(
    97  			zapcore.NewTee(cores...),
    98  			zap.AddCallerSkip(callerSkip),
    99  			zap.AddCaller(),
   100  		),
   101  	}
   102  }
   103  
   104  func newEncoder(c *OutputConfig) zapcore.Encoder {
   105  	encoderCfg := zapcore.EncoderConfig{
   106  		TimeKey:        GetLogEncoderKey("T", c.FormatConfig.TimeKey),
   107  		LevelKey:       GetLogEncoderKey("L", c.FormatConfig.LevelKey),
   108  		NameKey:        GetLogEncoderKey("N", c.FormatConfig.NameKey),
   109  		CallerKey:      GetLogEncoderKey("C", c.FormatConfig.CallerKey),
   110  		FunctionKey:    GetLogEncoderKey(zapcore.OmitKey, c.FormatConfig.FunctionKey),
   111  		MessageKey:     GetLogEncoderKey("M", c.FormatConfig.MessageKey),
   112  		StacktraceKey:  GetLogEncoderKey("S", c.FormatConfig.StacktraceKey),
   113  		LineEnding:     zapcore.DefaultLineEnding,
   114  		EncodeLevel:    zapcore.CapitalLevelEncoder,
   115  		EncodeTime:     NewTimeEncoder(c.FormatConfig.TimeFmt),
   116  		EncodeDuration: zapcore.StringDurationEncoder,
   117  		EncodeCaller:   zapcore.ShortCallerEncoder,
   118  	}
   119  	if c.EnableColor {
   120  		encoderCfg.EncodeLevel = zapcore.CapitalColorLevelEncoder
   121  	}
   122  	if newFormatEncoder, ok := formatEncoders[c.Formatter]; ok {
   123  		return newFormatEncoder(encoderCfg)
   124  	}
   125  	// Defaults to console encoder.
   126  	return zapcore.NewConsoleEncoder(encoderCfg)
   127  }
   128  
   129  var formatEncoders = map[string]NewFormatEncoder{
   130  	"console": zapcore.NewConsoleEncoder,
   131  	"json":    zapcore.NewJSONEncoder,
   132  }
   133  
   134  // NewFormatEncoder is the function type for creating a format encoder out of an encoder config.
   135  type NewFormatEncoder func(zapcore.EncoderConfig) zapcore.Encoder
   136  
   137  // RegisterFormatEncoder registers a NewFormatEncoder with the specified formatName key.
   138  // The existing formats include "console" and "json", but you can override these format encoders
   139  // or provide a new custom one.
   140  func RegisterFormatEncoder(formatName string, newFormatEncoder NewFormatEncoder) {
   141  	formatEncoders[formatName] = newFormatEncoder
   142  }
   143  
   144  // GetLogEncoderKey gets user defined log output name, uses defKey if empty.
   145  func GetLogEncoderKey(defKey, key string) string {
   146  	if key == "" {
   147  		return defKey
   148  	}
   149  	return key
   150  }
   151  
   152  func newConsoleCore(c *OutputConfig) (zapcore.Core, zap.AtomicLevel) {
   153  	lvl := zap.NewAtomicLevelAt(Levels[c.Level])
   154  	return zapcore.NewCore(
   155  		newEncoder(c),
   156  		zapcore.Lock(os.Stdout),
   157  		lvl), lvl
   158  }
   159  
   160  func newFileCore(c *OutputConfig) (zapcore.Core, zap.AtomicLevel, error) {
   161  	opts := []rollwriter.Option{
   162  		rollwriter.WithMaxAge(c.WriteConfig.MaxAge),
   163  		rollwriter.WithMaxBackups(c.WriteConfig.MaxBackups),
   164  		rollwriter.WithCompress(c.WriteConfig.Compress),
   165  		rollwriter.WithMaxSize(c.WriteConfig.MaxSize),
   166  	}
   167  	// roll by time.
   168  	if c.WriteConfig.RollType != RollBySize {
   169  		opts = append(opts, rollwriter.WithRotationTime(c.WriteConfig.TimeUnit.Format()))
   170  	}
   171  	writer, err := rollwriter.NewRollWriter(c.WriteConfig.Filename, opts...)
   172  	if err != nil {
   173  		return nil, zap.AtomicLevel{}, err
   174  	}
   175  
   176  	// write mode.
   177  	var ws zapcore.WriteSyncer
   178  	switch m := c.WriteConfig.WriteMode; m {
   179  	case 0, WriteFast:
   180  		// Use WriteFast as default mode.
   181  		// It has better performance, discards logs on full and avoid blocking service.
   182  		ws = rollwriter.NewAsyncRollWriter(writer, rollwriter.WithDropLog(true))
   183  	case WriteSync:
   184  		ws = zapcore.AddSync(writer)
   185  	case WriteAsync:
   186  		ws = rollwriter.NewAsyncRollWriter(writer, rollwriter.WithDropLog(false))
   187  	default:
   188  		return nil, zap.AtomicLevel{}, fmt.Errorf("validating WriteMode parameter: got %d, "+
   189  			"but expect one of WriteFast(%d), WriteAsync(%d), or WriteSync(%d)", m, WriteFast, WriteAsync, WriteSync)
   190  	}
   191  
   192  	// log level.
   193  	lvl := zap.NewAtomicLevelAt(Levels[c.Level])
   194  	return zapcore.NewCore(
   195  		newEncoder(c),
   196  		ws, lvl,
   197  	), lvl, nil
   198  }
   199  
   200  // NewTimeEncoder creates a time format encoder.
   201  func NewTimeEncoder(format string) zapcore.TimeEncoder {
   202  	switch format {
   203  	case "":
   204  		return func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
   205  			enc.AppendByteString(defaultTimeFormat(t))
   206  		}
   207  	case "seconds":
   208  		return zapcore.EpochTimeEncoder
   209  	case "milliseconds":
   210  		return zapcore.EpochMillisTimeEncoder
   211  	case "nanoseconds":
   212  		return zapcore.EpochNanosTimeEncoder
   213  	default:
   214  		return func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
   215  			enc.AppendString(t.Format(format))
   216  		}
   217  	}
   218  }
   219  
   220  // defaultTimeFormat returns the default time format "2006-01-02 15:04:05.000",
   221  // which performs better than https://pkg.go.dev/time#Time.AppendFormat.
   222  func defaultTimeFormat(t time.Time) []byte {
   223  	t = t.Local()
   224  	year, month, day := t.Date()
   225  	hour, minute, second := t.Clock()
   226  	micros := t.Nanosecond() / 1000
   227  
   228  	buf := make([]byte, 23)
   229  	buf[0] = byte((year/1000)%10) + '0'
   230  	buf[1] = byte((year/100)%10) + '0'
   231  	buf[2] = byte((year/10)%10) + '0'
   232  	buf[3] = byte(year%10) + '0'
   233  	buf[4] = '-'
   234  	buf[5] = byte((month)/10) + '0'
   235  	buf[6] = byte((month)%10) + '0'
   236  	buf[7] = '-'
   237  	buf[8] = byte((day)/10) + '0'
   238  	buf[9] = byte((day)%10) + '0'
   239  	buf[10] = ' '
   240  	buf[11] = byte((hour)/10) + '0'
   241  	buf[12] = byte((hour)%10) + '0'
   242  	buf[13] = ':'
   243  	buf[14] = byte((minute)/10) + '0'
   244  	buf[15] = byte((minute)%10) + '0'
   245  	buf[16] = ':'
   246  	buf[17] = byte((second)/10) + '0'
   247  	buf[18] = byte((second)%10) + '0'
   248  	buf[19] = '.'
   249  	buf[20] = byte((micros/100000)%10) + '0'
   250  	buf[21] = byte((micros/10000)%10) + '0'
   251  	buf[22] = byte((micros/1000)%10) + '0'
   252  	return buf
   253  }
   254  
   255  // zapLog is a Logger implementation based on zaplogger.
   256  type zapLog struct {
   257  	levels []zap.AtomicLevel
   258  	logger *zap.Logger
   259  }
   260  
   261  func (l *zapLog) WithOptions(opts ...Option) Logger {
   262  	o := &options{}
   263  	for _, opt := range opts {
   264  		opt(o)
   265  	}
   266  	return &zapLog{
   267  		levels: l.levels,
   268  		logger: l.logger.WithOptions(zap.AddCallerSkip(o.skip)),
   269  	}
   270  }
   271  
   272  // With add user defined fields to Logger. Fields support multiple values.
   273  func (l *zapLog) With(fields ...Field) Logger {
   274  	zapFields := make([]zap.Field, len(fields))
   275  	for i := range fields {
   276  		zapFields[i] = zap.Any(fields[i].Key, fields[i].Value)
   277  	}
   278  
   279  	return &zapLog{
   280  		levels: l.levels,
   281  		logger: l.logger.With(zapFields...)}
   282  }
   283  
   284  func getLogMsg(args ...interface{}) string {
   285  	msg := fmt.Sprintln(args...)
   286  	msg = msg[:len(msg)-1]
   287  	report.LogWriteSize.IncrBy(float64(len(msg)))
   288  	return msg
   289  }
   290  
   291  func getLogMsgf(format string, args ...interface{}) string {
   292  	msg := fmt.Sprintf(format, args...)
   293  	report.LogWriteSize.IncrBy(float64(len(msg)))
   294  	return msg
   295  }
   296  
   297  // Trace logs to TRACE log. Arguments are handled in the manner of fmt.Println.
   298  func (l *zapLog) Trace(args ...interface{}) {
   299  	if l.logger.Core().Enabled(zapcore.DebugLevel) {
   300  		l.logger.Debug(getLogMsg(args...))
   301  	}
   302  }
   303  
   304  // Tracef logs to TRACE log. Arguments are handled in the manner of fmt.Printf.
   305  func (l *zapLog) Tracef(format string, args ...interface{}) {
   306  	if l.logger.Core().Enabled(zapcore.DebugLevel) {
   307  		l.logger.Debug(getLogMsgf(format, args...))
   308  	}
   309  }
   310  
   311  // Debug logs to DEBUG log. Arguments are handled in the manner of fmt.Println.
   312  func (l *zapLog) Debug(args ...interface{}) {
   313  	if l.logger.Core().Enabled(zapcore.DebugLevel) {
   314  		l.logger.Debug(getLogMsg(args...))
   315  	}
   316  }
   317  
   318  // Debugf logs to DEBUG log. Arguments are handled in the manner of fmt.Printf.
   319  func (l *zapLog) Debugf(format string, args ...interface{}) {
   320  	if l.logger.Core().Enabled(zapcore.DebugLevel) {
   321  		l.logger.Debug(getLogMsgf(format, args...))
   322  	}
   323  }
   324  
   325  // Info logs to INFO log. Arguments are handled in the manner of fmt.Println.
   326  func (l *zapLog) Info(args ...interface{}) {
   327  	if l.logger.Core().Enabled(zapcore.InfoLevel) {
   328  		l.logger.Info(getLogMsg(args...))
   329  	}
   330  }
   331  
   332  // Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf.
   333  func (l *zapLog) Infof(format string, args ...interface{}) {
   334  	if l.logger.Core().Enabled(zapcore.InfoLevel) {
   335  		l.logger.Info(getLogMsgf(format, args...))
   336  	}
   337  }
   338  
   339  // Warn logs to WARNING log. Arguments are handled in the manner of fmt.Println.
   340  func (l *zapLog) Warn(args ...interface{}) {
   341  	if l.logger.Core().Enabled(zapcore.WarnLevel) {
   342  		l.logger.Warn(getLogMsg(args...))
   343  	}
   344  }
   345  
   346  // Warnf logs to WARNING log. Arguments are handled in the manner of fmt.Printf.
   347  func (l *zapLog) Warnf(format string, args ...interface{}) {
   348  	if l.logger.Core().Enabled(zapcore.WarnLevel) {
   349  		l.logger.Warn(getLogMsgf(format, args...))
   350  	}
   351  }
   352  
   353  // Error logs to ERROR log. Arguments are handled in the manner of fmt.Println.
   354  func (l *zapLog) Error(args ...interface{}) {
   355  	if l.logger.Core().Enabled(zapcore.ErrorLevel) {
   356  		l.logger.Error(getLogMsg(args...))
   357  	}
   358  }
   359  
   360  // Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf.
   361  func (l *zapLog) Errorf(format string, args ...interface{}) {
   362  	if l.logger.Core().Enabled(zapcore.ErrorLevel) {
   363  		l.logger.Error(getLogMsgf(format, args...))
   364  	}
   365  }
   366  
   367  // Fatal logs to FATAL log. Arguments are handled in the manner of fmt.Println.
   368  func (l *zapLog) Fatal(args ...interface{}) {
   369  	if l.logger.Core().Enabled(zapcore.FatalLevel) {
   370  		l.logger.Fatal(getLogMsg(args...))
   371  	}
   372  }
   373  
   374  // Fatalf logs to FATAL log. Arguments are handled in the manner of fmt.Printf.
   375  func (l *zapLog) Fatalf(format string, args ...interface{}) {
   376  	if l.logger.Core().Enabled(zapcore.FatalLevel) {
   377  		l.logger.Fatal(getLogMsgf(format, args...))
   378  	}
   379  }
   380  
   381  // Sync calls the zap logger's Sync method, and flushes any buffered log entries.
   382  // Applications should take care to call Sync before exiting.
   383  func (l *zapLog) Sync() error {
   384  	return l.logger.Sync()
   385  }
   386  
   387  // SetLevel sets output log level.
   388  func (l *zapLog) SetLevel(output string, level Level) {
   389  	i, e := strconv.Atoi(output)
   390  	if e != nil {
   391  		return
   392  	}
   393  	if i < 0 || i >= len(l.levels) {
   394  		return
   395  	}
   396  	l.levels[i].SetLevel(levelToZapLevel[level])
   397  }
   398  
   399  // GetLevel gets output log level.
   400  func (l *zapLog) GetLevel(output string) Level {
   401  	i, e := strconv.Atoi(output)
   402  	if e != nil {
   403  		return LevelDebug
   404  	}
   405  	if i < 0 || i >= len(l.levels) {
   406  		return LevelDebug
   407  	}
   408  	return zapLevelToLevel[l.levels[i].Level()]
   409  }
   410  
   411  // CustomTimeFormat customize time format.
   412  // Deprecated: Use https://pkg.go.dev/time#Time.Format instead.
   413  func CustomTimeFormat(t time.Time, format string) string {
   414  	return t.Format(format)
   415  }
   416  
   417  // DefaultTimeFormat returns the default time format "2006-01-02 15:04:05.000".
   418  // Deprecated: Use https://pkg.go.dev/time#Time.AppendFormat instead.
   419  func DefaultTimeFormat(t time.Time) []byte {
   420  	return defaultTimeFormat(t)
   421  }