gitee.com/lh-her-team/common@v1.5.1/log/log.go (about) 1 package log 2 3 import ( 4 "errors" 5 "fmt" 6 "hash/crc32" 7 "io" 8 "log" 9 "os" 10 "strings" 11 "time" 12 13 rotatelogs "gitee.com/lh-her-team/common/log/file-rotatelogs" 14 "go.uber.org/zap" 15 "go.uber.org/zap/zapcore" 16 ) 17 18 //LOG_LEVEL 日志级别,int类型,内部接口使用常量 19 type LOG_LEVEL int 20 21 const ( 22 LEVEL_DEBUG LOG_LEVEL = iota 23 LEVEL_INFO 24 LEVEL_WARN 25 LEVEL_ERROR 26 ) 27 28 // 日志级别,配置文件定义的常量 29 const ( 30 DEBUG = "DEBUG" 31 INFO = "INFO" 32 WARN = "WARN" 33 ERROR = "ERROR" 34 ) 35 36 // GetLogLevel 根据字符串型的日志级别,返回枚举型日志级别 37 // @param lvl 38 // @return LOG_LEVEL 39 func GetLogLevel(lvl string) LOG_LEVEL { 40 switch strings.ToUpper(lvl) { 41 case ERROR: 42 return LEVEL_ERROR 43 case WARN: 44 return LEVEL_WARN 45 case INFO: 46 return LEVEL_INFO 47 case DEBUG: 48 return LEVEL_DEBUG 49 } 50 return LEVEL_INFO 51 } 52 53 func getZapLevel(lvl string) (*zapcore.Level, error) { 54 var zapLevel zapcore.Level 55 switch strings.ToUpper(lvl) { 56 case ERROR: 57 zapLevel = zap.ErrorLevel 58 case WARN: 59 zapLevel = zap.WarnLevel 60 case INFO: 61 zapLevel = zap.InfoLevel 62 case DEBUG: 63 zapLevel = zap.DebugLevel 64 default: 65 return nil, errors.New("invalid log level") 66 } 67 return &zapLevel, nil 68 } 69 70 // 日志切割默认配置 71 const ( 72 DEFAULT_MAX_AGE = 365 // 日志最长保存时间,单位:天 73 DEFAULT_ROTATION_TIME = 6 // 日志滚动间隔,单位:小时 74 DEFAULT_ROTATION_SIZE = 100 // 默认的日志滚动大小,单位:MB 75 ) 76 77 //日志滚动单位 78 const ( 79 ROTATION_SIZE_MB = 1024 * 1024 80 ) 81 82 type color int 83 84 const ( 85 ColorBlack color = iota + 30 86 ColorRed 87 ColorGreen 88 ColorYellow 89 ColorBlue 90 ColorMagenta 91 ColorCyan 92 ColorWhite 93 ) 94 95 var colorList = [...]color{ColorRed, ColorGreen, ColorYellow, ColorBlue, ColorMagenta} 96 97 var hookMap = make(map[string]struct{}) 98 99 type LogConfig struct { 100 Module string // module: module name 101 ChainId string // chainId: chain id 102 LogPath string // logPath: log file save path 103 LogLevel LOG_LEVEL // logLevel: log level 104 MaxAge int // maxAge: the maximum number of days to retain old log files 105 RotationTime int // RotationTime: rotation time 106 RotationSize int64 // RotationSize: rotation size Mb 107 JsonFormat bool // jsonFormat: log file use json format 108 ShowLine bool // showLine: show filename and line number 109 LogInConsole bool // logInConsole: show logs in console at the same time 110 ShowColor bool // if true, show color log 111 IsBrief bool // if true, only show log, won't print log level、caller func and line 112 113 // StackTraceLevel record a stack trace for all messages at or above a given level. 114 // Empty string or invalid level will not open stack trace. 115 StackTraceLevel string 116 } 117 118 func InitSugarLogger(logConfig *LogConfig, writer ...io.Writer) (*zap.SugaredLogger, zap.AtomicLevel) { 119 var level zapcore.Level 120 switch logConfig.LogLevel { 121 case LEVEL_DEBUG: 122 level = zap.DebugLevel 123 case LEVEL_INFO: 124 level = zap.InfoLevel 125 case LEVEL_WARN: 126 level = zap.WarnLevel 127 case LEVEL_ERROR: 128 level = zap.ErrorLevel 129 default: 130 level = zap.InfoLevel 131 } 132 aLevel := zap.NewAtomicLevel() 133 aLevel.SetLevel(level) 134 sugaredLogger := newLogger(logConfig, aLevel, writer...).Sugar() 135 return sugaredLogger, aLevel 136 } 137 138 func newLogger(logConfig *LogConfig, level zap.AtomicLevel, writer ...io.Writer) *zap.Logger { 139 var ( 140 hook io.Writer 141 ok bool 142 err error 143 ) 144 _, ok = hookMap[logConfig.LogPath] 145 if !ok { 146 hook, err = getHook(logConfig.LogPath, logConfig.MaxAge, logConfig.RotationTime, logConfig.RotationSize) 147 if err != nil { 148 log.Fatalf("new logger get hook failed, %s", err) 149 } 150 hookMap[logConfig.LogPath] = struct{}{} 151 } else { 152 hook, err = getHook(logConfig.LogPath, logConfig.MaxAge, 0, logConfig.RotationSize) 153 if err != nil { 154 log.Fatalf("new logger get hook failed, %s", err) 155 } 156 } 157 var syncer zapcore.WriteSyncer 158 syncers := []zapcore.WriteSyncer{zapcore.AddSync(hook)} 159 if logConfig.LogInConsole { 160 syncers = append(syncers, zapcore.AddSync(os.Stdout)) 161 } 162 for _, outSyncer := range writer { 163 syncers = append(syncers, zapcore.AddSync(outSyncer)) 164 } 165 syncer = zapcore.NewMultiWriteSyncer(syncers...) 166 var encoderConfig zapcore.EncoderConfig 167 if logConfig.IsBrief { 168 encoderConfig = zapcore.EncoderConfig{ 169 TimeKey: "time", 170 MessageKey: "msg", 171 EncodeTime: CustomTimeEncoder, 172 LineEnding: zapcore.DefaultLineEnding, 173 } 174 } else { 175 encoderConfig = zapcore.EncoderConfig{ 176 TimeKey: "time", 177 LevelKey: "level", 178 NameKey: "logger", 179 CallerKey: "line", 180 MessageKey: "msg", 181 StacktraceKey: "stacktrace", 182 LineEnding: zapcore.DefaultLineEnding, 183 EncodeLevel: CustomLevelEncoder, 184 EncodeTime: CustomTimeEncoder, 185 EncodeDuration: zapcore.SecondsDurationEncoder, 186 EncodeCaller: zapcore.ShortCallerEncoder, 187 EncodeName: zapcore.FullNameEncoder, 188 } 189 } 190 var encoder zapcore.Encoder 191 if logConfig.JsonFormat { 192 encoder = zapcore.NewJSONEncoder(encoderConfig) 193 } else { 194 encoder = zapcore.NewConsoleEncoder(encoderConfig) 195 } 196 core := zapcore.NewCore( 197 encoder, 198 syncer, 199 level, 200 ) 201 chainId := fmt.Sprintf("@%s", logConfig.ChainId) 202 if logConfig.ShowColor { 203 chainId = getColorChainId(chainId) 204 } 205 var name string 206 if logConfig.ChainId != "" { 207 name = fmt.Sprintf("%s %s", logConfig.Module, chainId) 208 } else { 209 name = logConfig.Module 210 } 211 logger := zap.New(core).Named(name) 212 defer func(logger *zap.Logger) { 213 _ = logger.Sync() 214 }(logger) 215 if logConfig.ShowLine { 216 logger = logger.WithOptions(zap.AddCaller()) 217 } 218 if lvl, err := getZapLevel(logConfig.StackTraceLevel); err == nil { 219 logger = logger.WithOptions(zap.AddStacktrace(lvl)) 220 } 221 logger = logger.WithOptions(zap.AddCallerSkip(1)) 222 return logger 223 } 224 225 func getHook(filename string, maxAge, rotationTime int, rotationSize int64) (io.Writer, error) { 226 hook, err := rotatelogs.New( 227 filename+".%Y%m%d%H", 228 rotatelogs.WithRotationTime(time.Hour*time.Duration(rotationTime)), 229 //filename+".%Y%m%d%H%M", 230 //rotatelogs.WithRotationSize(rotationSize*ROTATION_SIZE_MB), 231 rotatelogs.WithLinkName(filename), 232 rotatelogs.WithMaxAge(time.Hour*24*time.Duration(maxAge)), 233 ) 234 if err != nil { 235 return nil, err 236 } 237 return hook, nil 238 } 239 240 // nolint: deadcode, unused 241 func recognizeLogLevel(l string) LOG_LEVEL { 242 logLevel := strings.ToUpper(l) 243 var level LOG_LEVEL 244 switch logLevel { 245 case DEBUG: 246 level = LEVEL_DEBUG 247 case INFO: 248 level = LEVEL_INFO 249 case WARN: 250 level = LEVEL_WARN 251 case ERROR: 252 level = LEVEL_ERROR 253 default: 254 level = LEVEL_INFO 255 } 256 return level 257 } 258 259 func CustomLevelEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { 260 enc.AppendString("[" + level.CapitalString() + "]") 261 } 262 263 func CustomTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { 264 enc.AppendString(t.Format("2006-01-02 15:04:05.000")) 265 } 266 267 // nolint: deadcode, unused 268 func showColor(color color, msg string) string { 269 return fmt.Sprintf("\033[%dm%s\033[0m", int(color), msg) 270 } 271 272 func showColorBold(color color, msg string) string { 273 return fmt.Sprintf("\033[%d;1m%s\033[0m", int(color), msg) 274 } 275 276 func getColorChainId(chainId string) string { 277 c := crc32.ChecksumIEEE([]byte(chainId)) 278 color := colorList[int(c)%len(colorList)] 279 return showColorBold(color, chainId) 280 }