如果想對一些偏大型或復(fù)雜場景進(jìn)行分析羊异,而又缺乏系統(tǒng)的日志收集檢索系統(tǒng),此時就需要借助腳本(Shell、Python桥胞、PhP 等)來幫助我們進(jìn)行日志分析,本文主要講解如何通過 Shell 來進(jìn)行日志分析考婴,并介紹一些比較高效的方法贩虾。
grep 命令
首先為你講解一個常用命令 grep , grep 是 Linux 常用對日志文件進(jìn)行篩選查找的命令沥阱。它的常用使用方式是這樣的:
grep [選項(xiàng)] PATTERN filename
grep 后面加具體的執(zhí)行選項(xiàng)缎罢,然后加上要查找的內(nèi)容(PATTERN),PATTERN 可以是模式匹配的關(guān)鍵文字內(nèi)容或正則表達(dá)式考杉,filename 就是查找的目標(biāo)文件名稱策精。
這是 grep 的一種典型使用方式,除此之處 grep 也支持使用(command1|grep [選項(xiàng)] PATTERN)使用方式崇棠,這個在前面的課時我們多次應(yīng)用到咽袜。
接下來我們主要講一講,grep 對文件的查找都有哪些具體的選項(xiàng)枕稀?
-i询刹,表示可以忽略大小寫,也就是可以忽略查找的文字的大小寫萎坷,不管大寫還是小寫范抓,只要匹配這個字符串的文字都可以被篩選出來。
-l(小寫字母 l)食铐,它表示結(jié)果中只顯示含有匹配內(nèi)容的文件名稱或路徑匕垫。
-R,遞歸查詢虐呻,查找在某一級目錄下象泵,有多少個文件內(nèi)容里含有指定的內(nèi)容字符串時寞秃,它可以在一個目錄層級下發(fā)起遞歸性查詢。
-o偶惠,表示結(jié)果中打印匹配出的內(nèi)容春寿。
-B,表示查找在匹配關(guān)鍵字符串之前忽孽,有多少行內(nèi)容绑改。
-A,表示匹配關(guān)鍵字的這一行之后有多少行內(nèi)容兄一。如果我們把 -B 和 -A 都同時加上厘线,比如 -B2 和 -A2,就會把匹配關(guān)鍵字的前 2 行和后 2 行內(nèi)容整體打印顯示出來出革。
以上這就是 grep 里的一些常見選項(xiàng)造壮,我們來看一個 grep 的正則匹配,需要使用 grep -E 或 egrep 命令骂束,可以直接進(jìn)行正則的匹配耳璧。
這里有一個匹配正則表達(dá)式的樣例:
egrep ‘[^0][0-9]{0,2}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}’ ./test -c
如上的 egrep 命令,單引號里是具體的正則表達(dá)式([^0][0-9]{0,2}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3})展箱,‘./test’ 表示需要查找的目標(biāo)文件旨枯,接下來我們分析正則表達(dá)式是什么作用。
從左到右分析混驰,首先拆開分析這樣的一段[^0][0-9]{0,2}\攀隔,第一個方括號中的 ^0,它表示匹配第一個數(shù)值是非零開頭的任意數(shù)字账胧,后面是 [0-9],表示第 2 個數(shù)開始先紫,數(shù)值需要 0~9 之間治泥,而 {0,2} 表示限制了第二個數(shù)字開始后面數(shù)字次數(shù)(可以不出現(xiàn)、或出現(xiàn)第二數(shù)遮精、或出現(xiàn)到第三個數(shù)) 居夹,它表述允許[0-9]數(shù)值出現(xiàn)的范圍。
通過一個小數(shù)點(diǎn)分割后本冲,是這樣的一段 [0-9]{1,3}\准脂,匹配原理也是一樣。
通過整個這樣的一串表達(dá)式檬洞,查找 test 文件里是否有 IP 地址狸膏,并把匹配 IP 地址的行信息全部都打印出來。
awk 命令
第 2 個介紹命令就是 awk添怔,它是一個非常強(qiáng)大的文件分析工具和編程語言湾戳,可以逐行掃描文件贤旷,從第一行到最后一行尋找匹配的特定模式的行,并在這些行上進(jìn)行想要的操作砾脑。
具體的使用方式是這樣的:
awk ‘pattern’ filename
awk 后面加想要匹配的文件內(nèi)容幼驶,然后再加這個文件的路徑或者名稱。
示例:awk -F: ‘/root/’ /etc/passwd
如上有一個使用事例韧衣,awk -F:盅藻,它表示查找 /etc 下的 passwd 文件,這里會以冒號進(jìn)行內(nèi)容上按列分割畅铭,然后前面加了一個匹配的內(nèi)容(pattern)氏淑,/root/ 表示是查找 /etc/ passwd 文件內(nèi)容是否包含 root 這個關(guān)鍵字,然后打印對應(yīng)的行打印顶瞒。
第 2 個使用方式是:
awk ‘{action}’ filename
示例:awk -F: ‘{print $1}’ /etc/passwd
我們同樣看一下這個示例夸政,這里的 {print $1},$1 表示打印 /etc/passwd 文件中每行的第 1 列(及系統(tǒng)上的用戶名)榴徐。
第3種使用方式是:
awk ‘pattern {action}’ filename
我們看到它既做了查找守问,后面又做了 action。這個方式會更加全面坑资。這里同樣有一個例子:
awk -F: ‘/root/{print $1,$3}’ /etc/passwd
首先它會做一個查找耗帕,匹配有 root 關(guān)鍵字的這一行,然后打印它的第 1 列和第 3 列袱贮,這里 awk 在這里既做關(guān)鍵詞的匹配仿便,也做了 action({print $1,$3})。
經(jīng)驗(yàn)來看攒巍,awk 的強(qiáng)大主要體現(xiàn)在它的 action (動作指令)嗽仪,它可以對文件內(nèi)容進(jìn)行豐富靈活的處理,關(guān)于action的使用格式可以細(xì)分如下:
格式1:BEGIN{} {} END{}
BEGIN{} 表示在 awk 處理行前柒莉,需要執(zhí)行的動作闻坚。中間的 {} 表示在 awk 執(zhí)行過程中,所需要執(zhí)行的動作兢孝,END{} 表示處理完所有內(nèi)容以后的動作窿凤。
值得注意的是:實(shí)際使用 action 這種格式中,BEGIN{} 和 END{} 我們可以選擇不加跨蟹。
我們來看一下這個案例:
awk -F: 'length($1)==5{count++;print $1}END{print "count is: "count}' /etc/passwd
它只加了中間括號 {} 和 END{}雳殊,在這個樣例的 awk 里面,它對 passwd 文件做了一個操作窗轩,用來匹配 /etc/passwd 里每一行第 1 列的內(nèi)容(Linux 系統(tǒng)用戶名)長度是否等于 5夯秃,如果是等于 5涎显,則說明匹配到要求的條件(length($1)==5)课梳。條件成立以后在處理過程中會做一個計數(shù)(count++)攀细,并把第 1 列的內(nèi)容打印出來寂曹,執(zhí)行完 awk 以后,再把 count 的結(jié)果打印出來衬潦,我們就知道總體的匹配有多少個斤蔓。
這就是 awk 的技術(shù)樣例。那么再來看一下這樣的一個樣例:
Cat xxx.log|awk 'BEGIN{max=0;min=1}
{if ($4 ~ /jeson/ && $8==200){
sum+=$NF; count+=1;
if($9 > max) max=$9 fi;if($9 < min) min=$9 fi;
}
}
END {print "Average = ", sum/count;print "Max = ", max;print "Min", min}'
進(jìn)行性能分析時镀岛,通常需要對 Nginx 的 access 日志進(jìn)行響應(yīng)時間的分析弦牡,如果我們想了解某一個接口它總體的情況,如最大響應(yīng)時間是多久漂羊,最小的響應(yīng)時間是多久驾锰,或者它的平均響應(yīng)時間是多久,這時就可能需要通過 awk 來對日志進(jìn)行整體分析走越,這里來看一下椭豫。
補(bǔ)充:xxx.log的日志格式:
log_format? main? '$remote_addr - $remote_user [$time_local] "$request" '
? ? ? ? ? ? ? ? ? ? ? '$status $body_bytes_sent "$http_referer" '
? ? ? ? ? ? ? ? ? ? ? ‘“$http_user_agent” “$http_x_forwarded_for” $upstream_response_time';
這里的使用方式是這樣的:
首先 cat 一個日志,把日志整打印出來旨指,然后通過管道符給 awk 處理赏酥,這里就用到了 BEGIN{} 這個 action 行為,然后還有中間的括號行為谆构,以及 END{}裸扶。
接下來 BEGIN action(max=0;min=1) 表示的是在執(zhí)行 awk 之前所需要進(jìn)行預(yù)處理的部分搬素,這里先設(shè)置變量 max 等于 0呵晨,還有一個最小的值 min 等于 1。在進(jìn)行處理中的括號里會有一個整體的語句進(jìn)行判斷熬尺,判斷 $4(也就是 Cat xxx.log 這個文件的第 4 列是否匹配關(guān)鍵字 jeson)摸屠,同時還要滿足另外一個條件 $8==200(也就是 Nginx log 里面的返回狀態(tài)碼是否滿足 200)。如果這兩個條件都成立粱哼,這個時候就會用 sum 進(jìn)行計數(shù)季二,$NF 表示日志里面最后一列的內(nèi)容,sum+=$NF 表示 upstream_response_time 的數(shù)值進(jìn)行累加皂吮,得到整體 upstream_response_time 的時間戒傻,也就是將 Nginx 轉(zhuǎn)發(fā)到后端所有請求響應(yīng)時間求和税手,賦值給 sum 變量蜂筹。count+=1 表示 count 同時做一個計數(shù)器來自增。
if($9 > max) max=$NF fi;if($NF < min) min=$NF 芦倒,接下來會做一個判斷艺挪,判斷 $NF(也就是最后的響應(yīng)時間)是否大于 max(第一次是默認(rèn)值 0),如果大于 0 的話,那么它會把 max 的值重新替換麻裳。同樣口蝠,也會和最小值進(jìn)行比較,如果它小于最小值津坑,就又會把最小變量 min 做一個替換妙蔗,從而循環(huán)的去進(jìn)行判斷,通過每一個請求拿到整體最大請求和最小請求的時間疆瑰,并且都賦值到對應(yīng)的變量里去眉反,分別是 count、sum穆役、max 和 min寸五。
END {print "Average = ", sum/count;print "Max = ", max;print "Min", min}'
最后再整體把它的結(jié)果輸出,這里就用到了 END 后面的括號了耿币。它會把這個文件內(nèi)容里面的平均響應(yīng)時間求出來梳杏,通過 sum 變量,用整體的響應(yīng)時間除以請求個數(shù)(sum/count)淹接,這樣就得到了一個平均的響應(yīng)時間十性。然后把 max 變量打印出來,得到了最大響應(yīng)時間蹈集。min 這個時變量打印出來就是最小打印時間烁试。
ag 命令
接下來還要為你介紹一個文件分析命令 ag,ag 命令相比 awk 和 grep 命令來我們感覺會更加新鮮拢肆,它的優(yōu)勢是性能比 grep 和 awk 做文件查找會更高效减响,并它默認(rèn)支持正則方式,而不用通過 egrep 這種在里面加一些 -e 的選項(xiàng)郭怪,可以直接進(jìn)行正則匹配支示。
ag 使用選項(xiàng),跟 grep 命令基本上都是一致的鄙才。我們可以看一下:
-A 表示查找指定行的后多少行颂鸿。
-B 表示查找指定行的前面有多少行。
-context 表示匹配特定行的前后多少行攒庵。
等等嘴纺,基本上和 grep 的命令選項(xiàng)的功能是幾乎一致的。
接下來我們演示一個 Shell 作日志分析的腳本浓冒,它用到了 ag 命令的使用方式栽渴,Shell 腳本里,大部分對于文件關(guān)鍵字的查找都是基于 ag 命令來實(shí)現(xiàn)的稳懒。
這個Shell 腳本主要可以實(shí)現(xiàn)這樣的一些功能:
1闲擦、統(tǒng)計 Top 20 地址
2、SQL 注入分析
3、SQL 注入 FROM 查詢統(tǒng)計
4墅冷、掃描器/常用黑客工具
5纯路、漏洞利用檢測
6、敏感路徑訪問
7寞忿、文件包含攻擊
8驰唬、Web Shell
9、尋找響應(yīng)長度的 URL Top 20
10腔彰、尋找罕見的腳本文件訪問
11定嗓、尋找 302 跳轉(zhuǎn)的腳本文件
整體 Nginx 的日志進(jìn)行分析,接下來登錄到一臺測試機(jī)上面萍桌,然后 cd t21 目錄下宵溅,有一個 nginx_check.sh 的 Shell 腳本。
我們首先來介紹一下 Shell 腳本的整體結(jié)構(gòu)上炎,最上面的這一段語句是做一個文件路徑(/tmp/logs)的判斷恃逻,如果存在的話,就會先把之前的文件做一個清空藕施。
這是因?yàn)閳?zhí)行日志分析的腳本時寇损,會把每一項(xiàng)的功能得到的統(tǒng)計結(jié)果,輸出到 tmp 路徑下面的 logs 目錄下裳食,并且以對應(yīng)的文件名進(jìn)行歸納矛市。當(dāng)我們執(zhí)行完腳本以后,想要了解每一項(xiàng)結(jié)果內(nèi)容的時候诲祸,就可以到該路徑下面去查看對應(yīng)的結(jié)果浊吏。
這里需要填寫 Nginx 的 access 日志目錄,用于分析的文件 access 日志路徑救氯。接下來做日志路徑判斷找田,如果日志路徑不存在,那么腳本執(zhí)行就會中斷退出着憨。
再往下看的話墩衙,這里就是做系統(tǒng)版本檢測,這個腳本需要在 Debian 操作系統(tǒng)或者 Ubuntu 甲抖、Centos 這樣的操作系統(tǒng)上漆改,如果操作系統(tǒng)不能滿足的話也會退出。
接下來就要用到我們剛剛講到的 ag 命令准谚。在沒有 ag 命令情況下挫剑,腳本會先提示并進(jìn)行安裝,對應(yīng)的使用 Yum 或者是 apt get 包管理器安裝氛魁。
下面就具體每一項(xiàng)的功能分析:
這里分析的就是訪問 Top20 的 IP 地址暮顺,那么 ag 命令就做一個正則匹配,把所有的地址打印出來秀存,然后通過 sort 來進(jìn)行排序捶码,uniq 來進(jìn)行統(tǒng)計,然后再得到由大到小的結(jié)果或链,并且過濾出前 20 行數(shù)惫恼,然后同時把內(nèi)容給到 tee 這個命令,它會把輸出內(nèi)容重定向到日志結(jié)果目錄(/tmp/logs/top20.log)澳盐,整體執(zhí)行完畢后祈纯,如果我們想要看這一項(xiàng)分析結(jié)果的話,那么就可以在 log 目錄下 Top20.log 文件里查看叼耙。另外 tee 命令還可以支持在終端輸出腕窥,也就是既把結(jié)果放在終端輸出。
所以這樣就完成了第 1 項(xiàng)的日志功能分析筛婉,分析出訪次數(shù)問前 20 的 IP 地址簇爆,并且打印。后面的每一項(xiàng)功能分析其實(shí)都是類似的原理爽撒,通過 ag 命令來對文件進(jìn)行關(guān)鍵字查找入蛆,并且進(jìn)行分析和統(tǒng)計。
好了硕勿,最后執(zhí)行 sh nginx_check.sh哨毁,就可以開始 nginx access 日志來分析,我們在控制臺終端關(guān)注它的執(zhí)行過程和進(jìn)度源武,并且在結(jié)果目錄中詳細(xì)分析日志得到的結(jié)果內(nèi)容扼褪。