最近在整理對于各個模塊的監(jiān)控,需要有一定的實(shí)時性。比如,需要獲取最近幾分鐘內(nèi)的日志,然后看某些請求的數(shù)量以及響應(yīng)時間是否符合要求。但是,線上服務(wù)的日志,通常都是按照小時粒度進(jìn)行切分的,你不可能對一個文件進(jìn)行直接的過濾操作。在此之前需要解決一個問題:在一份文件中,獲取最近一段時間的日志。
當(dāng)然,還有一個最最基礎(chǔ)的問題:你的日志內(nèi)容里面是表示時間的字段的。(不打時間和請求ID的日志簡直就是耍流氓!)
我一開始的想法是:估算平均請求壓力下,每5分鐘的日志會有多少條,然后直接將cat替換為tail -n XXX就可以了。雖然修改起來很方便,但是是有明顯缺陷的:
- 隨著流量變化,
tail出來的日志的時間粒度是不一樣的。如果用來監(jiān)控實(shí)時請求響應(yīng)時間還算能接受,用來監(jiān)控請求量就不行了; - 如果以后模塊升級,增加或者減少了請求日志,
tail出來的數(shù)字需要不斷調(diào)整。
看來還是要精確的獲取某個時間段的日志才行。其實(shí)思路還是比較清晰的:
- 計算出
開始時間和結(jié)束時間兩個字段 - 提取日志行中的
日志時間 - 比較三個值,如果日志行的時間符合要求,則將其打印,作為過濾程序的輸入
- 執(zhí)行數(shù)日志數(shù)量或者統(tǒng)計請求響應(yīng)時間的命令
對于步驟1,使用date命令就可以獲取,這個簡單。
對于步驟2,一般日志中的時間都會比較在日志前面幾個字段,比較好提取,也不難。
步驟4嘛,就看需求是什么了,如果是獲取請求數(shù)目,直接用grep和wc -l就OK了。如果涉及到提取日志字段,簡單的也可以用cut搞定,復(fù)雜就得用grep或者awk了。
最關(guān)鍵是步驟3如何實(shí)現(xiàn),我想到的是在awk中進(jìn)行邏輯判斷,獲取日志中的時間字段不難,但是如果時間字段是通過多個字段拼接而來的,比如2014-05-02和17:25:00,怎么把他們放到一個變量里面呢?要是有像sprintf這樣的函數(shù)就好了,沒想到,還真有!類似于下面這樣:
cat xxx.log | awk '{t=sprintf("%s %s", $2, $3);}'
還有一個問題,就是如何將BASH中的開始時間和結(jié)束時間變量傳入awk呢?也有辦法的!awk里面有-v選項(xiàng),支持將外部變量傳入其中。那么程序就類似于這樣了:
start_time=`date -d"$last_minutes minutes ago" +"%Y-%m-%d %H:%M:%S"`
end_time=`date +"%Y-%m-%d %H:%M:%S"`
cat xxx.log | awk -v st="$start_time" -v et="$end_time" '{t=sprintf("%s %s", $2, $3); if(t>=st && t<=et){print $0}}'
最后,還有一個小問題,因?yàn)闀ㄆ谇蟹秩罩?,所以需要考慮臨界時間點(diǎn)的情況,把當(dāng)前時間段和上個時間段的日志同時作為輸入即可。
這樣,精確獲取最近一段時間日志的需求就得到解決了。
--EOF--