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 }