Go語言編程實現(xiàn)支持六種級別的日志庫_第1頁
Go語言編程實現(xiàn)支持六種級別的日志庫_第2頁
Go語言編程實現(xiàn)支持六種級別的日志庫_第3頁
Go語言編程實現(xiàn)支持六種級別的日志庫_第4頁
Go語言編程實現(xiàn)支持六種級別的日志庫_第5頁
已閱讀5頁,還剩2頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第Go語言編程實現(xiàn)支持六種級別的日志庫目錄前言初始需求技術(shù)實現(xiàn)類型定義日志級別寫到文件默認(rèn)實現(xiàn)

前言

Golang標(biāo)準(zhǔn)日志庫提供的日志輸出方法有Print、Fatal、Panic等,沒有常見的Debug、Info、Error等日志級別,用起來不太順手。這篇文章就來手?jǐn)]一個自己的日志庫,可以記錄不同級別的日志。

其實對于追求簡單來說,Golang標(biāo)準(zhǔn)日志庫的三個輸出方法也夠用了,理解起來也很容易:

Print用于記錄一個普通的程序日志,開發(fā)者想記點什么都可以。Fatal用于記錄一個導(dǎo)致程序崩潰的日志,并會退出程序。Panic用于記錄一個異常日志,并觸發(fā)panic。

不過對于用慣了Debug、Info、Error的人來說,還是有點不習(xí)慣;對于想更細(xì)致的區(qū)分日志級別的需求,標(biāo)準(zhǔn)日志庫還提供了一個通用的Output方法,開發(fā)者在要輸出的字符串中加入級別也是可以的,但總是有點別扭,不夠直接。

目前市面上也已經(jīng)有很多優(yōu)秀的三方日志庫,比如uber開源的zap,常見的還有zerolog、logrus等。不過我這里還是想自己手?jǐn)]一個,因為大多數(shù)開源產(chǎn)品都不會完全貼合自己的需求,有很多自己用不上的功能,這會增加系統(tǒng)的復(fù)雜性,有沒有隱藏的坑也很難說,當(dāng)然自己入坑的可能性也很大;再者看了官方日志庫的實現(xiàn)之后,感覺可以簡單封裝下即可實現(xiàn)自己想要的功能,能夠hold住。

初始需求

我這里的初始需求是:

將日志寫入磁盤文件,每個月一個文件夾,每個小時一個文件。支持常見日志級別:Trace、Debug、Info、Warn、Error、Fatal,并且程序能夠設(shè)置日志級別。

我給這個日志庫取名為ylog,預(yù)期的使用方法如下:

ylog.SetLevel(LevelInfo)

ylog.Debug("Iamadebuglog.")

ylog.Info("IamaInfolog.")

技術(shù)實現(xiàn)

類型定義

需要定義一個結(jié)構(gòu)體,保存日志級別、要寫入的文件等信息。

typeFileLoggerstruct{

lastHourint64

file*os.File

LevelLogLevel

musync.Mutex

iLogger*log.Logger

Pathstring

來看一下這幾個參數(shù):

lastHour用來記錄創(chuàng)建日志文件時的小時數(shù),如果小時變了,就要創(chuàng)建新的日志文件。

file當(dāng)前使用的日志文件。

Level當(dāng)前使用的日志級別。

mu因為可能在不同的goroutine中寫日志,需要一個互斥體保證日志文件不會重復(fù)創(chuàng)建。

iLogger標(biāo)準(zhǔn)日志庫實例,因為這里是封裝了標(biāo)準(zhǔn)日志庫。

Path日志輸出的最上層目錄,比如程序根目錄下的logs目錄,這里就保存一個字符串:logs。

日志級別

先把日志級別定義出來,這里日志級別其實是int類型,從0到5,級別不斷升高。

如果設(shè)置為ToInfo,則Info級別及比Info級別高的日志都能輸出。

typeLogLevelint

const(

LevelTraceLogLevel=iota

LevelDebug

LevelInfo

LevelWarn

LevelError

LevelFatal

上文提到可以在Output方法的參數(shù)中加入日志級別,這里就通過封裝Output方法來實現(xiàn)不同級別的日志記錄方法。這里貼出其中一個方法,封裝的方式都一樣,就不全都貼出來了:

func(l*FileLogger)CanInfo()bool{

returnl.Level=LevelInfo

func(l*FileLogger)Info(v...any){

ifl.CanInfo(){

l.ensureFile()

v=append([]any{"Info"},v...)

l.iLogger.Output(2,fmt.Sprintln(v...))

輸出日志前做了三件事:

判斷日志級別,如果設(shè)置的日志級別小于等于當(dāng)前輸出級別,則可以輸出。確保日志文件已經(jīng)創(chuàng)建好,后邊會講如何確保。將日志級別前插到日志字符串中。

然后調(diào)用標(biāo)準(zhǔn)庫的Output函數(shù)輸出日志,這里第一個參數(shù)是為了獲取到當(dāng)前正在寫日志的程序文件名,傳入的是在程序調(diào)用棧中進(jìn)行查找的深度值,這里用2就正好。

寫到文件

標(biāo)準(zhǔn)庫的log是支持輸出到多種目標(biāo)的,只要實現(xiàn)了io.Write接口:

typeWriterinterface{

Write(p[]byte)(nint,errerror)

因為文件對象也實現(xiàn)了這個接口,所以這里可以創(chuàng)建os.File的實例,并把它設(shè)置到內(nèi)嵌的標(biāo)準(zhǔn)日志庫實例,也就是設(shè)置到前邊創(chuàng)建的FileLogger中的iLogger中。這個操作在ensureFile方法中,看一下這個文件的實現(xiàn):

func(l*FileLogger)ensureFile()(errerror){

currentTime:=time.Now()

ifl.file==nil{

l.mu.Lock()

deferl.mu.Unlock()

ifl.file==nil{

l.file,err=createFile(l.Path,currentTime)

l.iLogger.SetOutput(l.file)

l.iLogger.SetFlags(log.Lshortfile|log.Ldate|log.Ltime|log.Lmicroseconds)

l.lastHour=getTimeHour(currentTime)

return

currentHour:=getTimeHour(currentTime)

ifl.lastHour!=currentHour{

l.mu.Lock()

deferl.mu.Unlock()

ifl.lastHour!=currentHour{

_=l.file.Close()

l.file,err=createFile(l.Path,currentTime)

l.iLogger.SetOutput(l.file)

l.iLogger.SetFlags(log.Llongfile|log.Ldate|log.Ltime)

l.lastHour=getTimeHour(currentTime)

return

這里稍微有點復(fù)雜,基本邏輯是:如果文件實例不存在,則創(chuàng)建;如果需要創(chuàng)建新的文件,則先關(guān)閉舊的文件再創(chuàng)建新的文件。

更改文件實例時需要加鎖,否則可能多次操作,出現(xiàn)預(yù)期之外的情況。

設(shè)置輸出到文件后,標(biāo)準(zhǔn)log庫的Output方法就會將日志輸出到這個文件了。

默認(rèn)實現(xiàn)

經(jīng)過上邊一系列操作,這個FileLogger就可以使用了:

varlogger=NewFileLogger(LevelInfo,"logs")

logger.Info("Thisisainfo.")

不過和最初設(shè)想的用法有點差別:ylog.Info(xxxx)

這需要在ylog包中再定義一個名為Info的公開函數(shù),可以在這個公開函數(shù)中調(diào)用一個默認(rèn)創(chuàng)建的FileLogger實例,代碼是這樣的:

varstdPath="logs"

varstd=NewFileLogger(LevelInfo,stdPath)

funcTrace(v...any){

ifstd.CanTrace(){

std.ensureFile()

v=append([]any{"Trace"},v...)

std.iLogger.Output(2,fmt.Sprintln(v...))

注意這里沒有調(diào)用std的Trace方法,這是因為Output中的第一個參數(shù),如果嵌套調(diào)用std.Trace,則多了一層,這個參數(shù)就得設(shè)置為3,但是自己創(chuàng)建實例調(diào)用Trace時這個參數(shù)需要為2,這就產(chǎn)生沖突了。

經(jīng)過以上這些操作,就可以實現(xiàn)預(yù)期的日志操作了:

ylo

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論