github.com/Mrs4s/go-cqhttp@v1.2.0/global/log_hook.go (about) 1 package global 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "path/filepath" 8 "reflect" 9 "strings" 10 "sync" 11 12 "github.com/mattn/go-colorable" 13 "github.com/sirupsen/logrus" 14 ) 15 16 // LocalHook logrus本地钩子 17 type LocalHook struct { 18 lock *sync.Mutex 19 levels []logrus.Level // hook级别 20 formatter logrus.Formatter // 格式 21 path string // 写入path 22 writer io.Writer // io 23 } 24 25 // Levels ref: logrus/hooks.go impl Hook interface 26 func (hook *LocalHook) Levels() []logrus.Level { 27 if len(hook.levels) == 0 { 28 return logrus.AllLevels 29 } 30 return hook.levels 31 } 32 33 func (hook *LocalHook) ioWrite(entry *logrus.Entry) error { 34 log, err := hook.formatter.Format(entry) 35 if err != nil { 36 return err 37 } 38 39 _, err = hook.writer.Write(log) 40 if err != nil { 41 return err 42 } 43 return nil 44 } 45 46 func (hook *LocalHook) pathWrite(entry *logrus.Entry) error { 47 dir := filepath.Dir(hook.path) 48 if err := os.MkdirAll(dir, os.ModePerm); err != nil { 49 return err 50 } 51 52 fd, err := os.OpenFile(hook.path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o666) 53 if err != nil { 54 return err 55 } 56 defer fd.Close() 57 58 log, err := hook.formatter.Format(entry) 59 if err != nil { 60 return err 61 } 62 63 _, err = fd.Write(log) 64 return err 65 } 66 67 // Fire ref: logrus/hooks.go impl Hook interface 68 func (hook *LocalHook) Fire(entry *logrus.Entry) error { 69 hook.lock.Lock() 70 defer hook.lock.Unlock() 71 72 if hook.writer != nil { 73 return hook.ioWrite(entry) 74 } 75 76 if hook.path != "" { 77 return hook.pathWrite(entry) 78 } 79 80 return nil 81 } 82 83 // SetFormatter 设置日志格式 84 func (hook *LocalHook) SetFormatter(consoleFormatter, fileFormatter logrus.Formatter) { 85 hook.lock.Lock() 86 defer hook.lock.Unlock() 87 88 // 支持处理windows平台的console色彩 89 logrus.SetOutput(colorable.NewColorableStdout()) 90 // 用于在console写出 91 logrus.SetFormatter(consoleFormatter) 92 // 用于写入文件 93 hook.formatter = fileFormatter 94 } 95 96 // SetWriter 设置Writer 97 func (hook *LocalHook) SetWriter(writer io.Writer) { 98 hook.lock.Lock() 99 defer hook.lock.Unlock() 100 hook.writer = writer 101 } 102 103 // SetPath 设置日志写入路径 104 func (hook *LocalHook) SetPath(path string) { 105 hook.lock.Lock() 106 defer hook.lock.Unlock() 107 hook.path = path 108 } 109 110 // NewLocalHook 初始化本地日志钩子实现 111 func NewLocalHook(args any, consoleFormatter, fileFormatter logrus.Formatter, levels ...logrus.Level) *LocalHook { 112 hook := &LocalHook{ 113 lock: new(sync.Mutex), 114 } 115 hook.SetFormatter(consoleFormatter, fileFormatter) 116 hook.levels = append(hook.levels, levels...) 117 118 switch arg := args.(type) { 119 case string: 120 hook.SetPath(arg) 121 case io.Writer: 122 hook.SetWriter(arg) 123 default: 124 panic(fmt.Sprintf("unsupported type: %v", reflect.TypeOf(args))) 125 } 126 127 return hook 128 } 129 130 // GetLogLevel 获取日志等级 131 // 132 // 可能的值有 133 // 134 // "trace","debug","info","warn","warn","error" 135 func GetLogLevel(level string) []logrus.Level { 136 switch level { 137 case "trace": 138 return []logrus.Level{ 139 logrus.TraceLevel, logrus.DebugLevel, 140 logrus.InfoLevel, logrus.WarnLevel, logrus.ErrorLevel, 141 logrus.FatalLevel, logrus.PanicLevel, 142 } 143 case "debug": 144 return []logrus.Level{ 145 logrus.DebugLevel, logrus.InfoLevel, 146 logrus.WarnLevel, logrus.ErrorLevel, 147 logrus.FatalLevel, logrus.PanicLevel, 148 } 149 case "info": 150 return []logrus.Level{ 151 logrus.InfoLevel, logrus.WarnLevel, 152 logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel, 153 } 154 case "warn": 155 return []logrus.Level{ 156 logrus.WarnLevel, logrus.ErrorLevel, 157 logrus.FatalLevel, logrus.PanicLevel, 158 } 159 case "error": 160 return []logrus.Level{ 161 logrus.ErrorLevel, logrus.FatalLevel, 162 logrus.PanicLevel, 163 } 164 default: 165 return []logrus.Level{ 166 logrus.InfoLevel, logrus.WarnLevel, 167 logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel, 168 } 169 } 170 } 171 172 // LogFormat specialize for go-cqhttp 173 type LogFormat struct { 174 EnableColor bool 175 } 176 177 // Format implements logrus.Formatter 178 func (f LogFormat) Format(entry *logrus.Entry) ([]byte, error) { 179 buf := NewBuffer() 180 defer PutBuffer(buf) 181 182 if f.EnableColor { 183 buf.WriteString(GetLogLevelColorCode(entry.Level)) 184 } 185 186 buf.WriteByte('[') 187 buf.WriteString(entry.Time.Format("2006-01-02 15:04:05")) 188 buf.WriteString("] [") 189 buf.WriteString(strings.ToUpper(entry.Level.String())) 190 buf.WriteString("]: ") 191 buf.WriteString(entry.Message) 192 buf.WriteString(" \n") 193 194 if f.EnableColor { 195 buf.WriteString(colorReset) 196 } 197 198 ret := make([]byte, len(buf.Bytes())) 199 copy(ret, buf.Bytes()) // copy buffer 200 return ret, nil 201 } 202 203 const ( 204 colorCodePanic = "\x1b[1;31m" // color.Style{color.Bold, color.Red}.String() 205 colorCodeFatal = "\x1b[1;31m" // color.Style{color.Bold, color.Red}.String() 206 colorCodeError = "\x1b[31m" // color.Style{color.Red}.String() 207 colorCodeWarn = "\x1b[33m" // color.Style{color.Yellow}.String() 208 colorCodeInfo = "\x1b[37m" // color.Style{color.White}.String() 209 colorCodeDebug = "\x1b[32m" // color.Style{color.Green}.String() 210 colorCodeTrace = "\x1b[36m" // color.Style{color.Cyan}.String() 211 colorReset = "\x1b[0m" 212 ) 213 214 // GetLogLevelColorCode 获取日志等级对应色彩code 215 func GetLogLevelColorCode(level logrus.Level) string { 216 switch level { 217 case logrus.PanicLevel: 218 return colorCodePanic 219 case logrus.FatalLevel: 220 return colorCodeFatal 221 case logrus.ErrorLevel: 222 return colorCodeError 223 case logrus.WarnLevel: 224 return colorCodeWarn 225 case logrus.InfoLevel: 226 return colorCodeInfo 227 case logrus.DebugLevel: 228 return colorCodeDebug 229 case logrus.TraceLevel: 230 return colorCodeTrace 231 232 default: 233 return colorCodeInfo 234 } 235 }