Logrus源碼閱讀(1)--基本用法

選擇golang日志庫時, 使用logrus的主要原因就是因為star比較多, 而且社區(qū)活躍度非常高. 在項目使用過程中, 發(fā)現(xiàn)logrus的調(diào)用入口, 性能, 插件, 自定義插件, 輸出格式等都非常優(yōu)秀, 值得學(xué)習(xí)一下

整體結(jié)構(gòu)圖

logrus

整體來看總共提供兩種方式調(diào)用:

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

這些函數(shù)都在exported.go文件中. 當(dāng)然為了提供不同級別輸出日志的功能, 里面實現(xiàn)了各種各樣的print函數(shù), 如: 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的別名設(shè)置為log, 然后就直接調(diào)用了log.Info. 假如你的項目現(xiàn)在使用的標準庫log, 則可以無縫遷移到logrus上, 因為標準庫實現(xiàn)的print函數(shù)較少, logrus全部已經(jīng)實現(xiàn), 只需要簡單引入這個別名即可

WithFields

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

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

因為logrus鼓勵結(jié)構(gòu)化的日志輸出, 上面的用法就非常的不人性化, 不美觀. 應(yīng)該改成下面的方式:

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

但是根據(jù)實際使用過程中發(fā)現(xiàn), 一般要使用WithFields輸出日志字段時, 那些字段一般都是公共字段, 比如: request_id, token等等, 程序里到處打印WithFields也不是個優(yōu)美的辦法(后續(xù)會解釋怎么做)

所以盡管logrus不建議我們使用Printf, 但是程序該需要用到Printf的地方還是需要的

設(shè)置打印格式

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, 默認情況下是帶顏色輸出的. 當(dāng)然也不是任何時候都輸出帶顏色的結(jié)果, 取決于在終端輸出并且不是運行在windows系統(tǒng), 或者是否設(shè)置過ForceColors=true, 如果設(shè)置了就會按照有顏色的方式輸出.

程序會在啟動的時候檢測是否是終端運行, 具體的實現(xiàn)就是terminal_check_(OS).go, 具體實現(xiàn)后續(xù)關(guān)于TextFormatter的具體實現(xiàn)再看

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"

同時, 你可以根據(jù)自己的實際需求, 去定制自己的Formater, 只需要實現(xiàn)Format方法即可

設(shè)置調(diào)用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

也就設(shè)置這個是有性能問題的, 生產(chǎn)環(huán)境是一定不能啟動用, 其實也沒有必要, 我們并不關(guān)心是哪一行打印的(如果你的日志確實需要靠這個來確定的話, 那你的日志是需要優(yōu)化一下的)

設(shè)置日志級別

logrus日志一共7級別, 從高到低: panic, fatal, error, warn, info, debug, trace.

在生產(chǎn)環(huán)境時選擇打印Info以上級別的日志, 就可以log.SetLevel(log.InfoLevel), 那么Debug, Trace就不會打印出來. 源碼實現(xiàn)這個功能很簡單, 就是判斷Print函數(shù)的級別是否大于SetLevel的值

log.SetLevel(log.ErrorLevel)這個函數(shù)要求傳入的參數(shù)是Level類型的值(其實也就是uint32, type Level uint32), 我們在封裝我們代碼時, 肯定要定義panic等這些級別. logrus本身提供將panic轉(zhuǎn)換成PanicLevel的函數(shù)和獲取xxLevel對應(yīng)的字符串. 這些都封裝在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

你可以根據(jù)自己的特殊需求擴展自己的Hook, 只需要簡單實現(xiàn)Levels() []Level, Fire(*Entry) error即可. logrus提供一個syslog, test的插件, 同時github上可以找到很多

后面說源碼的時候, 我會選擇lfshook作為例子進行分析其實現(xiàn)細節(jié), 同時我們也會選擇一個功能實現(xiàn)一個

日志的文件輸出, 切分, 刪過期文件

logrus本身不提供這樣的功能, 需要借助第三方插件lfshook進行

相對高級的用法

前面說到程序里到處log.WithFields{log.Field{xxx}}是一種比較不好的用法, 故我們開發(fā)的框架在集成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的結(jié)合使用, 這是我的項目的一段實際的代碼. 在log目錄下創(chuàng)建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")

總結(jié)

第一篇關(guān)于logrus源碼閱讀主要是為了介紹相關(guān)的用法. 從下面開始將正式進入源碼階段. 下一篇主要根據(jù)源碼介紹logrus的整個生命周期

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蒿辙,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌姆怪,老刑警劉巖甸昏,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡抢韭,警方通過查閱死者的電腦和手機例衍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門昔期,熙熙樓的掌柜王于貴愁眉苦臉地迎上來已卸,“玉大人,你說我怎么就攤上這事硼一±墼瑁” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵般贼,是天一觀的道長愧哟。 經(jīng)常有香客問我,道長哼蛆,這世上最難降的妖魔是什么蕊梧? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮腮介,結(jié)果婚禮上肥矢,老公的妹妹穿的比我還像新娘。我一直安慰自己叠洗,他們只是感情好甘改,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著惕味,像睡著了一般楼誓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上名挥,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天疟羹,我揣著相機與錄音,去河邊找鬼禀倔。 笑死榄融,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的救湖。 我是一名探鬼主播愧杯,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鞋既!你這毒婦竟也來了力九?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤邑闺,失蹤者是張志新(化名)和其女友劉穎跌前,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體陡舅,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡抵乓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灾炭。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡茎芋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜈出,到底是詐尸還是另有隱情田弥,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布掏缎,位于F島的核電站皱蹦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏眷蜈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一沈自、第九天 我趴在偏房一處隱蔽的房頂上張望酌儒。 院中可真熱鬧,春花似錦枯途、人聲如沸忌怎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽榴啸。三九已至,卻和暖如春晚岭,著一層夾襖步出監(jiān)牢的瞬間鸥印,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工坦报, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留库说,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓片择,卻偏偏與公主長得像潜的,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子字管,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 在應(yīng)用程序中添加日志記錄總的來說基于三個目的:監(jiān)視代碼中變量的變化情況啰挪,周期性的記錄到文件中供其他應(yīng)用進行統(tǒng)計分析...
    時待吾閱讀 4,982評論 1 13
  • 在應(yīng)用程序中添加日志記錄總的來說基于三個目的:監(jiān)視代碼中變量的變化情況,周期性的記錄到文件中供其他應(yīng)用進行統(tǒng)計分析...
    時待吾閱讀 4,975評論 0 6
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 2,693評論 0 3
  • 在我們開發(fā)程序后嘲叔,如果有一些問題需要對程序進行調(diào)試的時候亡呵,日志是必不可少的,這是我們分析程序問題常用的手段借跪。 日志...
    豆瓣奶茶閱讀 18,353評論 0 22
  • 今天是我人生第一份工作的最后一天 熱血的青年需要走出自己的舒適地帶 其中的辛苦需要用自我鼓勵與堅持來砥礪 不斷反思...
    可樂荔枝櫻桃閱讀 449評論 0 3