github.com/vnforks/kid/v5@v5.22.1-0.20200408055009-b89d99c65676/mlog/log.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package mlog
     5  
     6  import (
     7  	"io"
     8  	"log"
     9  	"os"
    10  
    11  	"go.uber.org/zap"
    12  	"go.uber.org/zap/zapcore"
    13  	"gopkg.in/natefinch/lumberjack.v2"
    14  )
    15  
    16  const (
    17  	// Very verbose messages for debugging specific issues
    18  	LevelDebug = "debug"
    19  	// Default log level, informational
    20  	LevelInfo = "info"
    21  	// Warnings are messages about possible issues
    22  	LevelWarn = "warn"
    23  	// Errors are messages about things we know are problems
    24  	LevelError = "error"
    25  )
    26  
    27  // Type and function aliases from zap to limit the libraries scope into MM code
    28  type Field = zapcore.Field
    29  
    30  var Int64 = zap.Int64
    31  var Int32 = zap.Int32
    32  var Int = zap.Int
    33  var Uint32 = zap.Uint32
    34  var String = zap.String
    35  var Any = zap.Any
    36  var Err = zap.Error
    37  var NamedErr = zap.NamedError
    38  var Bool = zap.Bool
    39  var Duration = zap.Duration
    40  
    41  type LoggerConfiguration struct {
    42  	EnableConsole bool
    43  	ConsoleJson   bool
    44  	ConsoleLevel  string
    45  	EnableFile    bool
    46  	FileJson      bool
    47  	FileLevel     string
    48  	FileLocation  string
    49  }
    50  
    51  type Logger struct {
    52  	zap          *zap.Logger
    53  	consoleLevel zap.AtomicLevel
    54  	fileLevel    zap.AtomicLevel
    55  }
    56  
    57  func getZapLevel(level string) zapcore.Level {
    58  	switch level {
    59  	case LevelInfo:
    60  		return zapcore.InfoLevel
    61  	case LevelWarn:
    62  		return zapcore.WarnLevel
    63  	case LevelDebug:
    64  		return zapcore.DebugLevel
    65  	case LevelError:
    66  		return zapcore.ErrorLevel
    67  	default:
    68  		return zapcore.InfoLevel
    69  	}
    70  }
    71  
    72  func makeEncoder(json bool) zapcore.Encoder {
    73  	encoderConfig := zap.NewProductionEncoderConfig()
    74  	if json {
    75  		return zapcore.NewJSONEncoder(encoderConfig)
    76  	}
    77  
    78  	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
    79  	return zapcore.NewConsoleEncoder(encoderConfig)
    80  }
    81  
    82  func NewLogger(config *LoggerConfiguration) *Logger {
    83  	cores := []zapcore.Core{}
    84  	logger := &Logger{
    85  		consoleLevel: zap.NewAtomicLevelAt(getZapLevel(config.ConsoleLevel)),
    86  		fileLevel:    zap.NewAtomicLevelAt(getZapLevel(config.FileLevel)),
    87  	}
    88  
    89  	if config.EnableConsole {
    90  		writer := zapcore.Lock(os.Stderr)
    91  		core := zapcore.NewCore(makeEncoder(config.ConsoleJson), writer, logger.consoleLevel)
    92  		cores = append(cores, core)
    93  	}
    94  
    95  	if config.EnableFile {
    96  		writer := zapcore.AddSync(&lumberjack.Logger{
    97  			Filename: config.FileLocation,
    98  			MaxSize:  100,
    99  			Compress: true,
   100  		})
   101  		core := zapcore.NewCore(makeEncoder(config.FileJson), writer, logger.fileLevel)
   102  		cores = append(cores, core)
   103  	}
   104  
   105  	combinedCore := zapcore.NewTee(cores...)
   106  
   107  	logger.zap = zap.New(combinedCore,
   108  		zap.AddCaller(),
   109  	)
   110  
   111  	return logger
   112  }
   113  
   114  func (l *Logger) ChangeLevels(config *LoggerConfiguration) {
   115  	l.consoleLevel.SetLevel(getZapLevel(config.ConsoleLevel))
   116  	l.fileLevel.SetLevel(getZapLevel(config.FileLevel))
   117  }
   118  
   119  func (l *Logger) SetConsoleLevel(level string) {
   120  	l.consoleLevel.SetLevel(getZapLevel(level))
   121  }
   122  
   123  func (l *Logger) With(fields ...Field) *Logger {
   124  	newlogger := *l
   125  	newlogger.zap = newlogger.zap.With(fields...)
   126  	return &newlogger
   127  }
   128  
   129  func (l *Logger) StdLog(fields ...Field) *log.Logger {
   130  	return zap.NewStdLog(l.With(fields...).zap.WithOptions(getStdLogOption()))
   131  }
   132  
   133  // StdLogAt returns *log.Logger which writes to supplied zap logger at required level.
   134  func (l *Logger) StdLogAt(level string, fields ...Field) (*log.Logger, error) {
   135  	return zap.NewStdLogAt(l.With(fields...).zap.WithOptions(getStdLogOption()), getZapLevel(level))
   136  }
   137  
   138  // StdLogWriter returns a writer that can be hooked up to the output of a golang standard logger
   139  // anything written will be interpreted as log entries accordingly
   140  func (l *Logger) StdLogWriter() io.Writer {
   141  	newLogger := *l
   142  	newLogger.zap = newLogger.zap.WithOptions(zap.AddCallerSkip(4), getStdLogOption())
   143  	f := newLogger.Info
   144  	return &loggerWriter{f}
   145  }
   146  
   147  func (l *Logger) WithCallerSkip(skip int) *Logger {
   148  	newlogger := *l
   149  	newlogger.zap = newlogger.zap.WithOptions(zap.AddCallerSkip(skip))
   150  	return &newlogger
   151  }
   152  
   153  // Made for the plugin interface, wraps mlog in a simpler interface
   154  // at the cost of performance
   155  func (l *Logger) Sugar() *SugarLogger {
   156  	return &SugarLogger{
   157  		wrappedLogger: l,
   158  		zapSugar:      l.zap.Sugar(),
   159  	}
   160  }
   161  
   162  func (l *Logger) Debug(message string, fields ...Field) {
   163  	l.zap.Debug(message, fields...)
   164  }
   165  
   166  func (l *Logger) Info(message string, fields ...Field) {
   167  	l.zap.Info(message, fields...)
   168  }
   169  
   170  func (l *Logger) Warn(message string, fields ...Field) {
   171  	l.zap.Warn(message, fields...)
   172  }
   173  
   174  func (l *Logger) Error(message string, fields ...Field) {
   175  	l.zap.Error(message, fields...)
   176  }
   177  
   178  func (l *Logger) Critical(message string, fields ...Field) {
   179  	l.zap.Error(message, fields...)
   180  }