github.com/levb/mattermost-server@v5.3.1+incompatible/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 Int = zap.Int
    32  var Uint32 = zap.Uint32
    33  var String = zap.String
    34  var Any = zap.Any
    35  var Err = zap.Error
    36  var Bool = zap.Bool
    37  
    38  type LoggerConfiguration struct {
    39  	EnableConsole bool
    40  	ConsoleJson   bool
    41  	ConsoleLevel  string
    42  	EnableFile    bool
    43  	FileJson      bool
    44  	FileLevel     string
    45  	FileLocation  string
    46  }
    47  
    48  type Logger struct {
    49  	zap          *zap.Logger
    50  	consoleLevel zap.AtomicLevel
    51  	fileLevel    zap.AtomicLevel
    52  }
    53  
    54  func getZapLevel(level string) zapcore.Level {
    55  	switch level {
    56  	case LevelInfo:
    57  		return zapcore.InfoLevel
    58  	case LevelWarn:
    59  		return zapcore.WarnLevel
    60  	case LevelDebug:
    61  		return zapcore.DebugLevel
    62  	case LevelError:
    63  		return zapcore.ErrorLevel
    64  	default:
    65  		return zapcore.InfoLevel
    66  	}
    67  }
    68  
    69  func makeEncoder(json bool) zapcore.Encoder {
    70  	encoderConfig := zap.NewProductionEncoderConfig()
    71  	if json {
    72  		return zapcore.NewJSONEncoder(encoderConfig)
    73  	}
    74  
    75  	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
    76  	return zapcore.NewConsoleEncoder(encoderConfig)
    77  }
    78  
    79  func NewLogger(config *LoggerConfiguration) *Logger {
    80  	cores := []zapcore.Core{}
    81  	logger := &Logger{
    82  		consoleLevel: zap.NewAtomicLevelAt(getZapLevel(config.ConsoleLevel)),
    83  		fileLevel:    zap.NewAtomicLevelAt(getZapLevel(config.FileLevel)),
    84  	}
    85  
    86  	if config.EnableConsole {
    87  		writer := zapcore.Lock(os.Stdout)
    88  		core := zapcore.NewCore(makeEncoder(config.ConsoleJson), writer, logger.consoleLevel)
    89  		cores = append(cores, core)
    90  	}
    91  
    92  	if config.EnableFile {
    93  		writer := zapcore.AddSync(&lumberjack.Logger{
    94  			Filename: config.FileLocation,
    95  			MaxSize:  100,
    96  			Compress: true,
    97  		})
    98  		core := zapcore.NewCore(makeEncoder(config.FileJson), writer, logger.fileLevel)
    99  		cores = append(cores, core)
   100  	}
   101  
   102  	combinedCore := zapcore.NewTee(cores...)
   103  
   104  	logger.zap = zap.New(combinedCore,
   105  		zap.AddCallerSkip(1),
   106  		zap.AddCaller(),
   107  	)
   108  
   109  	return logger
   110  }
   111  
   112  func (l *Logger) ChangeLevels(config *LoggerConfiguration) {
   113  	l.consoleLevel.SetLevel(getZapLevel(config.ConsoleLevel))
   114  	l.fileLevel.SetLevel(getZapLevel(config.FileLevel))
   115  }
   116  
   117  func (l *Logger) SetConsoleLevel(level string) {
   118  	l.consoleLevel.SetLevel(getZapLevel(level))
   119  }
   120  
   121  func (l *Logger) With(fields ...Field) *Logger {
   122  	newlogger := *l
   123  	newlogger.zap = newlogger.zap.With(fields...)
   124  	return &newlogger
   125  }
   126  
   127  func (l *Logger) StdLog(fields ...Field) *log.Logger {
   128  	return zap.NewStdLog(l.With(fields...).zap.WithOptions(getStdLogOption()))
   129  }
   130  
   131  // StdLogWriter returns a writer that can be hooked up to the output of a golang standard logger
   132  // anything written will be interpreted as log entries accordingly
   133  func (l *Logger) StdLogWriter() io.Writer {
   134  	newLogger := *l
   135  	newLogger.zap = newLogger.zap.WithOptions(zap.AddCallerSkip(4), getStdLogOption())
   136  	f := newLogger.Info
   137  	return &loggerWriter{f}
   138  }
   139  
   140  func (l *Logger) WithCallerSkip(skip int) *Logger {
   141  	newlogger := *l
   142  	newlogger.zap = newlogger.zap.WithOptions(zap.AddCallerSkip(skip))
   143  	return &newlogger
   144  }
   145  
   146  // Made for the plugin interface, wraps mlog in a simpler interface
   147  // at the cost of performance
   148  func (l *Logger) Sugar() *SugarLogger {
   149  	return &SugarLogger{
   150  		wrappedLogger: l,
   151  		zapSugar:      l.zap.Sugar(),
   152  	}
   153  }
   154  
   155  func (l *Logger) Debug(message string, fields ...Field) {
   156  	l.zap.Debug(message, fields...)
   157  }
   158  
   159  func (l *Logger) Info(message string, fields ...Field) {
   160  	l.zap.Info(message, fields...)
   161  }
   162  
   163  func (l *Logger) Warn(message string, fields ...Field) {
   164  	l.zap.Warn(message, fields...)
   165  }
   166  
   167  func (l *Logger) Error(message string, fields ...Field) {
   168  	l.zap.Error(message, fields...)
   169  }
   170  
   171  func (l *Logger) Critical(message string, fields ...Field) {
   172  	l.zap.Error(message, fields...)
   173  }