当前位置: 首页 > article >正文

Go开源日志库Logrus的使用

一、Logrus简介

Logrus 是一个流行的 Go 语言日志库,以其功能强大、性能高效和高度灵活性而闻名。有关更多介绍可查看 Logrus。

主要特点
  • 丰富的日志级别:Logrus 支持多种日志级别,包括 Debug、Info、Warn、Error、Fatal 和 Panic,以及更细粒度的 Trace 级别。这些级别可以帮助开发者根据日志的严重程度进行筛选和处理。
  • 多种输出格式:Logrus 支持文本(TextFormatter)和 JSON(JSONFormatter)两种内置的日志格式,并且允许用户通过实现 Formatter 接口来自定义日志格式。
  • 结构化日志记录:Logrus 的 Field 机制允许用户为日志添加自定义字段,这些字段将作为日志消息的一部分被记录,使得日志信息更加结构化和易于查询。
  • 可扩展的钩子机制:Logrus 提供了钩子(hook)机制,允许用户通过编写自定义的 hook 来扩展日志的功能,例如将日志发送到远程服务器、写入文件等。
  • 预设日志字段:Logrus 的 Default Fields 机制可以给一部分或全部日志统一添加共同的日志字段,如请求ID、用户IP等。

二、Logrus基本用法

1、安装logrus包

go get github.com/sirupsen/logrus

2、引入logrus包

import "github.com/sirupsen/logrus"

3、设置日志级别

logrus.SetLevel(log.DebugLevel)

4、设置日志格式化器

logrus.SetFormatter(&logrus.TextFormatter{
	FullTimestamp:   true,                  // 完整时间
	TimestampFormat: "2006-01-02 15:04:05", // 时间格式
	ForceColors:     true,                  //显示颜色
})

5、设置日志输出类型

// 创建日志文件
file, _ := os.OpenFile("logs/application.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)

// 设置日志输出到文件
// logrus.SetOutput(file)

// 日志输出到文件和控制台
logrus.SetOutput(io.MultiWriter(file, os.Stdout))

// 输出到控制台
// logrus.SetOutput(os.Stdout)

6、记录日志

logrus.WithField("appName", "测试logrus").Debug("这是一条Debug日志")
logrus.WithField("appName", "测试logrus").Info("这是一条Info日志")
logrus.WithFields(logrus.Fields{
	"appName": "测试logrus",
	"appId":   101,
}).Info("这是一条Info日志")

效果示例:

三、Logrus进阶用法 

1、显示行号

// 显示行号
logrus.SetReportCaller(true)

效果演示: 

 2、hook机制

在 logrus 中,钩子(Hooks)是一种在日志条目(log entry)被处理之前或之后执行自定义逻辑的机制。你可以使用钩子来执行诸如将日志发送到外部服务(如 Sentry、Splunk 等)、修改日志消息、添加额外的日志上下文等任务。

使用方法:

  • 定义hook

实现logrus.Hook接口,其接口定义为:

type Hook interface {
	Levels() []Level
	Fire(*Entry) error
}
  • 注册hook
logrus.AddHook()

 完整代码:

package main

import (
	"os"

	"github.com/sirupsen/logrus"
)

// 自定义hook
type simpleHook struct {
}

// 实现logrus.Hook接口
func (h *simpleHook) Levels() []logrus.Level {
	// 只有日志级别为 ErrorLevel 的日志执行 Fire 中定义的操作
	return []logrus.Level{logrus.ErrorLevel}
}

func (h *simpleHook) Fire(entry *logrus.Entry) error {
	// 在日志条目被处理时执行的逻辑
	entry.Data["appName"] = "test"
	// 将错误级别的日志添加单独的错误文件中
	file, _ := os.OpenFile("logs/error.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	defer file.Close()

	line, _ := entry.String()
	file.Write([]byte(line))

	return nil
}

func main() {
	// 注册hook
	logrus.AddHook(&simpleHook{})

	logrus.Info("测试钩子")
	// 只有 error 级别的日志才显示 appName = test
	logrus.Error("测试钩子---错误信息")
}

效果演示: 

 错误信息被单独写入logs/error.log文件中,如下:

3、按时间分割日志

Logrus本身不支持日志轮转切割功能,需要配合 file-rotatelogs 包来实现。

  • 下载 file-rotatelogs 包
go get github.com/lestrrat-go/file-rotatelogs
  • 新建 RotateLogs(实现了 io.Writer 的 Write 方法)
// 创建一个 writer
logWriter, err := rotatelogs.New(
	filepath.Join("logs", "syslog_%Y%m%d%H%M%S.log"), //日志路径
	rotatelogs.WithLinkName(filepath.Join("logs", "syslog.log")),
	rotatelogs.WithMaxAge(7*24*time.Hour),       // 最大保留天数:7天
	rotatelogs.WithRotationTime(10*time.Second), // 日志分割时间:1分钟
)
if err != nil {
	panic(err)
}
  • 新建 NewHook()
// 新建Hook,将 otatelogs作为 writer
hook := lfshook.NewHook(logWriter,
	&logrus.TextFormatter{
		TimestampFormat: "2006-01-02 15:04:05",
		FullTimestamp:   true,
	},
)
  • 注册 Hook
// 注册 hook
logger.AddHook(hook)

完整代码:

package main

import (
	"io"
	"path/filepath"
	"time"

	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
)

func main() {
	// 创建一个 writer
	logWriter, err := rotatelogs.New(
		filepath.Join("logs", "syslog_%Y%m%d%H%M%S.log"), //日志路径
		rotatelogs.WithLinkName(filepath.Join("logs", "syslog.log")),
		rotatelogs.WithMaxAge(7*24*time.Hour),       // 最大保留天数:7天
		rotatelogs.WithRotationTime(10*time.Second), // 日志分割时间:10秒
	)
	if err != nil {
		panic(err)
	}

	// 新建Hook,将 otatelogs作为 writer
	hook := lfshook.NewHook(logWriter,
		&logrus.TextFormatter{
			TimestampFormat: "2006-01-02 15:04:05",
			FullTimestamp:   true,
		},
	)

	// 创建一个 logger
	logger := logrus.New()
	logger.SetReportCaller(true)
	logger.SetOutput(io.Discard)

	// 注册 hook
	logger.AddHook(hook)

	// 记录日志
	for i := 0; i < 10; i++ {
		logger.Info("Hello world!!")
		time.Sleep(3 * time.Second)
	}
}

 效果示例:

4、按日志级别分割日志

按日志级别分割日志,可以将错误信息单独写入一个文件。

方法为:新建hook时,将不同日志级别匹配到不同的writer,如下:

// 新建Hook,按日志级别匹配 writer
hook := lfshook.NewHook(
	lfshook.WriterMap{
		logrus.DebugLevel: logWriter,
		logrus.InfoLevel:  logWriter,
		logrus.WarnLevel:  logWriter,
		logrus.ErrorLevel: errorWriter,
	},
	&logrus.TextFormatter{
		TimestampFormat: "2006-01-02 15:04:05",
	},
)

完整代码:

package main

import (
	"io"
	"path/filepath"
	"time"

	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
)

func main() {
	// 创建一个 writer
	logWriter, err := rotatelogs.New(
		filepath.Join("logs", "syslog_%Y%m%d%H%M%S.log"), //日志路径
		rotatelogs.WithLinkName(filepath.Join("logs", "syslog.log")),
		rotatelogs.WithMaxAge(7*24*time.Hour),       // 最大保留天数:7天
		rotatelogs.WithRotationTime(10*time.Second), // 日志分割时间:10s
	)
	if err != nil {
		panic(err)
	}

	// 创建一个 Error 级别的 writer
	errorWriter, err := rotatelogs.New(
		filepath.Join("logs", "sysError_%Y%m%d%H%M%S.log"), //日志路径
		rotatelogs.WithLinkName(filepath.Join("logs", "sysError.log")),
		rotatelogs.WithMaxAge(7*24*time.Hour),       // 最大保留天数:7天
		rotatelogs.WithRotationTime(10*time.Second), // 日志分割时间:1分钟
	)
	if err != nil {
		panic(err)
	}

	// 新建Hook,按日志级别匹配 writer
	hook := lfshook.NewHook(
		lfshook.WriterMap{
			logrus.DebugLevel: logWriter,
			logrus.InfoLevel:  logWriter,
			logrus.WarnLevel:  logWriter,
			logrus.ErrorLevel: errorWriter,
		},
		&logrus.TextFormatter{
			TimestampFormat: "2006-01-02 15:04:05",
		},
	)

	// 创建一个 logger
	logger := logrus.New()
	logger.SetReportCaller(true)
	logger.SetOutput(io.Discard)

	// 注册 hook
	logger.AddHook(hook)

	// 记录日志
	for i := 0; i < 10; i++ {
		logger.Info("Hello world!!")
		logger.Error("这是报错信息")
		time.Sleep(3 * time.Second)
	}
}

 效果示例:

 


http://www.kler.cn/a/300996.html

相关文章:

  • Franka例程学习——force_control
  • Go语言中http.Transport的Keep-Alive配置与性能优化方法
  • 【微服务justsoso-cloud系列】目录
  • linux通过web向mac远程传输字符串,mac收到后在终端中直接打印。
  • C++并发编程之std::async的异常安全性
  • 网络网络层ICMP协议
  • netty和websocket的区别
  • 重拾精髓:go doc -http让离线包文档浏览更便捷
  • Unity射击游戏开发教程:(35)轰炸敌人
  • 解决Metasploit调用Nessus报错问题
  • 基于Springboot美食推荐小程序的设计与实现(源码+数据库+文档)
  • 【Kubernetes】常见面试题汇总(九)
  • 基于JavaWeb开发的Java+jquery+SpringMVC校园网站平台设计和实现
  • 专升本-英语笔记.1
  • 【Antd】Form.List的强大之处,Form.List使用方式细微讲解
  • Shell脚本流程控制(Linux篇)
  • 计算机网络13——IM聊天系统——网络功能实现——UDP
  • 懒人大屏自适应方案
  • 关于man手册不全和设置中文的问题
  • 手把手教你实现一个文件浏览器
  • 文件压缩zip工具
  • vue3的学习
  • 【LeetCode 算法笔记】49. 字母异位词分组
  • EmguCV学习笔记 VB.Net 11.3 DNN其它
  • 特种设备考试真题题库及答案
  • adb有线连接正常,adb connect失败