# Logrus_Study **Repository Path**: baitayanbin/logrus_-study ## Basic Information - **Project Name**: Logrus_Study - **Description**: No description available - **Primary Language**: Go - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-04-16 - **Last Updated**: 2024-04-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 日志包Logrus学习 ## 一、说明 ```go 【1】官方文档 https://gitcode.com/sirupsen/logrus/overview?utm_source=csdn_github_accelerator 【2】需要引入的包 //需要引入包 go get -u github.com/sirupsen/logrus 【3】说明 sirupsen/logrus: Logrus 是一个流行的Go语言日志库,提供了结构化日志记录功能,支持多种输出格式(JSON、文本等),并可通过插件系统扩展更多特性。它被广泛应用于各类Go项目中,以实现灵活且可定制的日志管理。 【4】参考地址 https://blog.csdn.net/xiaobo5264063/article/details/120711908 【5】视频及视频笔记地址 https://www.bilibili.com/video/BV1kV4y1A7B6?p=4&spm_id_from=pageDriver&vd_source=929ab5959c31eb557825b1d8147138cb https://docs.fengfengzhidao.com/#/docs/logrus%E6%96%87%E6%A1%A3/3.%E6%97%A5%E5%BF%97%E5%88%86%E5%89%B2 ``` ## 二、logrus 的级别 ### 1、日志的使用 ```go //------------------日志的级别----------------------------------------- //错误日志级别最高 logrus.Error("我是error错误级别") //警告级别 logrus.Warnln("我是Warnln警告级别") //消息级别,默认的级别 logrus.Info("我是info") //debug级别 logrus.Debug("我是debug级别") //输出级别,默认也是info logrus.Println("我是输出") ``` ### 2、获取日志的级别 ```go //------------获取日志的级别----------------------------- fmt.Println(logrus.GetLevel()) ``` ### 3、设置日志的级别 ```go //----------------设置日志的级别---------------------------- logrus.SetLevel(logrus.DebugLevel) 一般跟开发环境配合使用 ``` ## 三、设置特定字段 ### 1、设定标准输出的字段 ```go //------------------WithField进行设定输出的信息----------------------- //设置特定的字段,一般与请求结合使用 log := logrus.WithField("project", "study") log.Error("你好,输出的是项目的信息") log.WithField("请求体", "/user/id") //输出内容为: //time="2024-04-03T09:43:12+08:00" level=error msg="你好,输出的是项目的信息" project=study ``` ### 2、设定多个标准输出的字段 ```go //------------------WithFields进行设定输出的信息----------------------- log1 := logrus.WithFields(logrus.Fields{ "host": "127.0.0.1", "post": 8080, }) //输出Warnln警告级别的内容 log1.Warnln("你好,我是输出的请求") //输出内容为 //time="2024-04-03T09:43:12+08:00" level=warning msg="你好,我是输出的请求" host=127.0.0.1 post=8080 ``` ### 3、特定字段使用说明 ```go 通常在一个应用中、或者应用的一部分,都有一些固定的fied. 比如在处理用户http请求时,上下文中,所有的日志都会有request_id和user_id,为了了避免每次记录日志都要使用 logrus.WithFields(logrus.Fields{ "request_id": user_id, "user_id": user_id, }) 我们可以创建一个logrus_Entry实例,为这个实例设置默认的fields,在上下文中使用这个logrus.Entry实例记录日志即可 ``` ## 四、显示样式(text可以设置颜色) ### 1、设置显示样式text/json ```go //-------通过SetFormatter设置以json字符串的方式输出------------------------------------- package main import "github.com/sirupsen/logrus" func main() { //设置输出的格式 //logrus.SetFormatter(&logrus.TextFormatter{}) //默认时text格式输出 logrus.SetFormatter(&logrus.JSONFormatter{}) //设置输出的公共信息 logrus.WithFields(logrus.Fields{ "host": "127.0.0.1", "post": 8080, }) logrus.Info("我想输出的信息") } //输出内容 //{"level":"info","msg":"我想输出的信息","time":"2024-04-03T10:01:29+08:00"} ``` ### 2、log日志在控制台输出颜色 ```go //text才可以设置颜色【默认就是TextFormatter】 也就是必须得将SetFormatter(&logrus.TextFormatter{}) //-------------------------------------------------------------------- func main() { //设置初始化样式 logrus.SetFormatter(&logrus.TextFormatter{ //显示颜色 ForceColors: true, //输出完成的时间戳 FullTimestamp: true, //输出时间戳的格式 TimestampFormat: "2006-01-02 15:04:05", }) //设置输出级别 logrus.SetLevel(logrus.DebugLevel) logrus.Error("我是errr") logrus.Warnln("我输出的颜色为Warnln") logrus.Info("我输出的颜色为Info") logrus.Debug("我输出debug") logrus.Println("我输出Println") } ``` ![](image\输出日期加时间戳.png) ### 3、常用的TextFormatter属性 ```go type TextFormatter struct { // 是否强制颜色输出 ForceColors bool //是否禁用颜色输出 DisableColors bool // 是否引用所有值 ForceQuote bool // 是否禁用所有值 DisableQuote bool // 是否禁用时间戳记录 DisableTimestamp bool // 是否在链接到TTY时输出完成的时间戳 FullTimestamp bool // 输出完成的时间戳格式 TimestampFormat string } ``` ## 五、设置输出的时候的颜色 ### 1、go语言控制台输出颜色 ```go package main import "fmt" func main() { //设置字体颜色-------30m开始------------------------------- fmt.Println("\033[30m 黑色 \033[0m") fmt.Println("\033[31m 红色 \033[0m") fmt.Println("\033[32m 绿色 \033[0m") fmt.Println("\033[33m 黄色 \033[0m") fmt.Println("\033[34m 蓝色 \033[0m") fmt.Println("\033[35m 紫色 \033[0m") fmt.Println("\033[36m 青色 \033[0m") fmt.Println("\033[37m 灰色 \033[0m") //设置背景颜色-------40m开始------------------------------- fmt.Println("\033[40m 黑色 \033[0m") fmt.Println("\033[41m 红色 \033[0m") fmt.Println("\033[42m 绿色 \033[0m") fmt.Println("\033[43m 黄色 \033[0m") fmt.Println("\033[44m 蓝色 \033[0m") fmt.Println("\033[45m 紫色 \033[0m") fmt.Println("\033[46m 青色 \033[0m") fmt.Println("\033[47m 灰色 \033[0m") } ``` ![](image\3、颜色格式.png) ### 2、封装后设置输出颜色 ```go package main import "fmt" const ( cBlack = 0 //黑色 cRed = 1 //红色 cGreen2 = 2 //绿色 cYellow = 3 //黄色 cBlue = 4 //蓝色 cPurple = 5 //紫色 cCya = 6 //青色 cGrey = 7 //灰色 ) func GetColorPrint(color int, msg string, isbackground bool) { if isbackground { //是背景y fmt.Printf("\033[4%dm %s \033[0m", color, msg) return } fmt.Printf("\033[3%dm %s \033[0m", color, msg) } func main() { GetColorPrint(cGreen2, "你好", false) } ``` ## 六、输出到文件目录上 ### 1、输出到文件 ```go //设置需要输出的文件的路径及文件名称 file,_ := os.OpenFile("log/logs.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 8666) //把内容输出到文件中 logrus.SetOutput(file) //输出到文件 logrus.Warnln("我不想说话,只是用来进行写日志") ``` ### 2、输出的方法 ```go //正常输出 logrus.Error("Error的日志输出到文件") //正常输出加换行符号\n logrus.Errorln("Errorln的日志输出到文件") //格式化输出 logrus.Errorf("Errorf的日志输出到文件,%s", "格式化输出") ``` ### 3、同时输出到文件和屏幕 ```go //设置要输出的文件 file, _ := os.OpenFile("log/logs.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 8666) //设置输出到文件和控制台 //输出到控制台os.Stdout logrus.SetOutput(io.MultiWriter(file,os.Stdout)) logrus.Error("Error的日志输出到文件") logrus.Errorln("Errorln的日志输出到文件") logrus.Errorf("Errorf的日志输出到文件,%s", "格式化输出") } ``` ## 七、自定义样式输出 ### 1、自定义样式输出 ```go package main import ( "bytes" "fmt" "github.com/sirupsen/logrus" "io" "os" "path" ) const ( ccBlack = 0 //黑色 ccRed = 1 //红色 ccGreen = 2 //绿色 ccYellow = 3 //黄色 ccBlue = 4 //蓝色 ccPurple = 5 //紫色 ccCya = 6 //青色 ccGrey = 7 //灰色 ) type MyEntry struct { Prefix string } func SetFile(path string) (writers []io.Writer) { file, _ := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 8666) writers = []io.Writer{ //输出到文件 file, //输出到控制台 os.Stdout, } return writers } func (m MyEntry) Format(entry *logrus.Entry) ([]byte, error) { //设置颜色 var color int switch entry.Level { case logrus.ErrorLevel: color = ccRed case logrus.WarnLevel: color = ccYellow case logrus.InfoLevel: color = ccBlue case logrus.DebugLevel: color = ccGreen default: color = ccGrey } //设置Buffer缓冲区 var b *bytes.Buffer if entry.Buffer == nil { b = &bytes.Buffer{} } else { b = entry.Buffer } //时间格式化 fmtTime := entry.Time.Format("2006-01-02 15:04:05") //文件的行号 fileval := fmt.Sprintf("%s:%d", path.Base(entry.Caller.File), entry.Caller.Line) //设置格式 fmt.Fprintf(b, "\033[3%dm [%s] \033[0m [%s]-[%s]-[%s]-[%s] \n", color, entry.Level, m.Prefix, fileval, fmtTime, entry.Message) return b.Bytes(), nil } func main() { //设置开启行号 logrus.SetReportCaller(true) //设置日志的级别 logrus.SetLevel(logrus.DebugLevel) logrus.SetFormatter(&MyEntry{ Prefix: "gin", }) //设置文件输出路径 writers := SetFile("log/logs.log") logrus.SetOutput(io.MultiWriter(writers...)) logrus.Error("你好error") logrus.Warnln("你好Warnln") logrus.Info("你好info") logrus.Debug("你好Debug") } ``` ### 2、显示行号 ```go //显示行号必须要设置 logrus.SetReportCaller(true) //文件的行号 fileval := fmt.Sprintf("%s:%d:%s", path.Base(entry.Caller.File), entry.Caller.Line, entry.Caller.Function) //【说明】 //获取文件名 path.Base(entry.Caller.File) //获取行号 entry.Caller.Line //获取函数名 entry.Caller.Function ``` ## 八、Hook可扩展机制 ### 1、Hook接口 ```go //logrus在进行记录levels返回的日志级别消息会触发Hook //按照Fire定义的内容修改logrus.entry type Hook interface { //设置过滤等级的函数 Levels() []Level //设置相关的信息函数 Fire(*Entry) error } ``` ### 2、Hook的调用方式 ```go package main import ( "fmt" "github.com/sirupsen/logrus" ) type MyHook struct { } func (hook MyHook) Levels() []logrus.Level { return logrus.AllLevels } func (hook MyHook) Fire(entry *logrus.Entry) error { //添加输出的内容 entry.Data["app"] = "小陈" fmt.Println(entry) return nil } func main() { logrus.SetLevel(logrus.DebugLevel) logrus.AddHook(&MyHook{}) logrus.Error("你好") logrus.Warnln("你好") logrus.Info("你好") logrus.Debug("你好") } ``` ### 3、error日志独立输出 ```go package main import ( "fmt" "github.com/sirupsen/logrus" "os" ) type MyHook struct { } func (hook MyHook) Levels() []logrus.Level { //设置过滤的级别 return []logrus.Level{logrus.ErrorLevel} } func (hook MyHook) Fire(entry *logrus.Entry) error { fmt.Println(entry.Level) entry.Data["app"] = "小陈" //设置输出文件 file, _ := os.OpenFile("log/err.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) //设置输出的内容 line, _ := entry.String() //将erro内容进行输出到文件 file.Write([]byte(line)) return nil } func main() { logrus.SetLevel(logrus.DebugLevel) logrus.AddHook(&MyHook{}) logrus.Error("错误信息") logrus.Warnln("警告信息") } ``` ## 九、日志分割功能 ### 1、按时间进行分割--Writer ```go package main import ( "errors" "fmt" "io" "os" "path/filepath" "strings" "time" log "github.com/sirupsen/logrus" ) // LogFormatter 日志自定义格式 type LogFormatter struct{} // Format 格式详情 func (s *LogFormatter) Format(entry *log.Entry) ([]byte, error) { //日期格式化 timestamp := time.Now().Local().Format("2006-01-02 15:04:05") var file string var len int //日志的相关信息 if entry.Caller != nil { file = filepath.Base(entry.Caller.File) len = entry.Caller.Line } //fmt.Println(entry.Data) //设置输出的消息体 msg := fmt.Sprintf("[%s] %s [%s:%d] %s\n", strings.ToUpper(entry.Level.String()), timestamp, file, len, entry.Message) return []byte(msg), nil } /* * 输出文件的结构体 */ type logFileWriter struct { file *os.File //文件 logPath string //路径 fileDate string //判断日期切换目录 appName string //可以理解为模块名称 } func (p *logFileWriter) Write(data []byte) (n int, err error) { if p == nil { return 0, errors.New("logFileWriter is nil") } if p.file == nil { return 0, errors.New("file not opened") } fileDate := time.Now().Format("2006-01-02") //判断是否需要切换日期 if p.fileDate != fileDate { p.file.Close() err = os.MkdirAll(fmt.Sprintf("%s/%s", p.logPath, fileDate), os.ModePerm) if err != nil { return 0, err } filename := fmt.Sprintf("%s/%s/%s-%s.log", p.logPath, fileDate, p.appName, fileDate) p.file, err = os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600) if err != nil { return 0, err } } n, e := p.file.Write(data) return n, e } // InitLog 初始化日志 func InitLog(logPath string, appName string) { fileDate := time.Now().Format("2006-01-02") //创建目录 err := os.MkdirAll(fmt.Sprintf("%s/%s", logPath, fileDate), os.ModePerm) if err != nil { log.Error(err) return } filename := fmt.Sprintf("%s/%s/%s-%s.log", logPath, fileDate, appName, fileDate) file, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600) if err != nil { log.Error(err) return } fileWriter := logFileWriter{file, logPath, fileDate, appName} //设置输出到控制台 //log.SetOutput(os.Stdout) writers := []io.Writer{ &fileWriter, os.Stdout} //同时写文件和屏幕 fileAndStdoutWriter := io.MultiWriter(writers...) if err == nil { log.SetOutput(fileAndStdoutWriter) } else { log.Info("failed to log to file.") } log.SetReportCaller(true) log.SetFormatter(new(LogFormatter)) } func main() { InitLog("log", "gin") log.Error("这是不对的") } ``` ### 2、按日志等级分割 --hook ```go package main import ( "fmt" "github.com/sirupsen/logrus" "os" ) //定义类型 const ( allLog = "all" errLog = "err" warnLog = "warn" infoLog = "info" ) //实现HOOK接口的结构体 type FileLevelHook struct { file *os.File errFile *os.File warnFile *os.File infoFile *os.File logPath string } //过滤日志等级的接口 func (hook FileLevelHook) Levels() []logrus.Level { return logrus.AllLevels } //根据日志等级进行判断数据的输出位置 func (hook FileLevelHook) Fire(entry *logrus.Entry) error { line, _ := entry.String() switch entry.Level { case logrus.ErrorLevel: hook.errFile.Write([]byte(line)) case logrus.WarnLevel: hook.warnFile.Write([]byte(line)) case logrus.InfoLevel: hook.infoFile.Write([]byte(line)) } hook.file.Write([]byte(line)) return nil } func InitLevel(logPath string) { err := os.MkdirAll(fmt.Sprintf("%s", logPath), os.ModePerm) if err != nil { logrus.Error(err) return } allFile, err := os.OpenFile(fmt.Sprintf("%s/%s.log", logPath, allLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600) errFile, err := os.OpenFile(fmt.Sprintf("%s/%s.log", logPath, errLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600) warnFile, err := os.OpenFile(fmt.Sprintf("%s/%s.log", logPath, warnLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600) infoFile, err := os.OpenFile(fmt.Sprintf("%s/%s.log", logPath, infoLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600) fileHook := FileLevelHook{allFile, errFile, warnFile, infoFile, logPath} logrus.AddHook(&fileHook) } func main() { InitLevel("log/log_level") logrus.Errorln("你好") logrus.Errorln("err") logrus.Warnln("warn") logrus.Infof("info") logrus.Println("print") } ``` ## 十、Gin集成日志包 ### 1、主main函数 ```go package main import ( "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "my_logrus_study/Gin_Integration_Logrus" ) func main() { //进行调用log初始化 Gin_Integration_Logrus.InitFile("Gin_Integration_Logrus/log", "server") //进行创建路由 router := gin.New() //进行注册自定义函数 router.Use(Gin_Integration_Logrus.LogMiddleware()) router.GET("/", func(c *gin.Context) { logrus.Info("来了") c.JSON(200, gin.H{"msg": "你好"}) }) router.Run(":8081") } ``` ### 2、Log日志的初始化 ```go package Gin_Integration_Logrus import ( "bytes" "fmt" "github.com/sirupsen/logrus" "os" "time" ) type FileDateHook struct { file *os.File logPath string fileDate string //判断日期切换目录 appName string } func (hook FileDateHook) Levels() []logrus.Level { return logrus.AllLevels } func (hook FileDateHook) Fire(entry *logrus.Entry) error { timer := entry.Time.Format("2006-01-02_15-04") line, _ := entry.String() if hook.fileDate == timer { hook.file.Write([]byte(line)) return nil } // 时间不等 hook.file.Close() os.MkdirAll(fmt.Sprintf("%s/%s", hook.logPath, timer), os.ModePerm) filename := fmt.Sprintf("%s/%s/%s.log", hook.logPath, timer, hook.appName) hook.file, _ = os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600) hook.fileDate = timer hook.file.Write([]byte(line)) return nil } type MyFormatter struct { } func (f MyFormatter) Format(entry *logrus.Entry) ([]byte, error) { // 设置buffer 缓冲区 var b *bytes.Buffer if entry.Buffer == nil { b = &bytes.Buffer{} } else { b = entry.Buffer } // 设置格式 fmt.Fprintf(b, "%s\n", entry.Message) return b.Bytes(), nil } func InitFile(logPath, appName string) { logrus.SetFormatter(&MyFormatter{}) fileDate := time.Now().Format("2006-01-02_15-04") //创建目录 err := os.MkdirAll(fmt.Sprintf("%s/%s", logPath, fileDate), os.ModePerm) if err != nil { logrus.Error(err) return } filename := fmt.Sprintf("%s/%s/%s.log", logPath, fileDate, appName) file, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600) if err != nil { logrus.Error(err) return } fileHook := FileDateHook{file, logPath, fileDate, appName} logrus.AddHook(&fileHook) } ``` ### 3、Gin框架注册函数 ```go package Gin_Integration_Logrus import ( "fmt" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "time" ) const ( status200 = 42 status404 = 43 status500 = 41 methodGET = 44 ) func LogMiddleware() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path raw := c.Request.URL.RawQuery // Process request c.Next() // Log only when path is not being skipped // Stop timer end := time.Now() timeSub := end.Sub(start) clientIP := c.ClientIP() method := c.Request.Method statusCode := c.Writer.Status() //bodySize := c.Writer.Size() if raw != "" { path = path + "?" + raw } var statusColor string switch statusCode { case 200: statusColor = fmt.Sprintf("\033[%dm %d \033[0m", status200, statusCode) case 404: statusColor = fmt.Sprintf("\033[%dm %d \033[0m", status404, statusCode) } var methodColor string switch method { case "GET": methodColor = fmt.Sprintf("\033[%dm %s \033[0m", methodGET, method) } logrus.Infof("[GIN] %s |%s| %d | %s | %s | %s", start.Format("2006-01-02 15:04:06"), statusColor, timeSub, clientIP, methodColor, path, ) } } ```