github.com/matrixorigin/matrixone@v1.2.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, stackLevel=%s", conf.Level, conf.Filename, conf.StacktraceLevel) 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(), cfg.getOptions()...), 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 := GetDefaultConfig() 54 setGlobalLogConfig(&conf) 55 logger, _ := initMOLogger(&conf) 56 replaceGlobalLogger(logger) 57 } 58 59 func GetDefaultConfig() LogConfig { 60 return LogConfig{Level: "info", Format: "console", StacktraceLevel: "panic"} 61 } 62 63 // GetGlobalLogger returns the current global zap Logger. 64 func GetGlobalLogger() *zap.Logger { 65 return _globalLogger.Load().(*zap.Logger) 66 } 67 68 func GetSkip1Logger() *zap.Logger { 69 return _skip1Logger.Load().(*zap.Logger) 70 } 71 72 func GetErrorLogger() *zap.Logger { 73 return _errorLogger.Load().(*zap.Logger) 74 } 75 76 // replaceGlobalLogger replaces the current global zap Logger. 77 func replaceGlobalLogger(logger *zap.Logger) { 78 _globalLogger.Store(logger) 79 _skip1Logger.Store(logger.WithOptions(zap.AddCallerSkip(1))) 80 _errorLogger.Store(logger.WithOptions(zap.AddCallerSkip(1))) 81 } 82 83 type LogConfig struct { 84 Level string `toml:"level" user_setting:"basic"` 85 Format string `toml:"format" user_setting:"basic"` 86 Filename string `toml:"filename" user_setting:"advanced"` 87 MaxSize int `toml:"max-size"` 88 MaxDays int `toml:"max-days"` 89 MaxBackups int `toml:"max-backups"` 90 // DisableStore ctrl store log into db 91 DisableStore bool `toml:"disable-store"` 92 // DisableLog ctrl log into console 93 DisableLog bool `toml:"disable-log"` 94 // StacktraceLevel 95 StacktraceLevel string `toml:"stacktrace-level"` 96 } 97 98 func (cfg *LogConfig) getSyncer() zapcore.WriteSyncer { 99 if cfg.Filename == "" || cfg.Filename == "console" { 100 return getConsoleSyncer() 101 } 102 103 if stat, err := os.Stat(cfg.Filename); err == nil { 104 if stat.IsDir() { 105 panic("log file can't be a directory") 106 } 107 } 108 109 if cfg.MaxSize == 0 { 110 cfg.MaxSize = 512 111 } 112 // add lumberjack logger 113 return zapcore.AddSync(&lumberjack.Logger{ 114 Filename: cfg.Filename, 115 MaxSize: cfg.MaxSize, 116 MaxAge: cfg.MaxDays, 117 MaxBackups: cfg.MaxBackups, 118 LocalTime: true, 119 Compress: false, 120 }) 121 } 122 123 func (cfg *LogConfig) getEncoder() zapcore.Encoder { 124 return getLoggerEncoder(cfg.Format) 125 } 126 127 func (cfg *LogConfig) getLevel() zap.AtomicLevel { 128 level := zap.NewAtomicLevel() 129 err := level.UnmarshalText([]byte(cfg.Level)) 130 if err != nil { 131 panic(err) 132 } 133 return level 134 } 135 136 // getStacktraceLevel return stacktrace level. 137 // If cfg.StacktraceLevel == "", then return zap.PanicLevel 138 func (cfg *LogConfig) getStacktraceLevel() (level zapcore.Level) { 139 if len(cfg.StacktraceLevel) == 0 { 140 return zap.PanicLevel 141 } 142 err := level.UnmarshalText([]byte(cfg.StacktraceLevel)) 143 if err != nil { 144 panic(err) 145 } 146 return level 147 } 148 149 func (cfg *LogConfig) getSinks() (sinks []ZapSink) { 150 if !cfg.DisableLog { 151 encoder, syncer := cfg.getEncoder(), cfg.getSyncer() 152 sinks = append(sinks, ZapSink{encoder, syncer}) 153 } 154 if !cfg.DisableStore { 155 encoder, syncer := getTraceLogSinks() 156 sinks = append(sinks, ZapSink{encoder, syncer}) 157 } 158 return 159 } 160 161 func (cfg *LogConfig) getOptions() []zap.Option { 162 return []zap.Option{zap.AddStacktrace(cfg.getStacktraceLevel()), zap.AddCaller()} 163 } 164 165 func getLoggerEncoder(format string) zapcore.Encoder { 166 encoderConfig := zapcore.EncoderConfig{ 167 MessageKey: "msg", 168 LevelKey: "level", 169 TimeKey: "time", 170 NameKey: "name", 171 CallerKey: "caller", 172 StacktraceKey: "stacktrace", 173 LineEnding: zapcore.DefaultLineEnding, 174 EncodeLevel: zapcore.CapitalLevelEncoder, 175 EncodeTime: zapcore.TimeEncoder(func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { 176 enc.AppendString(t.Format("2006/01/02 15:04:05.000000 -0700")) 177 }), 178 EncodeDuration: zapcore.StringDurationEncoder, 179 EncodeCaller: zapcore.ShortCallerEncoder, 180 ConsoleSeparator: " ", 181 } 182 183 switch format { 184 case "json", "": 185 return zapcore.NewJSONEncoder(encoderConfig) 186 case "console": 187 return zapcore.NewConsoleEncoder(encoderConfig) 188 default: 189 panic(moerr.NewInternalError(context.Background(), "unsupported log format: %s", format)) 190 } 191 } 192 193 func getConsoleSyncer() zapcore.WriteSyncer { 194 syncer, _, err := zap.Open([]string{"stdout"}...) 195 if err != nil { 196 panic(err) 197 } 198 return syncer 199 }