【go语言开发】loglus日志框架的使用
本文将简单介绍loglus框架的基本使用,并给出demo
文章目录
- 前言
- Loglus常见用法
- 自定义日志级别
- 使用字段钩子
- 输出到多个位置
- 使用钩子实现自定义日志处理
- demo
前言
Logrus 是一个用于 Go 语言的结构化日志框架,它提供了丰富的日志级别、钩子和格式化选项。
环境搭建:
go get github.com/sirupsen/logrus
代码中导入Loglus
import (
"github.com/sirupsen/logrus"
)
Loglus常见用法
自定义日志级别
可以添加一个 TraceLevel 级别来更详细地跟踪程序的执行流程
package main
import (
"github.com/sirupsen/logrus"
)
var TraceLevel = logrus.Level(6)
func main() {
logger := logrus.New()
logger.SetLevel(TraceLevel)
logger.Trace("This is a trace level log")
}
使用字段钩子
使用字段钩子来在日志中添加额外的字段信息。例如,你可以添加一个钩子来记录每条日志的时间戳:
package main
import (
"github.com/sirupsen/logrus"
)
func main() {
logger := logrus.New()
logger.SetFormatter(&logrus.JSONFormatter{})
logger.AddHook(&logrus.FieldHook{
Field: "timestamp",
Func: func() (interface{}, error) {
return time.Now().Format("2006-01-02T15:04:05.999Z07:00"), nil
},
})
logger.Info("This is a log entry with timestamp field")
}
输出到多个位置
可以将日志同时输出到多个位置,比如标准输出和文件。以下是一个示例,将日志同时输出到控制台和文件中:
package main
import (
"os"
"io"
"github.com/sirupsen/logrus"
)
func main() {
logger := logrus.New()
// 设置日志级别和输出格式
// 输出到控制台
logger.SetOutput(os.Stdout)
// 输出到文件
file, err := os.OpenFile("logfile.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err == nil {
mw := io.MultiWriter(os.Stdout, file)
logger.SetOutput(mw)
} else {
logger.Info("Failed to log to file, using default stderr")
}
logger.Info("This log entry will be output to both console and file")
}
使用钩子实现自定义日志处理
使用钩子来实现自定义的日志处理逻辑。例如,你可以添加一个邮件钩子,在产生错误日志时发送邮件通知:
package main
import (
"github.com/sirupsen/logrus"
"net/smtp"
)
func main() {
logger := logrus.New()
// 设置日志级别和输出格式
// 添加邮件钩子
logger.AddHook(&logrus.Hook{
Levels: []logrus.Level{logrus.ErrorLevel, logrus.FatalLevel},
Fire: func(entry *logrus.Entry) error {
sendEmailNotification(entry.Message)
return nil
},
})
logger.Error("An error occurred, email notification will be sent")
}
func sendEmailNotification(message string) {
// 实现发送邮件的逻辑
}
demo
这里给出一个保存日志到项目log文件的示例:
package middleware
import (
"fmt"
"github.com/gin-gonic/gin"
retalog "github.com/lestrrat-go/file-rotatelogs"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
"log"
"math"
"os"
"path"
"time"
)
// SetOutputFile 设置输出文件名称,如果没有就创建
func SetOutputFile() (*os.File, string, error) {
now := time.Now()
logFilePath := ""
if dir, err := os.Getwd(); err == nil {
logFilePath = dir + "/logs"
}
_, err := os.Stat(logFilePath)
if os.IsNotExist(err) {
if err := os.MkdirAll(logFilePath, 0777); err != nil {
log.Println(err.Error())
return nil, "", err
}
}
logFileName := now.Format("2006-01-02") + ".log"
filePath := path.Join(logFilePath, logFileName)
if _, err := os.Stat(filePath); err != nil {
if _, err := os.Create(filePath); err != nil {
log.Println(err.Error())
return nil, "", err
}
}
src, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
fmt.Println("err: ", err)
return nil, "", err
}
log.Println("create log path: ", filePath)
return src, filePath, nil
}
// Logger 日志,此操作可以复用
func Logger() gin.HandlerFunc {
//建立软连接,需要管理员权限
linkName := "latest_log.log"
//设置日志文件的路径
src, filePath, _ := SetOutputFile()
//创建日志
logger := logrus.New()
//输出
logger.Out = src
//设置日志级别
logger.SetLevel(logrus.DebugLevel)
// 显示日志行数
//logger.SetReportCaller(true)
//添加时间分割
logWriter, _ := retalog.New(
filePath,
retalog.WithMaxAge(14*24*time.Hour), //日志保留时间:2周
retalog.WithRotationTime(24*time.Hour), //24小时分割一次
retalog.WithLinkName(linkName), //建立软连接
)
writeMap := lfshook.WriterMap{
logrus.InfoLevel: logWriter,
logrus.FatalLevel: logWriter,
logrus.DebugLevel: logWriter,
logrus.WarnLevel: logWriter,
logrus.ErrorLevel: logWriter,
logrus.PanicLevel: logWriter,
}
//实例化
Hook := lfshook.NewHook(writeMap, &logrus.TextFormatter{
TimestampFormat: "2006-01-02 15:04:05",
})
logger.AddHook(Hook)
return func(c *gin.Context) {
startTime := time.Now()
c.Next()
stopTime := time.Since(startTime)
spendTime := fmt.Sprintf("%d ms", int(math.Ceil(float64(stopTime.Nanoseconds()/1000000.0))))
hostName, err := os.Hostname()
if err != nil {
hostName = "unknown"
}
statusCode := c.Writer.Status()
clientIp := c.ClientIP()
//userAgent := c.Request.UserAgent()
dataSize := c.Writer.Size()
if dataSize < 0 {
dataSize = 0
}
method := c.Request.Method
requestPath := c.Request.RequestURI
entry := logger.WithFields(logrus.Fields{
"HostName": hostName,
"status": statusCode,
"SpendTime": spendTime,
"Ip": clientIp,
"Method": method,
"Path": requestPath,
"DataSize": dataSize,
//"Agent": userAgent, // TODO: UA
})
if len(c.Errors) > 0 {
entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String())
}
if statusCode >= 500 {
entry.Error()
} else if statusCode >= 400 {
entry.Warn()
} else {
entry.Info()
}
}
}
在gin中调用Logger()
r := gin.New()
r.Use(gin.Recovery())
r.Use(middleware.Logger())