2023-04-18 09:57:57來源:今日頭條
當(dāng)前的開源日志包有很多,像go中的標(biāo)準(zhǔn)庫log包、glog、logrus、zap。它們每種日志包都有相應(yīng)的應(yīng)用場景。四種日志包相關(guān)對比如下所示:
標(biāo)準(zhǔn)庫log
| 功能簡單,不支持日志級別、日志格式。但是使用簡單,易于快速上手。大型項(xiàng)目較少使用 |
glog | 提供了日志包的基本功能,像日志級別、格式等。適合一些小項(xiàng)目 |
logrus | 功能強(qiáng)大,不僅實(shí)現(xiàn)了基本日志功能,還提供了很多高級功能。適合大型項(xiàng)目 |
zap | 功能強(qiáng)大,性能高,適合對日志性能要求高的項(xiàng)目。另外zap的子包zapcore提供了很多底層日志接口,適合二次開發(fā) |
從頭開發(fā)一個日志包,可以讓我們了解日志包的底層邏輯,使得我們對日志包有定制需求的時候,可以能夠基于開源的日志包實(shí)現(xiàn)我們的功能。所以本文以cuslog為例,看看如何實(shí)現(xiàn)我們自己的日志包(代碼:https://github.com/marmotedu/gopractise-demo/tree/master/log/cuslog)。
代碼結(jié)構(gòu)cuslog目錄代碼結(jié)構(gòu)
cuslog代碼結(jié)構(gòu)
要實(shí)現(xiàn)一個日志包,就需要實(shí)現(xiàn)下面三個基本的對象,Entry,Logger,Options。
Entry代碼:https://github.com/marmotedu/gopractise-demo/blob/master/log/cuslog/entry.go。
//構(gòu)造函數(shù)func entry(logger *logger) *Entry { return &Entry{logger: logger, Buffer: new(bytes.Buffer), Map: make(map[string]interface{}, 5)}}/*entry主要方法是write方法,它首先通過e.logger.opt.level 與 level的比較,來判斷是否要將日志輸出,其中DEBUG最低,F(xiàn)ATAL最高,這個從https://github.com/marmotedu/gopractise-demo/blob/master/log/cuslog/options.go#L19中可以看到。*/func (e *Entry) write(level Level, format string, args ...interface{}) { if e.logger.opt.level > level { return } e.Time = time.Now() e.Level = level e.Format = format e.Args = args if !e.logger.opt.disableCaller { if pc, file, line, ok := runtime.Caller(2); !ok { e.File = "???" e.Func = "???" } else { e.File, e.Line, e.Func = file, line, runtime.FuncForPC(pc).Name() e.Func = e.Func[strings.LastIndex(e.Func, "/")+1:] } } e.format() e.writer() e.release()}Entry的write方法實(shí)現(xiàn)了將它Buffer中的數(shù)據(jù),寫入到它的logger所配置的output中。
Logger代碼:https://github.com/marmotedu/gopractise-demo/blob/master/log/cuslog/logger.go。
/*創(chuàng)建方法,通過sync.Pool緩存對象,提升性能,initOptions是用于初始化logger的options的各種屬性*/func New(opts ...Option) *logger { logger := &logger{opt: initOptions(opts...)} logger.entryPool = &sync.Pool{New: func() interface{} { return entry(logger) }} return logger}Options代碼:https://github.com/marmotedu/gopractise-demo/blob/68e100ee78a3093e6f2434439e7d4b143b9ebf60/log/cuslog/options.go。
/*opts 參數(shù)是一系列的用于設(shè)置options屬性的函數(shù),比如下面的WithOutput和WithLevel都是這種函數(shù),initOptions會接收這些函數(shù)作為輸入,對o = &options{}進(jìn)行設(shè)置*/type Option func(*options)func initOptions(opts ...Option) (o *options) { o = &options{} for _, opt := range opts { opt(o) } if o.output == nil { o.output = os.Stderr } if o.formatter == nil { o.formatter = &TextFormatter{} } return}func WithOutput(output io.Writer) Option { return func(o *options) { o.output = output }}func WithLevel(level Level) Option { return func(o *options) { o.level = level }}應(yīng)用通過下面的代碼,我們看看整個代碼是如何串起來的。
// 輸出到文件 fd, err := os.OpenFile("test.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.Fatalln("create file test.log failed") } defer fd.Close() l := cuslog.New(cuslog.WithLevel(cuslog.InfoLevel), cuslog.WithOutput(fd), cuslog.WithFormatter(&cuslog.JsonFormatter{IgnoreBasicFields: false}), ) l.Info("custom log with json formatter")上面的整體實(shí)現(xiàn)是,將"custom log with json formatter"這段字符串寫入到指定文件里面1到6行創(chuàng)建并打開文件重點(diǎn)是8行,cuslog.WithLevel(cuslog.InfoLevel)、cuslog.WithOutput(fd)、cuslog.WithFormatter(&cuslog.JsonFormatter{IgnoreBasicFields: false})三個函數(shù)調(diào)用,返回三個函數(shù)func(o*options),這些函數(shù)都是Option類型,因?yàn)閠ypeOptionfunc(*options)。然后調(diào)用cuslog.New,這個函數(shù)上面也給出了,它里面通過initOptions依次調(diào)用上面的Option函數(shù),對options對象進(jìn)行設(shè)置,然后把options賦給opt, 并創(chuàng)建logger. logger := &logger{opt: initOptions(opts...)}最后調(diào)用l.Info("custom log with json formatter")把字符串輸出到文件中.整個調(diào)用鏈?zhǔn)莑.info===>通過l的pool獲取entry===>調(diào)用entry的write(InfoLevel, FmtEmptySeparate, args...),在這個write函數(shù)里面,只有infoLevel比logger.level優(yōu)先級大或相等,才輸出。并且通過runtime.Caller(2)獲取最上層調(diào)用info時的,文件名,行號,函數(shù)名等信息。因?yàn)檫@個地方有2層嵌套才調(diào)用到entry的write,所以runtime.Caller(2)的參數(shù)是2總結(jié)上面的代碼實(shí)現(xiàn)了基本的日志功能,包括日志級別、日志格式配置、輸出文件或標(biāo)準(zhǔn)輸出的設(shè)置。但是一些高級的功能,比如按級別分類輸出,Hook能力,結(jié)構(gòu)化日志。這些目前都不支持。
關(guān)鍵詞:
?盡管Kubernetes是當(dāng)今使用最廣泛的開源容器編排平臺,但它沒有創(chuàng)建和管理用戶的手段,至少沒有本地方式。
背景當(dāng)前的開源日志包有很多,像go中的標(biāo)準(zhǔn)庫log包、glog、logrus、zap。它們每種日志包都有相應(yīng)的應(yīng)用場景
模塊和包是Python編程語言中非常重要的概念。模塊是一個包含Python代碼的文件,它可以包含函數(shù)、類、變量等
單節(jié)點(diǎn)模式(Standalone,不推薦用于生產(chǎn)環(huán)境)standalone模式即單節(jié)點(diǎn)模式,指在服務(wù)器上只部署一個mongod
4月18日消息,特斯拉CEO埃隆·馬斯克在接受采訪時表示,他開啟了一個新的人工智能項(xiàng)目,旨在理解宇宙本...
智通財經(jīng)獲悉,安徽皖通高速公司(00995)低開近5%,截止發(fā)稿,跌4 56%,報7 54港元,成交額188 5萬港元。
今日,國際足聯(lián)官方宣布,阿根廷將成為2023年U20世青賽的主辦國。
1、瓜子臉是所有女性向往的完美臉型,隨著整容風(fēng)潮的爆發(fā),很多女性的整容方向都是完美的瓜子臉,雖說瓜子
4月17日北向資金減持7 39萬股慧博云通。近5個交易日中,獲北向資金增持的有3天,累計凈增持11 68萬股。近20
在農(nóng)村,很多村民還有自己留存蔬菜種子的習(xí)慣,不過僅僅只針對方便留種的一些蔬菜。在我家,老媽經(jīng)常留著的
1、安全帶——生命帶!開車別忘了安全!2、安全帶是救生帶,是救生索!3、在車上系好安全帶,防止發(fā)生意...
長沙航院獲獎團(tuán)隊。近日,2023年“中成偉業(yè)杯”全國航空職業(yè)院校航空電子電氣裝調(diào)與維修技能大賽在張家...
21龍控03停牌提示
?從云南省西雙版納州勐臘縣勐捧鎮(zhèn)驅(qū)車行駛約16公里,抬眼便能望見一個村寨——曼賀南村,一個溫暖美麗...
1、Go匯編基礎(chǔ)知識1 1、通用寄存器不同體系結(jié)構(gòu)的CPU,其內(nèi)部寄存器的數(shù)量、種類以及名稱可能大不相同,這