成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何使用GO語(yǔ)言從零實(shí)現(xiàn)日志包

開發(fā) 前端
從頭開發(fā)一個(gè)日志包,可以讓我們了解日志包的底層邏輯,使得我們對(duì)日志包有定制需求的時(shí)候,可以能夠基于開源的日志包實(shí)現(xiàn)我們的功能。

背景

當(dāng)前的開源日志包有很多,像go中的標(biāo)準(zhǔn)庫(kù)log包、glog、logrus、zap。它們每種日志包都有相應(yīng)的應(yīng)用場(chǎng)景。四種日志包相關(guān)對(duì)比如下所示:

標(biāo)準(zhǔn)庫(kù)log

功能簡(jiǎn)單,不支持日志級(jí)別、日志格式。但是使用簡(jiǎn)單,易于快速上手。大型項(xiàng)目較少使用

glog

提供了日志包的基本功能,像日志級(jí)別、格式等。適合一些小項(xiàng)目

logrus

功能強(qiáng)大,不僅實(shí)現(xiàn)了基本日志功能,還提供了很多高級(jí)功能。適合大型項(xiàng)目

zap

功能強(qiáng)大,性能高,適合對(duì)日志性能要求高的項(xiàng)目。另外zap的子包zapcore提供了很多底層日志接口,適合二次開發(fā)

從頭開發(fā)一個(gè)日志包,可以讓我們了解日志包的底層邏輯,使得我們對(duì)日志包有定制需求的時(shí)候,可以能夠基于開源的日志包實(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)一個(gè)日志包,就需要實(shí)現(xiàn)下面三個(gè)基本的對(duì)象,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最高,這個(gè)從
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緩存對(duì)象,提升性能,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會(huì)接收這些函數(shù)作為輸入,對(duì)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)用

通過下面的代碼,我們看看整個(gè)代碼是如何串起來的。

// 輸出到文件
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")
  1. 上面的整體實(shí)現(xiàn)是,將"custom log with json formatter"這段字符串寫入到指定文件里面
  2. 1到6行創(chuàng)建并打開文件
  3. 重點(diǎn)是8行,cuslog.WithLevel(cuslog.InfoLevel)、cuslog.WithOutput(fd)、cuslog.WithFormatter(&cuslog.JsonFormatter{IgnoreBasicFields: false})三個(gè)函數(shù)調(diào)用,返回三個(gè)函數(shù)func(o *options),這些函數(shù)都是Option類型,因?yàn)?/span>type Option func(*options)。
  4. 然后調(diào)用cuslog.New,這個(gè)函數(shù)上面也給出了,它里面通過initOptions依次調(diào)用上面的Option函數(shù),對(duì)options對(duì)象進(jìn)行設(shè)置,然后把options賦給opt, 并創(chuàng)建logger. logger := &logger{opt: initOptions(opts...)}
  5. 最后調(diào)用l.Info("custom log with json formatter")把字符串輸出到文件中.整個(gè)調(diào)用鏈?zhǔn)莑.info===>通過l的pool獲取entry===>調(diào)用entry的write(InfoLevel, FmtEmptySeparate, args...),在這個(gè)write函數(shù)里面,只有infoLevel比logger.level優(yōu)先級(jí)大或相等,才輸出。并且通過runtime.Caller(2)獲取最上層調(diào)用info時(shí)的,文件名,行號(hào),函數(shù)名等信息。因?yàn)檫@個(gè)地方有2層嵌套才調(diào)用到entry的write,所以runtime.Caller(2)的參數(shù)是2

總結(jié)

上面的代碼實(shí)現(xiàn)了基本的日志功能,包括日志級(jí)別、日志格式配置、輸出文件或標(biāo)準(zhǔn)輸出的設(shè)置。但是一些高級(jí)的功能,比如按級(jí)別分類輸出,Hook能力,結(jié)構(gòu)化日志。這些目前都不支持。

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2023-02-13 00:24:37

Go語(yǔ)言日志庫(kù)

2024-02-01 13:30:53

Go語(yǔ)言開發(fā)

2020-03-17 10:24:12

Go語(yǔ)言停止寫障礙

2020-08-12 08:56:30

代碼凱撒密碼函數(shù)

2024-02-06 17:57:06

Go語(yǔ)言任務(wù)

2021-05-13 17:02:38

MDC腳手架日志

2023-10-13 19:42:00

2022-08-08 08:31:55

Go 語(yǔ)言閉包匿名函數(shù)

2022-08-08 06:50:06

Go語(yǔ)言閉包

2023-11-07 14:30:28

Python開發(fā)

2017-11-16 15:25:54

Go語(yǔ)言算法代碼

2021-06-08 07:45:44

Go語(yǔ)言優(yōu)化

2024-10-08 10:57:04

2021-04-09 20:04:34

區(qū)塊鏈Go加密

2024-03-12 09:13:28

Go語(yǔ)言main

2018-08-20 08:15:50

編程語(yǔ)言Go語(yǔ)言切片

2022-11-03 20:38:01

CMD命令Go

2021-01-06 09:47:51

內(nèi)存Go語(yǔ)言

2019-12-03 09:31:14

編程語(yǔ)言程序員Python

2021-02-06 18:19:54

TimeGo語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产目拍亚洲精品99久久精品 | 精品国产伦一区二区三区观看说明 | 拍拍无遮挡人做人爱视频免费观看 | 亚洲在线一区二区 | 久久久久久久久99精品 | 一区二区三区四区av | 精精国产xxxx视频在线播放 | 久久草视频 | 国产精品一区二区av | 九九爱这里只有精品 | 美女一级毛片 | 欧美日韩中文字幕在线 | 日韩欧美中文字幕在线观看 | 国产精品久久久久久亚洲调教 | 国产伦精品一区二区三区精品视频 | 亚洲男人天堂 | 国产精品美女在线观看 | 日韩久久久久久久久久久 | 亚洲国产一区二区在线 | 欧美成人综合 | 国产做a爱免费视频 | 人人人人干 | 中文字幕一区二区三区在线观看 | 日日操夜夜操天天操 | 欧美日韩一区二区三区视频 | 国产精品久久久亚洲 | 精品毛片视频 | 青春草在线 | 伊人网站 | 性欧美精品一区二区三区在线播放 | 久久男人 | 色五月激情五月 | 欧美性网 | 九九成人| 97久久精品午夜一区二区 | 欧美精品一区二区三区在线播放 | 久久国产欧美日韩精品 | 午夜免费网站 | 色呦呦网站 | 国产7777| 久久精品国产亚洲 |