logrus固定當天日誌檔名稱原始碼修改

2021-10-04 06:08:49 字數 4630 閱讀 4358

logrus

是go語言開發中應用十分廣泛的開源日誌元件,具有日誌分級列印、日誌檔案輪轉分割、自動刪除過期日誌檔案等功能,在github上擁有14.2k的star;

眾所周知,logrus的日誌檔案輪轉規則為定期生成乙個帶日期格式的日誌檔案,類似***_2020.03.19.log、***_2020.03.20.log等形式。但在某些場景下我們需要乙個固定名稱的最新日誌檔案,且不能是軟連線(emm,這個需求也挺奇葩的,奈何我們也左右不了)。這時如果還想用logrus做工程的日誌元件的話(比如你已經用這個寫了一坨坨**了,實在不想回去攪屎了。事實上,我也沒找到很契合支援這個的其他日誌元件,可能也是我懶吧),那麼就該在logrus原始碼上動刀了。

在手術之前確保你足夠了解你的牛,成不了庖丁也別差太遠。logrus整體包含三部分:logrus本身、本地檔案系統lfshook、輪轉file-rotatelogs。logrus本身只負責寫日誌,當我們呼叫logger.debug等語句時,logrus去獲取乙個writer,獲取成功了就寫,別的不管。lfshook是寫入處理的鉤子,因為寫的時候我們只傳入了內容message,至於這個message最後記錄在檔案中用什麼格式,是就一句話,還是用個類似json的字段分割,加不加上時間戳等等這些都有鉤子決定,所以這個是你定製化日誌格式的東西。最後,file-rotatelogs負責日誌檔案輪轉,它不管你要寫什麼,只管到時候了就建立新檔案,然後把新檔案的writer返回給logrus,如果有軟連就把軟體指向新檔案,完成輪轉。大體上就這麼簡單,就簡要說下,具體的還是你去看**去。這裡有一點就是,我們可能以為輪轉是定時器控制的,但其實不是,而是每次呼叫一次logger.debug類函式就觸發一次是否要輪轉的流程 ,而且進入流程必須加鎖來包含併發。所以效率其實有點低,雖然做了一些空間換時間的技巧,在不需要輪轉的情況下不用走完整個流程,但加鎖就注定併發效能高不到哪兒去。

背景就說這麼多,下邊上**。以下**是在按天分割日誌的需求下改的,有點偏硬,你理解了後可以自己重寫。思路就是在logrus獲取日誌檔案writer的輪轉判斷流程裡,不生成帶日期名稱的當天日誌檔案,而是先把昨天的固定名稱日誌檔案重新命名成帶日期的檔名(日期是檔案的建立日期),然後再生成乙個固定的日誌名(我這裡是pai-customer.log,是上層應用傳過來的),再把writer返回。在不需要輪轉的情況下,直接返回當前固定名稱的日誌檔案writer,結束流程。

首先擴充套件了inte***ce.go檔案中的rotatelogs結構體,新增了lastlogcreatetime變數,用於記錄需要改名的日誌檔案的建立日期:

type rotatelogs struct
然後修改rotatelogs.go檔案中的getwriter_nolock函式,修改如下:

// must be locked during this operation

func (rl *rotatelogs) getwriter_nolock(bailonrotatefail, usegenerationalnames bool) (io.writer, error)

} err, need := needrotate(rl, filename)

if err != nil

if !need

rl.outfh = fh

} return rl.outfh, nil

} // andy add end

/* andy comment

var forcenewfile bool

if basefn != rl.curbasefn

} else

forcenewfile = true

generation++

} if forcenewfile else

if _, err := os.stat(name); err != nil

generation++

} }*/ // make sure the dir is existed, eg:

// ./foo/bar/baz/hello.log must make sure ./foo/bar/baz is existed

dirname := filepath.dir(filename)

if err := os.mkdirall(dirname, 0755); err != nil

// if we got here, then we need to create a file

if err != nil

// andy begin

rl.lastlogcreatetime = rl.clock.now()

// andy end

if err := rl.rotate_nolock(filename); err != nil

return nil, err

} fmt.fprintf(os.stderr, "%s\n", err.error())

} rl.outfh.close()

rl.outfh = fh

rl.curbasefn = basefn

rl.curfn = filename

rl.generation = generation

if h := rl.eventhandler; h != nil )

} return fh, nil

}

rotate_nolock函式修改後為:

func (rl *rotatelogs) rotate_nolock(filename string) error 

var guard cleanupguard

guard.fn = func()

defer guard.run()

if rl.linkname != ""

if err := os.rename(tmplinkname, rl.linkname); err != nil

} if rl.maxage <= 0 && rl.rotationcount <= 0

// andy begin

//matches, err := filepath.glob(rl.globpattern)

dirname := filepath.dir(filename)

matches, err := filepath.glob(dirname + "/*.log")

// andy end

if err != nil

cutoff := rl.clock.now().add(-1 * rl.maxage)

var tounlink string

for _, path := range matches

fi, err := os.stat(path)

if err != nil

fl, err := os.lstat(path)

if err != nil

if rl.maxage > 0 && fi.modtime().after(cutoff)

if rl.rotationcount > 0 && fl.mode()&os.modesymlink == os.modesymlink

} if rl.rotationcount > 0

tounlink = tounlink[:len(tounlink)-int(rl.rotationcount)]

} if len(tounlink) <= 0

guard.enable()

go func()

}()return nil

}

其中帶andy注釋的是修改的。

用到的判斷是否輪轉的自定義函式為:

// andy begin

func needrotate(rl *rotatelogs, filename string) (error, bool)

if rl.lastlogcreatetime.after(rotatetime)

//modify to rename current log file

renametimestr := rl.lastlogcreatetime.format("2006.01.02")

renamefilename := strings.split(filename, ".log")[0] + "_" + renametimestr + ".log"

if err := os.rename(filename, renamefilename); err != nil

return nil, true

}// andy end

可以看到這裡我的判斷就有點硬了,日誌格式直接是到天的,這兒你按照你的需求來。

以上修改的**了,不多,本來也不是多大的修改。不過有點需要說的是,這種改法在一種場景下會有點兒瑕疵,在輪轉時的檔案重新命名上。就是當系統重啟時,已經存在乙個老的pai-customer.log檔案,但因為重啟了,這個檔案的建立日期就丟了,這時我是把它的最後修改時間當成了建立日期的,所以會導致這個檔案被多寫入一天的時間(在我這兒是一天,你那兒就看你輪轉週期了)。這裡是應該寫入檔案的建立日期的,本來在mac上調通了,但上線後發現linux平台檔案的狀態資訊結構體stat_t裡就沒有建立日期birthspectime這個變數(或者需要特殊的檔案格式和拿法,mac上有),於是作罷,就換了現在這種輪轉策略。

日拱一卒,功不唐捐~

linux系統日誌檔名

var log cron 定時日誌檔案 var log dmesg 記錄系統在開機的時候核心檢測過程所產生的各項資訊,由於centos預設講開機時核心的硬體檢測過程取消顯示,因此額外將資料記錄乙份在這個資料夾中 var log maillog 或 var log mial 記錄郵件往來資訊 var ...

log4c 在程式中設定日誌檔名

使用過log4c的人都知道,log4c的需要引數是通過logcrc配置檔案設定的。例如 紅色字的設定的日誌檔案的名稱。如果日誌檔案名字在程式就不能改變了。我想要通過程式改變日誌檔案的名字。在網上查了一下,寫的都比較基礎。外文的資料也懶得去看。看了log4c的例子裡也沒有介紹。所以自己研究了一下原始碼...

Qt下編寫日誌模組(同時記錄檔名 函式名 行數)

說來慚愧,一直以來,我都是使用乙個單例模式來完成日誌模組,具體操作就是呼叫單例的寫檔案函式,自己編輯日誌內容,記錄在日誌檔案裡。這種做法不利於查詢除錯。而使用qt內建的qinstallmessagehandler函式,重新編輯除錯函式的輸出內容才是簡單高效的做法。名字很高大上,其實大家都在使用的qd...