本文探討在大規(guī)模日志數(shù)據(jù)收集過程中络它,針對(duì)日志文件的處理需要注意的技術(shù)細(xì)節(jié)斤寂。
1. 通配符和目錄遞歸搜索
大多數(shù)場(chǎng)景下仿贬,日志往往被分散在不同的目錄中,比如以日期為名的目錄坠韩。因此,工具必需支持對(duì)目錄的遞歸搜索和某種模式匹配炼列。
POSIX
標(biāo)準(zhǔn)定義了一組用于通配的特殊符號(hào)(Pattern Matching Notation):
- *:匹配一個(gè)或多個(gè)字符
- ?:匹配一個(gè)字符
- []:匹配一個(gè)在范圍內(nèi)的字符
- [!]:匹配一個(gè)不在范圍內(nèi)的字符
在shell
中很多常見命令都可以應(yīng)用這種模式匹配規(guī)則只搁,比如:
find / -name "*.so"
作為日志收集工具,也需要能夠做到這種匹配唯鸭,從而對(duì)日志進(jìn)行初步篩選须蜗。在Unix系統(tǒng)中,可以使用fnmatch函數(shù)實(shí)現(xiàn)目溉。
2. 熱日志分析
日志的其中一個(gè)特點(diǎn)是:往往同時(shí)只有少數(shù)的日志文件正在寫入明肮,大部分日志文件都不是正在寫入狀態(tài)。那么在收集日志的時(shí)候缭付,為了降低資源的消耗柿估,需要有一種機(jī)制來判斷哪些是“熱更新”
的日志,只對(duì)熱更新日志進(jìn)行讀取陷猫。我們采用的方式是秫舌,如果在若干次采樣周期內(nèi),發(fā)現(xiàn)讀取文件都是EOF
绣檬,那么認(rèn)為這個(gè)文件屬于冷日志足陨,并將其剔除出熱日志隊(duì)列,并加入一個(gè)新的日志文件作為熱日志文件娇未,循環(huán)往復(fù)墨缘。這樣,大多數(shù)情況下,即保證了實(shí)時(shí)性镊讼,又降低了資源的無效損耗宽涌。
3. 新文件檢測(cè)
對(duì)于采集一個(gè)目錄下的文件
這種需求,必需要考慮到新文件增加的情況蝶棋。通常設(shè)置一個(gè)間隔時(shí)間(比如2s
)卸亮,對(duì)目錄進(jìn)行一個(gè)遍歷,然后對(duì)比當(dāng)前已經(jīng)被納管的文件玩裙,看是不是新文件兼贸。如果是新文件,應(yīng)立刻加入到熱文件隊(duì)列
吃溅,因?yàn)樾碌奈募鶗?huì)立刻被寫入數(shù)據(jù)寝受。這里采用hashmap
能提高對(duì)比性能。
4. 采集點(diǎn)保存
程序總會(huì)因?yàn)槟撤N原因退出罕偎,但是采集任務(wù)往往并沒有結(jié)束很澄,這個(gè)時(shí)候,程序就需要有能力記錄下一些信息颜及,以便下一次繼續(xù)從結(jié)束的點(diǎn)開始工作甩苛,以防止重復(fù)采集。針對(duì)每個(gè)文件俏站,記錄當(dāng)前讀取到的offset
讯蒲,并在程序退出時(shí),及時(shí)刷寫進(jìn)磁盤肄扎。
5. log rotate的探測(cè)
log rotate
是常用的一種日志策略墨林。當(dāng)達(dá)到rotate
的條件時(shí),當(dāng)前正在寫入的文件會(huì)重命名犯祠,并且不再寫入數(shù)據(jù)旭等;然后創(chuàng)建一個(gè)新的文件來繼續(xù)寫入。當(dāng)文件數(shù)量超過一定量時(shí)衡载,將最早產(chǎn)生的文件刪除搔耕,這樣能防止日志無限制暴漲造成文件系統(tǒng)空間浪費(fèi)。
基于log rotate
的特點(diǎn)(會(huì)產(chǎn)生重命名文件的情況)痰娱,日志工具可以通過記錄并對(duì)比inode
來判斷文件是否是重命名的弃榨。
6. 歸檔模式采集
遍歷和watch
一個(gè)擁有百萬級(jí)文件個(gè)數(shù)的目錄,是件十分浪費(fèi)資源的事情梨睁。因?yàn)榫ňΓ瑢?shí)際情況下,這種目錄的數(shù)據(jù)都是歷史數(shù)據(jù)坡贺,而且不會(huì)發(fā)生變化官辈。因此划咐,日志工具應(yīng)當(dāng)能夠支持我們稱為歸檔模式
的工作模式,這種模式下钧萍,遍歷和watch
目錄將采用極低的頻次,這樣不會(huì)浪費(fèi)資源政鼠。
7. 文件狀態(tài)異常
文件狀態(tài)異常是指下列可能的情況:
- 讀取文件的權(quán)限發(fā)生變化
- 讀取文件時(shí)發(fā)生某種錯(cuò)誤
程序應(yīng)避免對(duì)這種文件“一刀切”
风瘦,因?yàn)榭赡苓^一段時(shí)間文件又變成正常狀態(tài)了。所以公般,應(yīng)當(dāng)定期把有問題的文件再嘗試讀取万搔,這樣不會(huì)遺漏。
8. 字符集的探測(cè)和轉(zhuǎn)化
在一些老的系統(tǒng)中官帘,日志的編碼格式依舊會(huì)采用本地編碼瞬雹。典型的是GBK
編碼的日志。在日志上報(bào)的過程中刽虹,應(yīng)采用統(tǒng)一的編碼格式酗捌。幾乎所有的系統(tǒng)都支持libiconv
庫(kù),這是一個(gè)可進(jìn)行編碼轉(zhuǎn)化的常用庫(kù)涌哲。
9. 多行合并
日志數(shù)據(jù)由應(yīng)用程序生成胖缤,?許多應(yīng)用程序在寫入日志的時(shí)候,一條邏輯日志包含多行阀圾。比如下面的java
異常日志哪廓,打印出了堆棧的信息:
11 五月 2016 11:35:52,602 ERROR java.lang.IllegalArgumentException: No bean specified
at org.apache.commons.beanutils.PropertyUtilsBean.getNestedProperty(PropertyUtilsBean.java:632)
at org.apache.commons.beanutils.PropertyUtilsBean.getProperty(PropertyUtilsBean.java:715)
at org.apache.commons.beanutils.PropertyUtils.getProperty(PropertyUtils.java:290)
at lib.util.BeanUtil.getBeanProperty(BeanUtil.java:184)
at lib.comm.services.CommWebService.getResponse(CommWebService.java:173)
at lib.comm.services.CommWebService.SendSimplePack(CommWebService.java:307)
at lib.comm.services.CommWebService.exchange(CommWebService.java:40)
at lib.comm.CommunicationUtil.exchange(CommunicationUtil.java:46)
at lib.comm.CommunicationUtil.exchangeFull(CommunicationUtil.java:105)
at lib.helper.TradeHelper.tellerBasicInfoQuery(TradeHelper.java:1520)
從日志收集程序的角度,這里有很多行初烘,但是涡真,此時(shí)如果按行來分割是完全不行的。因此肾筐,應(yīng)當(dāng)提供一種可以合并多行日志為一行日志的能力哆料。注意到這個(gè)日志以一個(gè)時(shí)間為開始(通常都是這樣),那么我們就可以設(shè)置一個(gè)正則匹配規(guī)則吗铐,匹配到就認(rèn)為是一個(gè)邏輯日志行的開始:
/\d{2} \S+ \d{4} \d{2}:\d{2}:\d{2},\d{3}/
這樣收集上來的日志才便于處理和分析剧劝。通過靈活的設(shè)置正則,極大的降低了后端處理日志的難度抓歼。
10. Follow Symbolic Link
采集器能夠支持一個(gè)開關(guān)讥此,用于設(shè)置是否對(duì)鏈接進(jìn)行跟蹤,即讀取鏈接實(shí)際指向的文件或目錄谣妻。
其實(shí)萄喳,此外還有很多亮點(diǎn)功能值得探討,比如:
- 對(duì)歷史的歸檔日志(tar包)蹋半,直接讀取歸檔壓縮文件他巨,從而避免先解壓再讀取的麻煩。
- 在通配模式下,排除(exclude)或包含(include)某些特殊日志