本文探討在大規模日誌數據收集過程當中,針對日誌文件的處理須要注意的技術細節。html
大多數場景下,日誌每每被分散在不一樣的目錄中,好比以日期爲名的目錄。所以,工具必需支持對目錄的遞歸搜索和某種模式匹配。java
POSIX
標準定義了一組用於通配的特殊符號(Pattern Matching Notation):node
*:匹配一個或多個字符linux
?:匹配一個字符shell
[]:匹配一個在範圍內的字符apache
[!]:匹配一個不在範圍內的字符後端
在shell
中不少常見命令均可以應用這種模式匹配規則,好比:函數
find / -name "*.so"
做爲日誌收集工具,也須要可以作到這種匹配,從而對日誌進行初步篩選。在Unix系統中,可使用fnmatch函數實現。工具
日誌的其中一個特色是:每每同時只有少數的日誌文件正在寫入,大部分日誌文件都不是正在寫入狀態。那麼在收集日誌的時候,爲了下降資源的消耗,須要有一種機制來判斷哪些是「熱更新」
的日誌,只對熱更新日誌進行讀取。咱們採用的方式是,若是在若干次採樣週期內,發現讀取文件都是EOF
,那麼認爲這個文件屬於冷日誌,並將其剔除出熱日誌隊列,並加入一個新的日誌文件做爲熱日誌文件,循環往復。這樣,大多數狀況下,即保證了實時性,又下降了資源的無效損耗。性能
對於採集一個目錄下的文件
這種需求,必須要考慮到新文件增長的狀況。一般設置一個間隔時間(好比2s
),對目錄進行一個遍歷,而後對比當前已經被納管的文件,看是否是新文件。若是是新文件,應馬上加入到熱文件隊列
,由於新的文件每每會馬上被寫入數據。這裏採用hashmap
能提升對比性能。
程序總會由於某種緣由退出,可是採集任務每每並無結束,這個時候,程序就須要有能力記錄下一些信息,以便下一次繼續從結束的點開始工做,以防止重複採集。針對每一個文件,記錄當前讀取到的offset
,並在程序退出時,及時刷寫進磁盤。
log rotate
是經常使用的一種日誌策略。當達到rotate
的條件時,當前正在寫入的文件會重命名,而且再也不寫入數據;而後建立一個新的文件來繼續寫入。當文件數量超過必定量時,將最先產生的文件刪除,這樣能防止日誌無限制暴漲形成文件系統空間浪費。
基於log rotate
的特色(會產生重命名文件的狀況),日誌工具能夠經過記錄並對比inode
來判斷文件是不是重命名的。
遍歷和watch
一個擁有百萬級文件個數的目錄,是件十分浪費資源的事情。由於,實際狀況下,這種目錄的數據都是歷史數據,並且不會發生變化。所以,日誌工具應當可以支持咱們稱爲歸檔模式
的工做模式,這種模式下,遍歷和watch
目錄將採用極低的頻次,這樣不會浪費資源。
文件狀態異常是指下列可能的狀況:
讀取文件的權限發生變化
讀取文件時發生某種錯誤
程序應避免對這種文件「一刀切」
,由於可能過一段時間文件又變成正常狀態了。因此,應當按期把有問題的文件再嘗試讀取,這樣不會遺漏。
在一些老的系統中,日誌的編碼格式依舊會採用本地編碼。典型的是GBK
編碼的日誌。在日誌上報的過程當中,應採用統一的編碼格式。幾乎全部的系統都支持libiconv
庫,這是一個可進行編碼轉化的經常使用庫。
日誌數據由應用程序生成,許多應用程序在寫入日誌的時候,一條邏輯日誌包含多行。好比下面的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)
從日誌收集程序的角度,這裏有不少行,可是,此時若是按行來分割是徹底不行的。所以,應當提供一種能夠合併多行日誌爲一行日誌的能力。注意到這個日誌以一個時間爲開始(一般都是這樣),那麼咱們就能夠設置一個正則匹配規則,匹配到就認爲是一個邏輯日誌行的開始:
/\d{2} \S+ \d{4} \d{2}:\d{2}:\d{2},\d{3}/
這樣收集上來的日誌才便於處理和分析。經過靈活的設置正則,極大的下降了後端處理日誌的難度。
採集器可以支持一個開關,用於設置是否對連接進行跟蹤,即讀取連接實際指向的文件或目錄。
其實,此外還有不少亮點功能值得探討,好比:
對歷史的歸檔日誌(tar包),直接讀取歸檔壓縮文件,從而避免先解壓再讀取的麻煩。
在通配模式下,排除(exclude)或包含(include)某些特殊日誌