github.com/klaytn/klaytn@v1.12.1/log/zap_logger.go (about)

     1  // Copyright 2018 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The klaytn library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package log
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"sync"
    23  
    24  	"go.uber.org/zap"
    25  	"go.uber.org/zap/zapcore"
    26  )
    27  
    28  var zlManager = zapLoggerManager{
    29  	"stderr", // Use stderr to outputPath instead of stdout to be aligned with log15.
    30  	"json", zapcore.InfoLevel,
    31  	sync.Mutex{},
    32  	make(map[ModuleID][]*zapLogger),
    33  }
    34  
    35  type zapLoggerManager struct {
    36  	outputPath   string
    37  	encodingType string
    38  	logLevel     zapcore.Level
    39  	mutex        sync.Mutex
    40  	loggersMap   map[ModuleID][]*zapLogger
    41  }
    42  
    43  type zapLogger struct {
    44  	mi  ModuleID
    45  	cfg *zap.Config
    46  	sl  *zap.SugaredLogger
    47  }
    48  
    49  // A zapLogger generated from NewWith inherits InitialFields and ModuleID from its parent.
    50  func (zl *zapLogger) NewWith(keysAndValues ...interface{}) Logger {
    51  	zlManager.mutex.Lock()
    52  	defer zlManager.mutex.Unlock()
    53  
    54  	newCfg := genDefaultConfig()
    55  	for k, v := range zl.cfg.InitialFields {
    56  		newCfg.InitialFields[k] = v
    57  	}
    58  	newCfg.Level.SetLevel(zl.cfg.Level.Level())
    59  	return genLoggerZap(zl.mi, newCfg)
    60  }
    61  
    62  func (zl *zapLogger) newModuleLogger(mi ModuleID) Logger {
    63  	zlManager.mutex.Lock()
    64  	defer zlManager.mutex.Unlock()
    65  
    66  	zapCfg := genDefaultConfig()
    67  	zapCfg.InitialFields[module] = mi
    68  	return genLoggerZap(mi, zapCfg)
    69  }
    70  
    71  func (zl *zapLogger) Trace(msg string, keysAndValues ...interface{}) {
    72  	zl.sl.Debugw(msg, keysAndValues...)
    73  }
    74  
    75  func (zl *zapLogger) Debug(msg string, keysAndValues ...interface{}) {
    76  	zl.sl.Debugw(msg, keysAndValues...)
    77  }
    78  
    79  func (zl *zapLogger) Info(msg string, keysAndValues ...interface{}) {
    80  	zl.sl.Infow(msg, keysAndValues...)
    81  }
    82  
    83  func (zl *zapLogger) Warn(msg string, keysAndValues ...interface{}) {
    84  	zl.sl.Warnw(msg, keysAndValues...)
    85  }
    86  
    87  func (zl *zapLogger) Error(msg string, keysAndValues ...interface{}) {
    88  	zl.sl.Errorw(msg, keysAndValues...)
    89  }
    90  
    91  func (zl *zapLogger) ErrorWithStack(msg string, keysAndValues ...interface{}) {
    92  	zl.sl.Errorw(msg, keysAndValues...)
    93  }
    94  
    95  func (zl *zapLogger) Crit(msg string, keysAndValues ...interface{}) {
    96  	zl.sl.Fatalw(msg, keysAndValues...)
    97  }
    98  
    99  func (zl *zapLogger) CritWithStack(msg string, keysAndValues ...interface{}) {
   100  	zl.sl.Fatalw(msg, keysAndValues...)
   101  }
   102  
   103  // GetHandler and SetHandler do nothing but exist to make consistency in Logger interface.
   104  func (zl *zapLogger) GetHandler() Handler {
   105  	return nil
   106  }
   107  
   108  func (zl *zapLogger) SetHandler(h Handler) {
   109  }
   110  
   111  func (zl *zapLogger) setLevel(lvl Lvl) {
   112  	zl.cfg.Level.SetLevel(lvlToZapLevel(lvl))
   113  }
   114  
   115  // register registers the receiver to zapLoggerManager.
   116  func (zl *zapLogger) register() {
   117  	zlManager.loggersMap[zl.mi] = append(zlManager.loggersMap[zl.mi], zl)
   118  }
   119  
   120  func genBaseLoggerZap() Logger {
   121  	return genLoggerZap(BaseLogger, genDefaultConfig())
   122  }
   123  
   124  // genLoggerZap creates a zapLogger with given ModuleID and Config.
   125  func genLoggerZap(mi ModuleID, cfg *zap.Config) Logger {
   126  	logger, err := cfg.Build()
   127  	if err != nil {
   128  		Fatalf("Error while building zapLogger from the config. ModuleID: %v, err: %v", mi, err)
   129  	}
   130  	newLogger := &zapLogger{mi, cfg, logger.Sugar()}
   131  	newLogger.register()
   132  	return newLogger
   133  }
   134  
   135  // ChangeLogLevelWithName changes the log level of loggers with given ModuleName.
   136  func ChangeLogLevelWithName(moduleName string, lvl Lvl) error {
   137  	if err := levelCheck(lvl); err != nil {
   138  		return err
   139  	}
   140  	mi := GetModuleID(moduleName)
   141  	if mi == ModuleNameLen {
   142  		return errors.New("entered module name does not match with any existing log module")
   143  	}
   144  	return ChangeLogLevelWithID(mi, lvl)
   145  }
   146  
   147  // ChangeLogLevelWithName changes the log level of loggers with given ModuleID.
   148  func ChangeLogLevelWithID(mi ModuleID, lvl Lvl) error {
   149  	if err := levelCheck(lvl); err != nil {
   150  		return err
   151  	}
   152  	if err := idCheck(mi); err != nil {
   153  		return err
   154  	}
   155  	loggers := zlManager.loggersMap[mi]
   156  	for _, logger := range loggers {
   157  		logger.setLevel(lvl)
   158  	}
   159  	return nil
   160  }
   161  
   162  func ChangeGlobalLogLevel(glogger *GlogHandler, lvl Lvl) error {
   163  	if err := levelCheck(lvl); err != nil {
   164  		return err
   165  	}
   166  	for _, loggers := range zlManager.loggersMap {
   167  		for _, logger := range loggers {
   168  			logger.setLevel(lvl)
   169  		}
   170  	}
   171  
   172  	if glogger != nil {
   173  		glogger.Verbosity(lvl)
   174  	}
   175  	return nil
   176  }
   177  
   178  func levelCheck(lvl Lvl) error {
   179  	if lvl >= LvlEnd {
   180  		return errors.New(fmt.Sprintf("insert log level less than %d", LvlEnd))
   181  	}
   182  	if lvl < LvlCrit {
   183  		return errors.New(fmt.Sprintf("insert log level greater than or equal to %d", LvlCrit))
   184  	}
   185  	return nil
   186  }
   187  
   188  func idCheck(mi ModuleID) error {
   189  	if mi >= ModuleNameLen {
   190  		return errors.New(fmt.Sprintf("insert log level less than %d", ModuleNameLen))
   191  	}
   192  	if mi <= BaseLogger {
   193  		return errors.New(fmt.Sprintf("insert log level greater than %d", BaseLogger))
   194  	}
   195  	return nil
   196  }
   197  
   198  func lvlToZapLevel(lvl Lvl) zapcore.Level {
   199  	switch lvl {
   200  	case LvlCrit:
   201  		return zapcore.FatalLevel
   202  	case LvlError:
   203  		return zapcore.ErrorLevel
   204  	case LvlWarn:
   205  		return zapcore.WarnLevel
   206  	case LvlInfo:
   207  		return zapcore.InfoLevel
   208  	case LvlDebug:
   209  		return zapcore.DebugLevel
   210  	case LvlTrace:
   211  		return zapcore.DebugLevel
   212  	default:
   213  		baseLogger.Error("Unexpected log level entered. Use InfoLevel instead.", "entered level", lvl)
   214  		return zapcore.InfoLevel
   215  	}
   216  }
   217  
   218  func genDefaultEncoderConfig() zapcore.EncoderConfig {
   219  	return zapcore.EncoderConfig{
   220  		TimeKey:  "ts",
   221  		LevelKey: "level",
   222  		NameKey:  "logger",
   223  		// CallerKey:      "caller",
   224  		MessageKey:     "msg",
   225  		StacktraceKey:  "stacktrace",
   226  		LineEnding:     zapcore.DefaultLineEnding,
   227  		EncodeLevel:    zapcore.LowercaseLevelEncoder,
   228  		EncodeTime:     zapcore.ISO8601TimeEncoder,
   229  		EncodeDuration: zapcore.SecondsDurationEncoder,
   230  		// EncodeCaller:   zapcore.ShortCallerEncoder,
   231  	}
   232  }
   233  
   234  func genDefaultConfig() *zap.Config {
   235  	encoderConfig := genDefaultEncoderConfig()
   236  	return &zap.Config{
   237  		Encoding:      zlManager.encodingType,
   238  		Level:         zap.NewAtomicLevelAt(zlManager.logLevel),
   239  		OutputPaths:   []string{zlManager.outputPath},
   240  		Development:   false,
   241  		EncoderConfig: encoderConfig,
   242  		InitialFields: make(map[string]interface{}),
   243  	}
   244  }