logrus概述
简介
- Logrus 是一个流行的 Go 语言日志库,它提供了结构化日志和多种日志级别的功能。Logrus 非常灵活,支持自定义日志格式和输出,被许多 Go 语言项目广泛使用
特点
-
完全兼容
log
标准库:Logrus 可以很容易地替换掉log
标准库,因为它实现了相同的接口 -
结构化日志记录:可以很容易地记录字段数据,这些数据随后可以被其他日志处理系统解析
-
多个日志级别:Logrus 支持多种日志级别,包括:
Panic
、Fatal
、Error
、Warn
、Info
、Debug
和Trace
-
易于集成:Logrus 可以与其他系统如syslog、Hook等集成,便于日志的集中管理和分析
-
高度可定制:可以通过 Hooks 和格式化器来自定义日志的输出格式和内容
下载
go get github.com/sirupsen/logrus
logrus常用方法
logrus.Debugln("Debugln")
logrus.Infoln("Infoln")
logrus.Warnln("Warnln")
logrus.Errorln("Errorln")
logrus.Println("Println")
// 输出如下
time="2024-10-20T16:08:01+08:00" level=info msg=Infoln
time="2024-10-20T16:08:01+08:00" level=warning msg=Warnln
time="2024-10-20T16:08:01+08:00" level=error msg=Errorln
time="2024-10-20T16:08:01+08:00" level=info msg=Println
- debug的没有输出,是因为logrus默认的日志输出等级是 info
日志级别
logrus.PanicLevel
: 记录日志,然后调用 panic()logrus.FatalLevel
: 记录日志,然后调用 os.Exit(1)logrus.ErrorLevel
: 记录错误级别的日志logrus.WarnLevel
: 记录警告级别的日志logrus.InfoLevel
: 记录信息级别的日志logrus.DebugLevel
: 记录调试级别的日志logrus.TraceLevel
: 记录跟踪级别的日志
package main
import (
"os"
"github.com/sirupsen/logrus"
)
func main() {
// 设置日志输出到 os.Stdout
logrus.SetOutput(os.Stdout)
// 设置日志级别为 InfoLevel,这意味着 InfoLevel 及以上级别的日志会被记录
logrus.SetLevel(logrus.InfoLevel)
// 记录不同级别的日志
logrus.Trace("This is a trace message and will not be printed.")
logrus.Debug("This is a debug message and will not be printed.")
logrus.Info("This is an info message and will be printed.")
logrus.Warn("This is a warning message and will be printed.")
logrus.Error("This is an error message and will be printed.")
// 注意:通常不推荐在生产环境中使用 PanicLevel 和 FatalLevel,因为它们会导致程序退出。
// logrus.Panic("This is a panic message and will cause the program to panic.")
// logrus.Fatal("This is a fatal message and will cause the program to exit.")
}
字段
WithField(key string, value interface{}) *Entry
:添加一个字段到日志条目WithFields(fields log.Fields) *Entry
:添加多个字段到日志条目WithError(err error) *Entry
:添加错误字段到日志条目
package main
import (
"os"
"github.com/sirupsen/logrus"
)
func main() {
// 设置日志输出到 os.Stdout
logrus.SetOutput(os.Stdout)
// 设置日志格式为 JSON,这对于结构化日志记录很有用
logrus.SetFormatter(&logrus.JSONFormatter{})
// 使用 WithField 方法添加一个字段
logEntry := logrus.WithField("user", "Alice")
// 使用 WithFields 方法添加多个字段
logEntry = logEntry.WithFields(logrus.Fields{
"operation": "login",
"result": "success",
})
// 记录一条包含字段的日志
logEntry.Info("User logged in successfully")
// 使用 WithError 方法添加一个错误字段
err := fmt.Errorf("something went wrong")
logEntry.WithError(err).Error("An error occurred")
}
输出
日志样式
显示行号
logrus.SetReportCaller(true)
样式设置
- 默认的是以text的形式展示,也可以设置为jsong样式
textLogger := logrus.New()
// 创建一个 TEXT 格式的日志记录器
textLogger.SetFormatter(&logrus.TextFormatter{
DisableColors: false,
FullTimestamp: true,
})
// 创建一个 JSON 格式的日志记录器
jsonLogger := logrus.New()
jsonLogger.SetFormatter(&logrus.JSONFormatter{})
输出地址
-
SetOutput(io.Writer)
:设置日志的输出目的地 -
SetFormatter(formatter Formatter)
:设置日志的格式化器
package main
import (
"os"
"github.com/sirupsen/logrus"
)
func main() {
// 创建一个新的 Logrus 实例
log := logrus.New()
// 输出到 os.Stdout
log.SetOutput(os.Stdout)
// 输出到文件
file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err == nil {
log.SetOutput(file)
} else {
log.Fatalf("Failed to log to file, using default stderr: %v", err)
}
// 输出到自定义 io.Writer,例如 bytes.Buffer
var buffer bytes.Buffer
log.SetOutput(&buffer)
// 记录一些日志
log.Info("This is an info message")
log.Warn("This is a warning message")
log.Error("This is an error message")
// 如果输出到 bytes.Buffer,你可以获取日志内容
logBytes := buffer.Bytes()
os.Stdout.Write(logBytes) // 将 buffer 中的内容输出到 os.Stdout
}
日志颜色
默认颜色
-
DebugLevel: 蓝色
-
InfoLevel: 绿色
-
WarningLevel: 黄色
-
ErrorLevel: 红色
-
FatalLevel: 红色(通常伴随有其他指示,比如退出程序)
-
PanicLevel: 红色(通常伴随有 panic)
禁用颜色
log.SetFormatter(&logrus.TextFormatter{
DisableColors: true,
})
自定义颜色
- 创建一个新的
TextFormatter
结构体 - 重写
Format
方法,在格式化日志时添加自定义颜色代码 - 将自定义的
Formatter
设置给 Logrus 实例
package main
import (
"bytes"
"fmt"
"github.com/sirupsen/logrus"
"os"
)
// CustomFormatter 自定义格式化器
type CustomFormatter struct {
logrus.TextFormatter
}
// Format 实现 logrus.Formatter 接口
func (f *CustomFormatter) Format(entry *logrus.Entry) ([]byte, error) {
var b *bytes.Buffer
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
// 添加自定义颜色代码
color := ""
switch entry.Level {
case logrus.DebugLevel:
color = "\x1b[34m" // 蓝色
case logrus.InfoLevel:
color = "\x1b[32m" // 绿色
case logrus.WarnLevel:
color = "\x1b[33m" // 黄色
case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
color = "\x1b[31m" // 红色
}
// 写入颜色代码和日志内容
fmt.Fprintf(b, "%s%s\x1b[0m\n", color, entry.Message)
return b.Bytes(), nil
}
func main() {
log := logrus.New()
log.SetFormatter(&CustomFormatter{
TextFormatter: logrus.TextFormatter{
DisableColors: false,
FullTimestamp: true,
},
})
log.Debug("This is a debug message")
log.Info("This is an info message")
log.Warn("This is a warning message")
log.Error("This is an error message")
}
自定义格式
- 通过实现
logrus.Formatter
接口来自定义日志格式
package main
import (
"bytes"
"fmt"
"time"
"github.com/sirupsen/logrus"
)
// MyFormatter 自定义格式化器
type MyFormatter struct {
}
// Format 实现了 logrus.Formatter 接口
func (f *MyFormatter) Format(entry *logrus.Entry) ([]byte, error) {
b := &bytes.Buffer{}
// 自定义时间格式
timestamp := time.Now().Format(time.RFC3339)
fmt.Fprintf(b, "[%s] ", timestamp)
// 自定义日志级别
level := entry.Level.String()
fmt.Fprintf(b, "[%s] ", level)
// 自定义消息格式
message := entry.Message
fmt.Fprintf(b, "%s ", message)
// 添加字段
for key, value := range entry.Data {
fmt.Fprintf(b, "%s=%v ", key, value)
}
// 添加换行符
b.WriteByte('\n')
return b.Bytes(), nil
}
func main() {
log := logrus.New()
// 设置自定义格式化器
log.SetFormatter(&MyFormatter{})
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
}
MyFormatter
结构体实现了Format
方法,该方法接收一个logrus.Entry
对象,该对象包含了日志条目的所有信息,包括时间戳、日志级别、消息和字段。Format
方法将这些信息格式化为一个字符串,并返回字节数组。
[2024-10-20T17:14:22+08:00] [info] A group of walrus emerges from the ocean size=10 animal=walrus
Hook
-
在 Logrus 中,
Hook
是一个接口,允许你添加自定义的逻辑,这些逻辑会在日志记录之前或之后执行。通过实现logrus.Hook
接口,你可以创建自己的钩子来执行额外的操作,比如发送日志到远程系统、写入数据库、执行特定的监控检查等。 -
在 Logrus 中,
Hook
的基本用法涉及以下步骤:
- 定义一个 Hook 结构体:这个结构体需要实现
Levels()
和Fire(entry *logrus.Entry) error
方法。 - 实现
Levels()
方法:这个方法返回一个logrus.Level
切片,表示该 Hook 将被哪些日志级别触发。 - 实现
Fire(entry \*logrus.Entry) error
方法:这个方法定义了当日志被记录时应该执行的逻辑。 - 将 Hook 添加到 Logrus 实例:使用
log.AddHook(hook)
方法。
- 自定义
Hook
示例,它会在每次记录日志时打印出当前的函数名和文件名:
package main
import (
"fmt"
"runtime"
"github.com/sirupsen/logrus"
)
// MyHook 是一个自定义的 Logrus 钩子
type MyHook struct {
}
// Levels 定义了这个钩子会被哪些日志级别触发
func (hook *MyHook) Levels() []logrus.Level {
return logrus.AllLevels
}
// Fire 是每次日志记录时都会调用的方法
func (hook *MyHook) Fire(entry *logrus.Entry) error {
// 获取调用者的函数名和文件名
pc, file, line, ok := runtime.Caller(8) // 8 是调用栈的深度,可能需要根据你的代码结构进行调整
if !ok {
fmt.Println("Could not get caller info")
return nil
}
function := runtime.FuncForPC(pc).Name()
fmt.Printf("Caller: %s:%d %s\n", file, line, function)
return nil
}
func main() {
log := logrus.New()
// 添加自定义钩子
log.AddHook(&MyHook{})
log.Info("This is an informational message")
log.Warn("This is a warning message")
}
-
在上面的代码中,
MyHook
结构体实现了Levels
和Fire
方法。Levels
方法返回一个日志级别切片,表示这个钩子会对哪些级别的日志进行响应。在这个例子中,我们使用logrus.AllLevels
,这意味着它会对所有级别的日志做出响应。
Fire
方法会在每次记录日志时被调用。在这个方法中,我们使用runtime.Caller
来获取调用日志记录函数的函数名和文件名,并打印出来。
在main
函数中,我们创建了一个 Logrus 实例,并使用AddHook
方法将自定义的MyHook
添加到 Logrus 中。之后,当我们记录日志时,MyHook
的Fire
方法会被调用,并打印出调用日志的函数名和文件名。 -
代码输出:
Caller: D:/goproject/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.2.windows-amd64/src/runtime/proc.go:272 runtime.main
time="2024-10-20T17:19:37+08:00" level=info msg="This is an informational message"
time="2024-10-20T17:19:37+08:00" level=warning msg="This is a warning message"
Caller: D:/goproject/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.2.windows-amd64/src/runtime/proc.go:272 runtime.main