github.com/matrixorigin/matrixone@v0.7.0/pkg/logutil/internal.go (about)

     1  // Copyright 2021 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package logutil
    16  
    17  import (
    18  	"context"
    19  	"os"
    20  	"sync/atomic"
    21  	"time"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    24  	"go.uber.org/zap"
    25  	"go.uber.org/zap/zapcore"
    26  	"gopkg.in/natefinch/lumberjack.v2"
    27  )
    28  
    29  // SetupMOLogger sets up the global logger for MO Server.
    30  func SetupMOLogger(conf *LogConfig) {
    31  	setGlobalLogConfig(conf) // keep for dragonboat/v4, ... and so on
    32  	logger, err := initMOLogger(conf)
    33  	if err != nil {
    34  		panic(err)
    35  	}
    36  	replaceGlobalLogger(logger)
    37  	Infof("MO logger init, level=%s, log file=%s", conf.Level, conf.Filename)
    38  }
    39  
    40  // initMOLogger initializes a zap Logger.
    41  func initMOLogger(cfg *LogConfig) (*zap.Logger, error) {
    42  	return GetLoggerWithOptions(cfg.getLevel(), cfg.getEncoder(), cfg.getSyncer()), nil
    43  }
    44  
    45  // global zap logger for MO server.
    46  var _globalLogger atomic.Value
    47  var _skip1Logger atomic.Value
    48  var _errorLogger atomic.Value
    49  
    50  // init initializes a default zap logger before set up logger.
    51  func init() {
    52  	SetLogReporter(&TraceReporter{noopReportZap, noopContextField})
    53  	conf := &LogConfig{Level: "info", Format: "console"}
    54  	setGlobalLogConfig(conf)
    55  	logger, _ := initMOLogger(conf)
    56  	replaceGlobalLogger(logger)
    57  }
    58  
    59  // GetGlobalLogger returns the current global zap Logger.
    60  func GetGlobalLogger() *zap.Logger {
    61  	return _globalLogger.Load().(*zap.Logger)
    62  }
    63  
    64  func GetSkip1Logger() *zap.Logger {
    65  	return _skip1Logger.Load().(*zap.Logger)
    66  }
    67  
    68  func GetErrorLogger() *zap.Logger {
    69  	return _errorLogger.Load().(*zap.Logger)
    70  }
    71  
    72  // replaceGlobalLogger replaces the current global zap Logger.
    73  func replaceGlobalLogger(logger *zap.Logger) {
    74  	_globalLogger.Store(logger)
    75  	_skip1Logger.Store(logger.WithOptions(zap.AddCallerSkip(1)))
    76  	_errorLogger.Store(logger.WithOptions(zap.AddCallerSkip(1), zap.AddStacktrace(zap.ErrorLevel)))
    77  }
    78  
    79  type LogConfig struct {
    80  	Level      string `toml:"level"`
    81  	Format     string `toml:"format"`
    82  	Filename   string `toml:"filename"`
    83  	MaxSize    int    `toml:"max-size"`
    84  	MaxDays    int    `toml:"max-days"`
    85  	MaxBackups int    `toml:"max-backups"`
    86  	// DisableStore ctrl store log into db
    87  	DisableStore bool `toml:"disable-store"`
    88  }
    89  
    90  func (cfg *LogConfig) getSyncer() zapcore.WriteSyncer {
    91  	if cfg.Filename == "" || cfg.Filename == "console" {
    92  		return getConsoleSyncer()
    93  	}
    94  
    95  	if stat, err := os.Stat(cfg.Filename); err == nil {
    96  		if stat.IsDir() {
    97  			panic("log file can't be a directory")
    98  		}
    99  	}
   100  
   101  	if cfg.MaxSize == 0 {
   102  		cfg.MaxSize = 512
   103  	}
   104  	// add lumberjack logger
   105  	return zapcore.AddSync(&lumberjack.Logger{
   106  		Filename:   cfg.Filename,
   107  		MaxSize:    cfg.MaxSize,
   108  		MaxAge:     cfg.MaxDays,
   109  		MaxBackups: cfg.MaxBackups,
   110  		LocalTime:  true,
   111  		Compress:   false,
   112  	})
   113  }
   114  
   115  func (cfg *LogConfig) getEncoder() zapcore.Encoder {
   116  	return getLoggerEncoder(cfg.Format)
   117  }
   118  
   119  func (cfg *LogConfig) getLevel() zap.AtomicLevel {
   120  	level := zap.NewAtomicLevel()
   121  	err := level.UnmarshalText([]byte(cfg.Level))
   122  	if err != nil {
   123  		panic(err)
   124  	}
   125  	return level
   126  }
   127  
   128  func (cfg *LogConfig) getSinks() (sinks []ZapSink) {
   129  	encoder, syncer := cfg.getEncoder(), cfg.getSyncer()
   130  	sinks = append(sinks, ZapSink{encoder, syncer})
   131  	if !cfg.DisableStore {
   132  		encoder, syncer := getTraceLogSinks()
   133  		sinks = append(sinks, ZapSink{encoder, syncer})
   134  	}
   135  	return
   136  }
   137  
   138  func (cfg *LogConfig) getOptions() []zap.Option {
   139  	return []zap.Option{zap.AddStacktrace(zapcore.FatalLevel), zap.AddCaller()}
   140  }
   141  
   142  func getLoggerEncoder(format string) zapcore.Encoder {
   143  	encoderConfig := zapcore.EncoderConfig{
   144  		MessageKey:    "msg",
   145  		LevelKey:      "level",
   146  		TimeKey:       "time",
   147  		NameKey:       "name",
   148  		CallerKey:     "caller",
   149  		StacktraceKey: "stacktrace",
   150  		LineEnding:    zapcore.DefaultLineEnding,
   151  		EncodeLevel:   zapcore.CapitalLevelEncoder,
   152  		EncodeTime: zapcore.TimeEncoder(func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
   153  			enc.AppendString(t.Format("2006/01/02 15:04:05.000000 -0700"))
   154  		}),
   155  		EncodeDuration:   zapcore.StringDurationEncoder,
   156  		EncodeCaller:     zapcore.ShortCallerEncoder,
   157  		ConsoleSeparator: " ",
   158  	}
   159  
   160  	switch format {
   161  	case "json", "":
   162  		return zapcore.NewJSONEncoder(encoderConfig)
   163  	case "console":
   164  		return zapcore.NewConsoleEncoder(encoderConfig)
   165  	default:
   166  		panic(moerr.NewInternalError(context.Background(), "unsupported log format: %s", format))
   167  	}
   168  }
   169  
   170  func getConsoleSyncer() zapcore.WriteSyncer {
   171  	syncer, _, err := zap.Open([]string{"stdout"}...)
   172  	if err != nil {
   173  		panic(err)
   174  	}
   175  	return syncer
   176  }