Logrus源码阅读(1)--基本用法

选择golang日志库时, 使用logrus的主要原因就是因为star比较多, 而且社区活跃度非常高. 在项目使用过程中, 发现logrus的调用入口, 性能, 插件, 自定义插件, 输出格式等都非常优秀, 值得学习一下

整体结构图

logrus

整体来看总共提供两种方式调用:

  1. logrus.Info("hello logrus")
  2. logrus.WithField(logruns.Fields{"key1":"v1"}).Info("hello logrus")

这些函数都在exported.go文件中. 当然为了提供不同级别输出日志的功能, 里面实现了各种各样的print函数, 如: Infof, Error, Errorf, Panic等等

在直接使用logrus等情况下exported.go是唯一入口, 但是我们可以简单封装一下, 跟项目框架更加贴合, 这个留在后面用具体例子来解释这么做的原因和好处

简单介绍使用方法

普通用法

package main

import (
  log "github.com/sirupsen/logrus"
)

func main() {
  log.Info("A walrus appears")
}
time="2019-07-16T22:51:31+08:00" level=info msg="hello logrus"

注意log "github.com/sirupsen/logrus"这里将logrus的别名设置为log, 然后就直接调用了log.Info. 假如你的项目现在使用的标准库log, 则可以无缝迁移到logrus上, 因为标准库实现的print函数较少, logrus全部已经实现, 只需要简单引入这个别名即可

WithFields

由于logrus不建议下面的用法:

log.Fatalf("Failed to send event %s to topic %s with key %d")

因为logrus鼓励结构化的日志输出, 上面的用法就非常的不人性化, 不美观. 应该改成下面的方式:

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

但是根据实际使用过程中发现, 一般要使用WithFields输出日志字段时, 那些字段一般都是公共字段, 比如: request_id, token等等, 程序里到处打印WithFields也不是个优美的办法(后续会解释怎么做)

所以尽管logrus不建议我们使用Printf, 但是程序该需要用到Printf的地方还是需要的

设置打印格式

logrus自带两种方式的输出格式: 纯文本和JSON格式的.

JSONFormatter

func main() {
    log.SetFormatter(&log.JSONFormatter{})
    log.Info("hello logrus")
}
{"level":"info","msg":"hello logrus","time":"2019-07-17T22:47:14+08:00"}

TextFormatter

默认情况下就是TextFormatter, 默认情况下是带颜色输出的. 当然也不是任何时候都输出带颜色的结果, 取决于在终端输出并且不是运行在windows系统, 或者是否设置过ForceColors=true, 如果设置了就会按照有颜色的方式输出.

程序会在启动的时候检测是否是终端运行, 具体的实现就是terminal_check_(OS).go, 具体实现后续关于TextFormatter的具体实现再看

func main() {
    log.SetFormatter(&log.TextFormatter{})
    log.Info("hello logrus")
}
INFO[0000] hello logrus

也可以禁用

func main() {
    log.SetFormatter(&log.TextFormatter{
        DisableColors: true,
    })
    log.Info("hello logrus")
}

time="2019-07-17T23:44:42+08:00" level=info msg="hello logrus"

同时, 你可以根据自己的实际需求, 去定制自己的Formater, 只需要实现Format方法即可

设置调用log的位置

func main() {
    log.SetFormatter(&log.TextFormatter{
        DisableColors: true,
    })
    log.SetReportCaller(true)
    log.Info("hello logrus")
}
time="2019-07-18T10:40:21+08:00" level=info msg="hello logrus" func=main.main file="/Users/haohongfan/goproject/test/logrus_test/main.go:33"

但是请注意:

Note that this does add measurable overhead - the cost will depend on the version of Go,
but is between 20 and 40% in recent tests with 1.6 and 1.7.You can validate this in your environment
via benchmarks: go test -bench=.*CallerTracing

也就设置这个是有性能问题的, 生产环境是一定不能启动用, 其实也没有必要, 我们并不关心是哪一行打印的(如果你的日志确实需要靠这个来确定的话, 那你的日志是需要优化一下的)

设置日志级别

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

在生产环境时选择打印Info以上级别的日志, 就可以log.SetLevel(log.InfoLevel), 那么Debug, Trace就不会打印出来. 源码实现这个功能很简单, 就是判断Print函数的级别是否大于SetLevel的值

log.SetLevel(log.ErrorLevel)这个函数要求传入的参数是Level类型的值(其实也就是uint32, type Level uint32), 我们在封装我们代码时, 肯定要定义panic等这些级别. logrus本身提供将panic转换成PanicLevel的函数和获取xxLevel对应的字符串. 这些都封装在logrus.go里面

func main() {
    // log.SetLevel(log.ErrorLevel)
    level, _ := log.ParseLevel("info")
    log.SetLevel(level)
    log.Info("hello logrus")
    fmt.Println(log.ErrorLevel)
}
error
time="2019-07-18T11:41:02+08:00" level=info msg="hello logrus"

Hook

Hook是一大特色, 也给logrus留下各种各样的扩展机会. 比如: lfshook, dingrus

你可以根据自己的特殊需求扩展自己的Hook, 只需要简单实现Levels() []Level, Fire(*Entry) error即可. logrus提供一个syslog, test的插件, 同时github上可以找到很多

后面说源码的时候, 我会选择lfshook作为例子进行分析其实现细节, 同时我们也会选择一个功能实现一个

日志的文件输出, 切分, 删过期文件

logrus本身不提供这样的功能, 需要借助第三方插件lfshook进行

相对高级的用法

前面说到程序里到处log.WithFields{log.Field{xxx}}是一种比较不好的用法, 故我们开发的框架在集成logrus的时候要简单封装一下. logrus README也有提到

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

下面说具体如何操作, 可以参考bilibili sniper

比如跟gin的结合使用, 这是我的项目的一段实际的代码. 在log目录下创建log.go

// Entry ling-nest log Entry
func Entry(ctx *gin.Context) *logrus.Entry {
    return logrus.WithFields(logrus.Fields{
        "device_type": ctx.Value("device_type"),
        "channel":     ctx.Value("channel"),
        "license":     ctx.Value("license"),
        "v4":          ctx.Value("V4"),
    })
}

实际使用时: log.Entry(context).Info("xxxxxx")

总结

第一篇关于logrus源码阅读主要是为了介绍相关的用法. 从下面开始将正式进入源码阶段. 下一篇主要根据源码介绍logrus的整个生命周期

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 4,817评论 1 13
  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 4,907评论 0 6
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,615评论 0 3
  • 在我们开发程序后,如果有一些问题需要对程序进行调试的时候,日志是必不可少的,这是我们分析程序问题常用的手段。 日志...
    豆瓣奶茶阅读 18,311评论 0 22
  • 今天是我人生第一份工作的最后一天 热血的青年需要走出自己的舒适地带 其中的辛苦需要用自我鼓励与坚持来砥砺 不断反思...
    可乐荔枝樱桃阅读 437评论 0 3