針對Nginx日誌的相關運維操作記錄

散盡浮華發表於2018-02-28

 

在分析伺服器執行情況和業務資料時,nginx日誌是非常可靠的資料來源,而掌握常用的nginx日誌分析命令的應用技巧則有著事半功倍的作用,可以快速進行定位和統計。

1)Nginx日誌的標準格式(可參考:http://www.cnblogs.com/kevingrace/p/5893499.html

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '  
             '$status $body_bytes_sent "$http_referer" '  
             '"$http_user_agent" $request_time';  

記錄的形式如下: 

192.168.28.22 - - [28/Feb/2018:04:01:11 +0800] "GET /UserRecommend.php HTTP/1.1" 200 870 "http://wwww.kevin.www/grace/index.html" 
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)" 320 

日誌格式說明:
$remote_addr             遠端請求使用的IP地址
$remote_user             遠端登入名
$time_local                 時間,用普通日誌時間格式(標準英語格式)
$request                     請求的第一行
$status                       狀態。
$body_bytes_sent     請求返回的位元組數,包括請求頭的資料
$http_referer             請求頭Referer的內容
$http_user_agent     請求頭User-Agent的內容
$request_time           處理完請求所花時間,以秒為單位

==============================================================
Apache日誌的標準格式

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %T " combined  
    CustomLog log/access_log combined  

記錄的形式如下: 

192.168.28.23 - frank [28/Feb/2018:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.example.com/start.html" 
"Mozilla/4.08 [en] (Win98; I ;Nav)" 

日誌格式說明:
%h     請求使用的IP地址
%l      遠端登入名(由identd而來,如果支援的話),除非IdentityCheck設為"On",否則將得到一個"-"。
%u     遠端使用者名稱(根據驗證資訊而來;如果返回status(%s)為401,可能是假的)
%t      時間,用普通日誌時間格式(標準英語格式)
%r      請求的第一行
%s     狀態。對於內部重定向的請求,這個狀態指的是原始請求的狀態,---%>s則指的是最後請求的狀態。
%b      以CLF格式顯示的除HTTP頭以外傳送的位元組數,也就是當沒有位元組傳送時顯示'-'而不是0。
\"%{Referer}i\"     傳送到伺服器的請求頭Referer的內容。
\"%{User-Agent}i\"     傳送到伺服器的請求頭User-Agent的內容。
%T      處理完請求所花時間,以秒為單位。
%I       接收的位元組數,包括請求頭的資料,並且不能為零。要使用這個指令你必須啟用mod_logio模組。
%O     傳送的位元組數,包括請求頭的資料,並且不能為零。要使用這個指令你必須啟用mod_logio模組。

=======================================================

2)Nginx日誌切割

#!/bin/sh   
# 設定日誌檔案備份檔名    
#logfilename=`date +%Y%m%d`  
logfilename=`date +\%Y\%m\%d -d "1 days ago"`  
# 設定日誌檔案原始路徑    
logfilepath=/opt/nginx/logs/  
# 設定日誌備份檔案路徑  
backupfilepath=/opt/data/logs/nginx/  
  
LOG_FILE='access error log_mm log_db'  
for j in $LOG_FILE  
do  
        cd ${logfilepath}  
        tar zcvf ${backupfilepath}$j/${logfilename}.tar.gz $j.log  
        rm -rf $j.log  
done  
  
kill -USR1 `cat  /opt/nginx/nginx.pid  

===================================================
apache日誌切割

#!/bin/bash  
# 獲取昨天的日期  
logfilename=`date -d yesterday +%Y_%m_%d`  
today=`date +%Y.%m.%d`  
# 設定日誌檔案原始路徑    
logfilepath=/opt/apache2/logs/  
# 設定日誌備份檔案路徑  
backupfilepath=/opt/data/logs/apache/  
  
echo "get access log:"  
# 打包壓縮訪問日誌檔案  
cd ${logfilepath}  
tar zcvf ${backupfilepath}access/${logfilename}.tar.gz access_${logfilename}.log  
rm -rf access_${logfilename}.log  
  
echo "get error log:"  
# 打包壓縮錯誤日誌檔案  
cd ${logfilepath}  
tar zcvf ${backupfilepath}error/${logfilename}.tar.gz error_${logfilename}.log  
rm -rf error_${logfilename}.log  
  
echo "done @"${today}  

==========================================================

3)日誌定時清理的指令碼

#!/bin/sh  
####################### clear logs #########################  
### nginx ###  
#clear nginx access log(by hour .log) 2 days ago   
/usr/bin/find /opt/data/logs/nginx/access -mtime +2 -name "access.log*" -exec rm -rf {} \;  
  
#clear nginx (access,error,log_mm,log_db) log(by day tar.gz) 10 days ago  
NGINX='access error log_mm log_db'  
for i in $NGINX  
do  
        /usr/bin/find /opt/data/logs/nginx/$i -mtime +10 -name "*tar.gz" -exec rm -rf {} \;  
done  
  
### apache ###   
#clear apache (access,error) log(by day tar.gz) 10 days ago  
APACHE='access error'  
for j in $APACHE  
do  
        /usr/bin/find /opt/data/logs/apache/$j -mtime +10 -name "*tar.gz" -exec rm -rf {} \;  
done  
  
### other log ###  
#clear (txt/mq,txt/auto,txt/man) log(by day .log) 10 days ago  
OTHER='txt/mq txt/auto txt/man'  
for k in $OTHER  
do  
        /usr/bin/find /opt/data/logs/$k -mtime +10 -name "*log" -exec rm -rf {} \;  
done  

=============在分析nginx日誌時常用命令總結=============

1. 利用grep ,wc命令統計某個請求或字串出現的次數

比如統計GET /app/kevinContent介面在某天的呼叫次數,則可以使用如下命令: 
[root@Fastdfs_storage_s1 ~]# cat /usr/local/nginx/logs/access.log | grep 'GET /app/kevinContent' | wc -l

其中cat用來讀取日誌內容,grep進行匹配的文字搜尋,wc則進行最終的統計。 
當然只用grep也能實現上述功能:
[root@Fastdfs_storage_s1 ~]# grep 'GET /app/kevinContent'  /usr/local/nginx/logs/access.log -c

2. 統計所有介面的呼叫次數並顯示出現次數最多的前二十的URL

[root@Fastdfs_storage_s1 ~]# cat /usr/local/nginx/logs/access.log|awk '{split($7,b,"?");COUNT[b[1]]++;}END{for(a in COUNT) print  COUNT[a], a}'|
sort -k1 -nr|head -n20 

2722 /
10 /group1/M00/00/00/wKgKylqT3OCAUrqYAAAwK2jUNaY262.png
9 /group1/M00/00/00/wKgKylqUxBOAFo8hAAKHUIZ3K9s443.jpg
6 /group1/M00/00/00/wKgKylqUrceAGkPOAAAwK2jUNaY843.png
4 /group1/M00/00/00/wKgKylqTsFCAdeEuAAKHUIZ3K9s287.png
3 /group2/M00/00/00/wKgKy1qUtu2Acai1AAKHUIZ3K9s555.jpg
2 /favicon.ico
1 /group2/M00/00/00/wKgKy1qT3P-Ae-vQAAKHUIZ3K9s459.png
1 /group2/M00/00/00/wKgKy1qT3P-Ae-vQAAKHUIZ3K9s459.jpg
1 /group1/M00/00/00/wKgKylqUyMuAdkLwAAAwK2jUNaY176.png
1 /group1/M00/00/00/wKgKylqUtuyAA5xrAAKHUIZ3K9s226.jpg
1 /group1/M00/00/00/wKgKylqUscKAa4NXAAKHUIZ3K9s530.jpg
1 /group1/M00/00/00/wKgKylqTsFCAdeEuAAKHUIZ3K9s287.jpg
1 /group1/M00/00/00/wKgKylqT4ESAHdNjAAKHUIZ3K9s730.jpg
1 /group1/M00/00/00/wKgKylqT3-6AbEeUAAKHUIZ3K9s742.png

解釋說明:
這裡awk是按照空格把每一行日誌拆分成若干項,其中$7對應的就是URL,當然具體對應的內容和使用nginx時設定的日誌格式有關。
這樣就可以通過拆分提取出IP,URL,狀態碼等資訊。split是awk的內建函式,在此的意思是按照“?”將URL進行分割得到一個陣列,並賦值給b。
COUNT[b[1]]++表示相同的介面數目加1。sort用來排序,-k1nr表示要把進行排序的第一列作為數字看待,並且結果倒序排列。
head -n20意為取排名前二十的結果。

3. 統計報錯的介面 

統計nginx日誌中報錯較多的介面,對於分析伺服器的執行情況很有幫助,也可以有針對性的修復bug和效能優化。
[root@Fastdfs_storage_s1 ~]# cat /usr/local/nginx/logs/access.log|awk '{if($9==500) print $0}'|
awk '{split($7,b,"?");COUNT[b[1]]++;}END{for(a in COUNT) print  COUNT[a], a}'|sort -k 1 -nr|head -n10

先用awk’{if(9==500)print0}’過濾出500錯誤的日誌,然後在此基礎上做統計,其思路同2類似!

4. 統計HTTP響應狀態碼

通過統計響應狀態碼可以看出伺服器的響應情況,比如499較多時可以判斷出伺服器響應緩慢,再結合3可以找出響應慢的介面,
這樣就能有針對性進行效能分析和優化。

[root@Fastdfs_storage_s1 ~]# cat /usr/local/nginx/logs/access.log |awk '{counts[$(9)]+=1}; END {for(code in counts) print code, counts[code]}' 
| sort -k 2 -nr

200 2733
304 20
404 11

5. 統計伺服器併發量

[root@Fastdfs_storage_s1 ~]# cat /usr/local/nginx/logs/access.log |grep '10.15.19.138'| awk '{COUNT[$4]++}END{for( a in COUNT) print a,COUNT[a]}'
|sort -k 2 -nr|head -n20

nginx轉發請求時可以記錄響應請求的伺服器IP,先通過grep過濾出某個伺服器所有的請求,然後統計各個時間點的併發請求響應的數量即可得到某個伺服器的併發量。
$4對應的是響應時間。當然,如果把grep的內容更換成某個介面也就可以統計出該介面對應的併發量了。

6. grep多條件與或操作

有時候我們需要在nginx日誌通過多個條件來查詢某些特定請求,比如我需要找個某個使用者瀏覽文章的請求,則可以需要同時匹配兩個條件:
瀏覽文章介面GET /app/kevinContent和userId=59h7hrrn。

grep對應的與操作命令如下:
[root@Fastdfs_storage_s1 ~]# grep -E "GET /app/kevinContent.*userId=59h7hrrn" /usr/local/nginx/logs/access.log

grep與命令格式: grep -E “a.*b” file,ab條件同時成立 
而grep或命令的格式為:grep -E “a|b” file ,ab兩個條件有一個成立即可。

7. grep列印匹配的前後幾行 

有時候我們需要查詢某個特定請求的前後幾行的請求,以觀察使用者的關聯操作情況。grep提供了一下幾條命令: 
# grep -C 5 'parttern' inputfile    //列印匹配行的前後5行。
# grep -A 5 'parttern' inputfile    //列印匹配行的後5行
# grep -B 5 'parttern' inputfile    //列印匹配行的前5行

grep -An  或grep -A n
grep -Bn  或grep -B n
grep -Cn  或grep -C n

如下,列印出access.log日誌檔案中匹配/app/kevinContent關鍵字元所在行的前後各10行
[root@Fastdfs_storage_s1 ~]# grep -C 10 'GET /app/kevinContent' /usr/local/nginx/logs/access.log

相關文章