介绍 logrus

它是一个结构化、插件化的日志记录库。完全兼容 golang 标准库中的日志模块。它还内置了 2 种日志输出格式 JSONFormatter 和 TextFormatter,来定义输出的日志格式。

github地址:https://github.com/sirupsen/logrus

logrus 使用

使用的版本:logrus v1.8.1

1. 开始使用

package main

import (
log "github.com/sirupsen/logrus"
) func main() {
log.WithFields(log.Fields{
"animal": "walrus",
}).Info("a walrus appears")
}

运行输出:

time="2021-11-11T17:41:48+08:00" level=info msg="a walrus appears" animal=walrus

2. 设置日志格式,日志级别,输出方式

设置日志格式

1)内置日志格式

log Formatter,logrus内置的formatter有 2 种,logrus.TextFormatter 和 logrus.JSONFormatter

  • logrus.JSONFormatter{}, 设置为 json 格式,所有设置选项在 logrus.JSONFormatter

    log.SetFormatter(&log.JSONFormatter{
    TimestampFormat: "2006-01-02 15:04:05", // 设置json里的日期输出格式
    }) log.SetFormatter(&log.JSONFormatter{}) // 设置为json格式
  • logrus.TextFormatter{},设置为文本格式,所有的设置选项在 logrus.TextFormatter

    log.SetFormatter(&log.TextFormatter{
    TimestampFormat: "2006-01-02 15:04:05",
    ForceColors: true,
    EnvironmentOverrideColors: true,
    // FullTimestamp:true,
    // DisableLevelTruncation:true,
    })

2)自定义日志格式

可以根据 Formatter 接口自定义日志格式,里面有一个 Format 方法,这个 Format 方法里有一个struct类型数据 *Entry, Entry.Data 是所有字段集合,Fields 类型为 map[string]interface{}。

比如:entry.Data["msg"],entry.Data["time"]`. The timestamp

package main

import (
"fmt" jsoniter "github.com/json-iterator/go"
log "github.com/sirupsen/logrus"
) type MyJSONFormatter struct {
JSONPrefix string
Otherdata string
} func (my *MyJSONFormatter) Format(entry *log.Entry) ([]byte, error) {
// fmt.Println(entry.Data["msg"]) entry.Data["msg"] = fmt.Sprintf("%s%s", my.JSONPrefix, my.Otherdata)
json, err := jsoniter.Marshal(&entry.Data)
if err != nil {
return nil, fmt.Errorf("failed to marshal fields to JSON , %w", err)
}
return append(json, '\n'), nil } func main() {
formatter := &MyJSONFormatter{
JSONPrefix: "jsonprefix-",
Otherdata: ":otherdata:",
} log.SetFormatter(formatter)
log.Info("this is customered formatter")
}

3)第三方自定义formatter设置日志格式

等等

设置日志级别

logrus日志一共7级别, 从高到低: panic, fatal, error, warn, info, debug, trace.

  • log.SetLevel(log.WarnLevel) // 设置输出警告级别

设置日志输出方式

  • log.SetOutput(os.Stdout) // 输入到 Stdout,默认输出到 Stderr
  • logfile, _ := os.OpenFile("./logrus.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)

    logrus.SetOutput(logfile) // 输出到文件里

例子:

package main

import (
log "github.com/sirupsen/logrus"
"os"
) func init() {
log.SetFormatter(&log.JSONFormatter{}) // 设置 format json
log.SetLevel(log.WarnLevel) // 设置输出警告级别
// Output to stdout instead of the default stderr
log.SetOutput(os.Stdout)
} func main() {
log.WithFields(log.Fields{
"animal": "dog",
"size": 10,
}).Info("a group of dog emerges from the zoon") log.WithFields(log.Fields{
"omg": true,
"number": 12,
}).Warn("the group's number increased") log.WithFields(log.Fields{
"omg": true,
"number": 100,
}).Fatal("th ice breaks") // the logrus.Entry returned from WithFields()
contextLogger := log.WithFields(log.Fields{
"common": "this is a common filed",
"other": "i also should be logged always",
})
// 共同字段输出
contextLogger.Info("I'll be logged with common and other field")
contextLogger.Info("Me too")
}

运行输出:

{"level":"warning","msg":"the group's number increased","number":12,"omg":true,"time":"2021-11-11T18:00:55+08:00"}
{"level":"fatal","msg":"th ice breaks","number":100,"omg":true,"time":"2021-11-11T18:00:55+08:00"}

从输出的结果看出,Info 级别的日志信息都没有输出出来。

屏蔽设置日志级别的代码

func init() {
log.SetFormatter(&log.JSONFormatter{}) // 设置 format json
// log.SetLevel(log.WarnLevel) // 设置输出警告级别
}

在运行输出:

{"animal":"dog","level":"info","msg":"a group of dog emerges from the zoon","size":10,"time":"2021-11-11T18:26:45+08:00"}
{"level":"warning","msg":"the group's number increased","number":12,"omg":true,"time":"2021-11-11T18:26:45+08:00"}
{"level":"fatal","msg":"th ice breaks","number":100,"omg":true,"time":"2021-11-11T18:26:45+08:00"}
exit status 1

从输出的日志信息来看,并没有输出 contextLogger 的日志info信息,日志信息没有输出,为啥没有输出日志?

把上面的 Fatal 输出日志屏蔽掉:

// log.WithFields(log.Fields{
// "omg": true,
// "number": 100,
// }).Fatal("th ice breaks")

在运行输出:

{"animal":"dog","level":"info","msg":"a group of dog emerges from the zoon","size":10,"time":"2021-11-11T18:28:56+08:00"}
{"level":"warning","msg":"the group's number increased","number":12,"omg":true,"time":"2021-11-11T18:28:56+08:00"}
{"common":"this is a common filed","level":"info","msg":"I'll be logged with common and other field","other":"i also should be logged always","time":"2021-11-11T18:28:56+08:00"}
{"common":"this is a common filed","level":"info","msg":"Me too","other":"i also should be logged always","time":"2021-11-11T18:28:56+08:00"}

这时候可以输出 contextLogger 日志信息了。

3. logrus 的 Fatal 处理

上面的例子定义了输出 Fatal 日志后,其后的日志都不能输出了,这是为什么?日志后面有个信息 exit status 1

因为 logrus 的 Fatal 输出后,会执行 os.Exit(1)。那如果程序后面还有一些必要的程序要处理怎么办?

logrus 提供了 RegisterExitHandler 方法,在 fatal 异常时处理一些问题。

package main

import (
"fmt"
log "github.com/sirupsen/logrus"
) func main() {
log.SetFormatter(&log.TextFormatter{
TimestampFormat: "2006-01-02 15:04:05",
}) log.RegisterExitHandler(func() {
fmt.Println("发生了fatal异常,执行一些必要的处理工作")
}) log.Warn("warn")
log.Fatal("fatal")
log.Info("info") //不会执行
}

运行输出:

time="2021-11-11 21:48:25" level=warning msg=warn
time="2021-11-11 21:48:25" level=fatal msg=fatal
发生了fatal异常,执行一些必要的处理工作
exit status 1

4. 切分日志文件

如果日志文件太大了,想切分成小文件,但是 logrus 没有提供这个功能。

一种是借助linux系统的 logrotate 命令来切分 logrus 生成的日志文件。

另外一种是用 logrus 的 hook 功能,做一个切分日志的插件。找到了 file-rotatelogs,但是这个库状态

已经是 archived 状态,库作者现在不接受任何修改,他也不继续维护了。所以使用还是慎重些。

logrus issue 里找到了这个 https://github.com/natefinch/lumberjack 切割文件的库。

例子:

package main

import (
log "github.com/sirupsen/logrus" "gopkg.in/natefinch/lumberjack.v2"
) func main() {
logger := &lumberjack.Logger{
Filename: "./testlogrus.log",
MaxSize: 500, // 日志文件大小,单位是 MB
MaxBackups: 3, // 最大过期日志保留个数
MaxAge: 28, // 保留过期文件最大时间,单位 天
Compress: true, // 是否压缩日志,默认是不压缩。这里设置为true,压缩日志
} log.SetOutput(logger) // logrus 设置日志的输出方式 }

5. 设置 logrus 实例

如果一个应用有多个地方使用日志,可以单独实例化一个 logrus,作为全局的日志实例。

package main

import (
"os" "github.com/sirupsen/logrus"
) var log = logrus.New() func main() {
log.Out = os.Stdout // 设置输出日志位置,可以设置日志到file里 log.WithFields(logrus.Fields{
"fruit": "apple",
"size": 20,
}).Info(" a lot of apples on the tree")
}

输出:

time="2021-11-11T18:39:15+08:00" level=info msg=" a lot of apples on the tree" fruit=apple size=20

6. fields

在使用 logrus 时,鼓励用 log.WithFields(log.Fields{}).Fatal() 这种方式替代 og.Fatalf("Failed to send event %s to topic %s with key %d"), 也就是不是用 %s,%d 这种方式格式化,而是直接传入变量 event,topic 给 log.Fields ,这样就显得结构化日志输出,很人性化美观。

log.WithFields(log.Fields{
"event": event,
"topic": topic,
"key": key,
}).Fatal("Failed to send event")

7. 设置默认字段

比如在链路追踪里,会有一个 rquest_id ,trace_id 等,想这个 log 一直带有这 2 个字段,logrus 怎么设置?

可以用 log.WithFields(log.Fields{"request_id": request_id, "trace_id": trace_id})

requestLogger := log.WithFields(log.Fields{"request_id": request_id, "trace_id": trace_id})
requestLogger.Info("something happened on that request")
requestLogger.Warn("something not great happened")

例子:

package main

import (
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
) func main() {
uid := uuid.New()
request_id := uid
trace_id := uid
requestLogger := log.WithFields(log.Fields{"request_id": request_id, "trace_id": trace_id})
requestLogger.Info("something happened on that request")
requestLogger.Warn("something not great happened")
}

8. hook 钩子-扩展logrus功能

hook 给 logrus 提供了强大的可扩展功能.

用户可以给 logrus 编写钩子插件,根据自己的日志需求编写 hook。

logrus 也有一些内置插件hooks

第三方给 logrus 编写的 hook, 第三方hook列表

官方的 syslog hook example

package main

import (
"log/syslog" "github.com/sirupsen/logrus"
lSyslog "github.com/sirupsen/logrus/hooks/syslog"
) func main() {
log := logrus.New()
hook, err := lSyslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
if err != nil {
log.Hooks.Add(hook)
}
}

参考

golang常用库:日志记录库-logrus使用的更多相关文章

  1. 基于java.util.logging实现轻量级日志记录库(增加根据当前类class初始化,修复线程池模型(javaEE)下的堆栈轨迹顺序与当前调用方法不一致问题)

    前言: 本章介绍自己写的基于java.util.logging的轻量级日志记录库(baseLog). 该版本的日志记录库犹如其名,baseLog,是个实现日志记录基本功能的小库,适合小型项目使用,方便 ...

  2. python的一个简单日志记录库glog的使用

    一. glog的简介 glog所记录的日志信息总是记录到标准的stderr中,即控制台终端. 每一行日志记录总是会添加一个谷歌风格的前缀,即google-style log prefix, 它的形式如 ...

  3. SLF4J - 一个允许你统一日志记录API的抽象层

    一.什么是SLF4J 我们在做Java开发时,如果需要记录日志,有很多日志API可供选择,如: java.util.logging Apache log4j logback SLF4J又是个什么东东呢 ...

  4. Python 日志记录与程序流追踪(基础篇)

    日志记录(Logging) More than print: 每次用 terminal debug 时都要手动在各种可能出现 bug 的地方 print 相关信息来确认 bug 的位置: 每次完成 d ...

  5. 微软企业库5.0 学习之路——第九步、使用PolicyInjection模块进行AOP—PART4——建立自定义Call Handler实现用户操作日志记录

    在前面的Part3中, 我介绍Policy Injection模块中内置的Call Handler的使用方法,今天则继续介绍Call Handler——Custom Call Handler,通过建立 ...

  6. numpy函数库中一些常用函数的记录

    ##numpy函数库中一些常用函数的记录 最近才开始接触Python,python中为我们提供了大量的库,不太熟悉,因此在<机器学习实战>的学习中,对遇到的一些函数的用法进行记录. (1) ...

  7. Python - loguru日志库,高效输出控制台日志和日志记录

    一.安装loguru loguru的PyPI地址为:https://pypi.org/project/loguru/ GitHub仓库地址为:https://github.com/Delgan/log ...

  8. golang常用库:cli命令行/应用程序生成工具-cobra使用

    golang常用库:cli命令行/应用程序生成工具-cobra使用 一.Cobra 介绍 我前面有一篇文章介绍了配置文件解析库 Viper 的使用,这篇介绍 Cobra 的使用,你猜的没错,这 2 个 ...

  9. Python常用的标准库以及第三方库有哪些?

    20个必不可少的Python库也是基本的第三方库 读者您好.今天我将介绍20个属于我常用工具的Python库,我相信你看完之后也会觉得离不开它们.他们是: Requests.Kenneth Reitz ...

随机推荐

  1. css布局宽度自适应

    随着各种终端的不断涌现,网页中的元素适应不同的分辨率变得特别重要,根据经验,涉及到宽度自适应的一共有四种情况: 左端固定,右边自适应:右端固定,左边自适应:两端固定,中间自适应:中间固定,两端自适应. ...

  2. Python守护线程简述

    thread模块不支持守护线程的概念,当主线程退出时,所有的子线程都将终止,不管它们是否仍在工作,如果你不希望发生这种行为,就要引入守护线程的概念. threading模块支持守护线程,其工作方式是: ...

  3. WPF进阶技巧和实战03-控件(5-列表、树、网格02)

    数据模板 样式提供了基本的格式化能力,但是不管如何修改ListBoxItem,他都不能够展示功能更强大的元素组合,因为了每个ListBoxItem只支持单个绑定字段(通过DisplayMemberPa ...

  4. 01 ASP.NET Core 3 启动过程(一)

    ASP.NET Core 3 启动过程(一) 最近又忙于各种扯淡,今天来一个需求,明天又来一个需求,后天需求又变了,这可能是很多人遇到的情况.正在紧张的忙碌着,突然一个信息把所有计划打乱了," ...

  5. Mybatis一级缓存的锅

    问题背景 项目开发中有一个树形数据结构,不像经典组织结构树.菜单级别树,我们这个树形结构是用户后期手动建立起来的关系.因此数据库表结构为两张表:数据记录表.记录关系表,通过业务规则限制,形成的树形结构 ...

  6. C语言对"不定长"字符串数组的遍历

    一般来说,c语言的数组的初始化可以通过三种方式: {0},在声明时使用,如 int a[10]={0} 使用memset, memset(array,0,sizeof(array)) 用for循环赋值 ...

  7. ubuntu16.04安装klee

    ubuntu16.04安装klee(基于llvm 3.8)教程 前言 查阅了很多资料,踩了不少的坑,总的来说,这个应该是比较完善的基于llvm3.8和ubuntu16.04的安装教程,至少我自己按照这 ...

  8. Linux命令(二)

    1.cd命令 这是一个非常基本,也是大家经常需要使用的命令,它用于切换当前目录,它的参数是要切换到的目录的路径,可以是绝对路径,也可以是相对路径.如: cd /root/Docements # 切换到 ...

  9. 异构智联Wi-Fi+蓝牙模组,连接快、准、稳!

    下班回家打开门,电灯.电视.空调.音响.电动窗帘.扫地机器人--一呼百应,有序开工,原本冰冷的房子立刻变成了温暖港湾.可以说,舒适便捷的智能设备已经完全融入了我们的生活中. 从单一场景.单一设备,到现 ...

  10. 【c++ Prime 学习笔记】第8章 IO库

    C++语言不直接处理输入输出,而是通过标准库中的一组类来处理IO 1.2节介绍的IO库: istream(输入流)类型,提供输入 ostream(输出流)类型,提供输出 cin,是istream对象, ...