gitee.com/hongliu9527/go-tools@v0.0.8/logger/logger.go (about) 1 /* 2 * @Author: hongliu 3 * @Date: 2022-04-26 09:34:48 4 * @LastEditors: hongliu 5 * @LastEditTime: 2022-04-26 10:34:25 6 * @FilePath: \go-tools\logger\logger.go 7 * @Description: 封装日志 8 * 9 * Copyright (c) 2022 by 洪流, All Rights Reserved. 10 */ 11 12 // 1. 支持日志信息输出到终端和日志文件(支持同时输出),默认终端输出 13 // 1.1 支持日志文件容量限制 14 // 1.2 支持日志文件切片(按天进行切分)) 15 // 1.3 支持设置最大保留天数 16 // 1.4 保证系统升级时不会清除存在的日志 17 // 1.5 当剩余磁盘空间少于日志文件容量[可选] 18 // 1.6 终端输出时支持颜色 19 // 2. 保证系统升级时不会清除日志系统配置 20 // 3. 支持日志输出等级 21 22 package logger 23 24 import ( 25 "fmt" 26 "path" 27 "runtime" 28 "strconv" 29 "time" 30 31 rotatelogs "github.com/lestrrat-go/file-rotatelogs" 32 "github.com/rifflock/lfshook" 33 "github.com/sirupsen/logrus" 34 ) 35 36 // Logger 日志记录器类型封装 37 var logger *logrus.Logger 38 39 // fixFields 日志上报的固定信息域 40 var fixFields = make(logrus.Fields, 0) 41 42 // 模块初始化函数 43 func init() { 44 logger = logrus.New() 45 logger = logrus.New() 46 logger.SetFormatter(&Formatter{ 47 TimestampFormat: "2006-01-02 15:04:05.000", // 设置时间戳格式 48 NoFieldsColors: false, // 设置单行所有内容都显示颜色 49 }) 50 } 51 52 // LogConfig 日志配置 53 type LogConfig struct { 54 AppName string // 应用程序名称 55 LogDir string // 保存目录 56 IsSaveToFile bool // 是否保存日志文件 57 ConsoleLogLevel string // 终端日志等级 58 FileLogLevel string // 文件日志等级 59 RotationIntervalTime time.Duration // 日志分割时间间隔 60 MaxRotationRemainCount uint // 日志分割文件个数 61 } 62 63 // logDefaultConfig 默认日志配置 64 var logDefaultConfig = LogConfig{ 65 AppName: "App", // 默认日志文件以应用程序名称的前缀 66 LogDir: "./log", // 默认日志保存目录为当前目录下log目录 67 IsSaveToFile: true, // 默认开启日志文件保存功能 68 ConsoleLogLevel: "info", // 默认设置日志命令行输出级别 69 FileLogLevel: "info", // 默认设置日志文件输出级别 70 RotationIntervalTime: time.Hour, // 默认设置每隔1个小时切分一次日志文件 71 MaxRotationRemainCount: 24, // 默认设置只保存24个小时的日志内容 72 } 73 74 // ChinaClock 中国时区时钟 75 type ChinaClock struct{} 76 77 // Now 查询当前时间 78 func (t ChinaClock) Now() time.Time { 79 return time.Now().UTC().Add(8 * time.Hour) 80 } 81 82 // newLogFileHook 创建日志文件相关的钩子 83 // 1. 支持日志文件分割 84 func newLogFileHook(logDir string, logLevel logrus.Level) logrus.Hook { 85 writer, err := rotatelogs.New( 86 logDir+"/"+logDefaultConfig.AppName+"_%Y-%m-%d_%H.log", 87 rotatelogs.WithClock(ChinaClock{}), 88 rotatelogs.WithRotationTime(logDefaultConfig.RotationIntervalTime), // 设置日志分割的时间 89 rotatelogs.WithRotationCount(logDefaultConfig.MaxRotationRemainCount), // 设置文件清理前最多保存的个数 90 // rotatelogs.WithMaxAge(time.Hour*24), // 设置文件清理前的最长保存时间(WithMaxAge和WithRotationCount二者只能设置一个) 91 ) 92 93 if err != nil { 94 logrus.Errorf("配置日志文件分割属性失败(%s)", err.Error()) 95 } 96 97 writerMap := make(lfshook.WriterMap) 98 levels := []logrus.Level{ 99 logrus.DebugLevel, 100 logrus.InfoLevel, 101 logrus.WarnLevel, 102 logrus.ErrorLevel, 103 logrus.FatalLevel, 104 logrus.PanicLevel, 105 } 106 107 for _, level := range levels { 108 if int(level) <= int(logLevel) { 109 writerMap[level] = writer 110 } 111 } 112 113 lfsHook := lfshook.NewHook(writerMap, &logrus.TextFormatter{ 114 DisableColors: true, 115 FullTimestamp: true, 116 TimestampFormat: "2006-01-02 15:04:05.000", 117 }) 118 return lfsHook 119 } 120 121 // SetAppName 设置日志文件名以对应的应用程序名称为前缀 122 func SetAppName(appName string) { 123 logDefaultConfig.AppName = appName 124 } 125 126 // SetLogFileDir 设置日志文件目录 127 func SetLogFileDir(dir string) error { 128 logDefaultConfig.LogDir = dir 129 return nil 130 } 131 132 // SetLogRotationTime 设置日志文件分割时长(NOTE: 最小有效时间间隔为小时) 133 func SetLogRotationTime(duration time.Duration) { 134 logDefaultConfig.RotationIntervalTime = duration 135 } 136 137 // SetLogRotationMaxFileCount 设置日志文件分割最大个数 138 func SetLogRotationMaxFileCount(fileCount uint) { 139 logDefaultConfig.MaxRotationRemainCount = fileCount 140 } 141 142 // SetFileLevel 设置日志文件输出等级 143 func SetFileLevel(logLevel string) { 144 level, err := logrus.ParseLevel(logLevel) 145 if err != nil { 146 logrus.Errorf("输入的日志等级(%s)校验失败(%s)", logLevel, err.Error()) 147 return 148 } 149 150 // 创建日志文件相关的钩子替换掉默认钩子从而实现日志文件保存功能 151 hooks := make(logrus.LevelHooks) 152 hooks.Add(newLogFileHook(logDefaultConfig.LogDir, level)) 153 logger.ReplaceHooks(hooks) 154 } 155 156 // SetFixedFields 设置日志上报的固定信息域 157 func SetFixedFields(fields logrus.Fields) { 158 fixFields = fields 159 } 160 161 // AddFixedField 增加日志上报的固定信息域 162 func AddFixedField(key string, value interface{}) { 163 fixFields[key] = value 164 } 165 166 // SetConsoleLevel 设置日志终端输出等级 167 func SetConsoleLevel(logLevel string) { 168 level, err := logrus.ParseLevel(logLevel) 169 if err != nil { 170 logrus.Errorf("输入的日志等级(%s)校验失败(%s)", logLevel, err.Error()) 171 return 172 } 173 174 if logger != nil { 175 logger.SetLevel(level) 176 } 177 } 178 179 // Debug 输出Debug信息 180 func Debug(format string, v ...interface{}) { 181 _, filepath, line, ok := runtime.Caller(1) 182 if ok { 183 format = "[" + path.Base(filepath) + ":" + strconv.Itoa(line) + "] " + format 184 } 185 186 now := time.Now().UTC().Add(8 * time.Hour) 187 if logger != nil { 188 if len(v) == 0 { 189 logger.WithTime(now).WithFields(fixFields).Debug(format) 190 } else { 191 logger.WithTime(now).WithFields(fixFields).Debugf(format, v...) 192 } 193 } else { 194 fmt.Println("日志记录器未创建") 195 } 196 } 197 198 // Info 输出Info信息 199 func Info(format string, v ...interface{}) { 200 _, filepath, line, ok := runtime.Caller(1) 201 if ok { 202 format = "[" + path.Base(filepath) + ":" + strconv.Itoa(line) + "] " + format 203 } 204 205 now := time.Now().UTC().Add(8 * time.Hour) 206 if logger != nil { 207 if len(v) == 0 { 208 logger.WithTime(now).WithFields(fixFields).Info(format) 209 } else { 210 logger.WithTime(now).WithFields(fixFields).Infof(format, v...) 211 } 212 } else { 213 fmt.Println("日志记录器未创建") 214 } 215 } 216 217 // Warning 输出Warning信息 218 func Warning(format string, v ...interface{}) { 219 _, filepath, line, ok := runtime.Caller(1) 220 if ok { 221 format = "[" + path.Base(filepath) + ":" + strconv.Itoa(line) + "] " + format 222 } 223 224 now := time.Now().UTC().Add(8 * time.Hour) 225 if logger != nil { 226 if len(v) == 0 { 227 logger.WithTime(now).WithFields(fixFields).Warn(format) 228 } else { 229 logger.WithTime(now).WithFields(fixFields).Warnf(format, v...) 230 } 231 } else { 232 fmt.Println("日志记录器未创建") 233 } 234 } 235 236 // Error 输出Error信息 237 func Error(format string, v ...interface{}) { 238 _, filepath, line, ok := runtime.Caller(1) 239 if ok { 240 format = "[" + path.Base(filepath) + ":" + strconv.Itoa(line) + "] " + format 241 } 242 243 now := time.Now().UTC().Add(8 * time.Hour) 244 if logger != nil { 245 if len(v) == 0 { 246 logger.WithTime(now).WithFields(fixFields).Error(format) 247 } else { 248 logger.WithTime(now).WithFields(fixFields).Errorf(format, v...) 249 } 250 } else { 251 fmt.Println("日志记录器未创建") 252 } 253 } 254 255 // Fatal 输出Fatal信息 256 func Fatal(format string, v ...interface{}) { 257 _, filepath, line, ok := runtime.Caller(1) 258 if ok { 259 format = "[" + path.Base(filepath) + ":" + strconv.Itoa(line) + "] " + format 260 } 261 262 now := time.Now().UTC().Add(8 * time.Hour) 263 if logger != nil { 264 if len(v) == 0 { 265 logger.WithTime(now).WithFields(fixFields).Fatal(format) 266 } else { 267 logger.WithTime(now).WithFields(fixFields).Fatalf(format, v...) 268 } 269 } else { 270 fmt.Println("日志记录器未创建") 271 } 272 }