在分析伺服器運作情況和業務資料時,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子產品。
Nginx 日志字段解釋
說明 | 字段名 | 示例 |
主機頭 | $host | 域名 kevin.bo.com |
伺服器ip | $server_addr | 192.168.10.109 |
端口 | $server_port | 80 |
客戶ip | $remote_addr | 172.17.12.18 |
客戶 | $remote_user | - |
時間 | $time_iso8601 | 2018-11-04T10:13:40+09:00 |
狀态碼 | $status | 204 |
發送主體大小 | $body_bytes_sent | |
發送總大小 | $bytes_sent | 140 |
請求總大小 | $request_length | 578 |
請求主體大小 | $request_body | |
請求時間 | $request_time | 0.001 |
請求方式 | $request_method | GET |
uri | $uri | /rest/quickreload/latest/18747370 |
變量 | $args | since=1559180602998&_=1559181197999 |
協定 | $server_protocol | HTTP/1.1 |
cookie | $cookie_nid | |
記錄從哪個頁面連結通路過來 | $http_referer | http://kevin.bo.com/pages/viewpage.action?pageId=18747370 |
用戶端資訊 | $http_user_agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36 |
用戶端真實ip(經過反向代理) | $http_x_forwarded_for | |
編碼 | $http_accept_encoding | gzip, deflate |
目前通過一個連接配接獲得的請求數量 | $connection_requests | 1 |
後端ip | $upstream_addr | 192.168.10.33:8090 |
後端狀态碼 | $upstream_status | |
後端響應時間 | | |
背景緩存 | $upstream_cache_status | |
後端接口狀态 | $upstream_http_x_status | |
配置檔案
log_format main '$host\t$server_addr\t$server_port\t$remote_addr\t'
'$remote_user\t$time_iso8601\t$status\t'
'$body_bytes_sent\t$bytes_sent\t$request_length\t'
'$request_body\t$request_time\t$request_method\t'
'$uri\t$args\t$server_protocol\t$cookie_nid\t'
'$http_referer\t$http_user_agent\t$http_x_forwarded_for\t'
'$http_accept_encoding\t$connection_requests\t$upstream_addr\t'
'$upstream_status\t$upstream_response_time\t$upstream_cache_status\t$upstream_http_x_status';
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
*************** 當你發現自己的才華撐不起野心時,就請安靜下來學習吧!***************