nginx日志配置与分析
一、access_log日志配置
access_log用来定义日志级别,日志位置。语法如下:
日志级别: debug > info > notice > warn > error > crit > alert > emerg
语法格式:
access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
默认值 : access_log logs/access.log combined;
作用域 : http, server, location, if in location, limit_except
实例一:
access_log /spool/logs/nginx-access.log compression buffer=32k;
二、log_format 定义日志格式
语法格式: log_format name [escape=default|json] string ...;
默认值 : log_format combined "...";
作用域 : http
实例二:
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" "$gzip_ratio"';
access_log /spool/logs/nginx-access.log compression buffer=32k;
常见的日志变量
$remote_addr
,$http_x_forwarded_for
记录客户端IP地址$remote_user
记录客户端用户名称$request
记录请求的URL和HTTP协议(GET,POST,DEL,等)$status
记录请求状态$body_bytes_sent
发送给客户端的字节数,不包括响应头的大小;该变量与Apache模块mod_log_config里的“%B”参数兼容。$bytes_sent
发送给客户端的总字节数。$connection
连接的序列号。$connection_requests
当前通过一个连接获得的请求数量。$msec
日志写入时间。单位为秒,精度是毫秒。$pipe
如果请求是通过HTTP流水线(pipelined)发送,pipe值为“p”,否则为“.”。$http_referer
记录从哪个页面链接访问过来的$http_user_agent
记录客户端浏览器相关信息$request_length
请求的长度(包括请求行,请求头和请求正文)。$request_time
请求处理时间,单位为秒,精度毫秒;从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。$time_iso8601 ISO8601
标准格式下的本地时间。$time_local
通用日志格式下的本地时间。
实例二:
# Nginx 的ngx_http_log_module 模块中log_format 指令,可以帮我们去完成自定义日志的格式。
log_format main '$http_x_real_ip $http_host [$time_local] "$request" $request_length '
'$status $body_bytes_sent $request_time "$http_referer" '
'"$http_user_agent" $remote_addr ';
log_format dev '$http_x_real_ip $http_host [$time_local]';
log_format prd
log_format test
test 测试环境 dev 开发环境 pre 预发环境 prd 生产环境(线上环境)
日志中每个字段的具体含义
$http_x_real_ip 记录客户端IP地址,通常使用$remote_addr, 这里结合负载均衡的配置获取真是的客户端IP
$http_host 请求的域名
$time_local 通用日志格式下的本地时间。
$request 记录请求的URL和HTTP协议版本,及请求方式。 格式为"METHOD URL VERSION"
$request_length 请求的长度(包括请求行,请求头和请求正文)。
$status 记录请求状态,HTTP状态码。
$body_bytes_sent 发送给客户端的响应体大小,不包括响应头
$http_referer 记录从哪个页面链接访问过来的
$http_user_agent 记录客户端浏览器相关信息
$remote_addr 远端服务器,到底是哪台代理服务器来的请求。
使用自定义日志格式
# 通过使用access_log 指令去指定访问日志时,指定使用的日志格式
access_log /var/log/access.log main; dev
三、Nginx 日志切割问题
若记录了Nginx 的access Log,最好能够按天对日志进行切割、压缩。这样做的好处有:
- 日志归档清晰
- 大量的日志也不会导致磁盘空间占满
- 若当天业务有问题,查询日志时不必从历史日志出发
按时间和大小 每天生成一个日志文件, 日志大小到1g自动切割,每个日志文件大小都是1g
23:59 200m
大小1g - 10g 本地日志
时间(每天产生100g), 100 个文件 10个文件
按小时 12 个,转移日志方便
日志保留策略 本地日志保留3-7天 防止本地磁盘被占满 1,日志系统 elk,efk, 2,删除 3,归档,压缩打包仓库存储
#!/bin/bash
# 脚本功能
# 定期删除30天前一天的归档日志。
# 可以通过crontab 在每天凌晨后执行, 执行后会将前一天的日志归档到 $LOGARCHIVE 变量指定的目录中
# 可以留作业, 让学生改进成,每天归档后对日志进行压缩。以减少日志对磁盘的使用情况。
# 日志被 mv 走后, 对 Nginx 发送了 -USR1 信号, 重新打开日志文件。 这个在第一章中有介绍 usr1 usr2 用户自定义信号,重启,重载配置
# Nginx 日志存放目录
LOGDIR="/data0/www/logs"
# 一定要设置Nginx 的 access log 日志文件后缀名都为 -access_log
LOGSUFFIXA="*-access_log"
# 归档日志存放的目录(打包压缩)
LOGARCHIVE="/data0/www/logs/archives"
# Nginx 的Pid 文件
PID="/usr/local/nginx/logs/nginx.pid" # 如果是yum安的/run/nginx.pid
# 删除 30天以前的日志
find $LOGARCHIVE -type f -atime +30 -exec rm -f {} \; > /dev/null 2>&1
# 删除空目录
find $LOGARCHIVE -type d -empty -exec rmdir {} \; >/dev/null 2>&1
# 获取前一天的时间
DATE=`date --date="LAST DAY" "+%y%m%d"`
# 创建前一天归档日志目录
LOGARCHIVE="$LOGARCHIVE/$DATE"
test -d $LOGARCHIVE || mkdir -p $LOGARCHIVE
cd $LOGDIR
for FILE in *$LOGSUFFIXA*; do
mv $FILE $LOGARCHIVE && cd $LOGARCHIVE && tar -czvf $DATE.tar.gz $DATE && rm -rf $DATE
done
# 发送 USR1 信号给Nginx, 让Nginx 重新打开⽇日志⽂文件。
kill -USR1 `cat ${PID}`
- USR1通常被用来告知应用程序重载配置文件
- 停止接受新的连接,等待当前连接停止;
- 重新载入配置文件;
- 重新打开日志文件;
- 重载配置文件,从而实现相对平滑的不关机更新配置
- kill -HUP pid 或者 killall -HUP pName 其中pid是进程标识,pName是进程的名称 如果想要更改配置而不停止服务,可以使用上面两个命令。在对配置文件作必要的更改后,发出该命令以动态更新服务配置。
- 当发送一个挂起信号(信号1或HUP)时,大多数服务器进程(所有常用的进程)都会进行复位操作并重新加载它们的配置文件。
其他案例:
日志切割脚本参考 https://zuolaoshi.cn/article/2024/10/23/547.html
open_log_file_cache
使用open_log_file_cache来设置日志文件缓存(默认是off)。
- max:设置缓存中的最大文件描述符数量,如果缓存被占满,采用LRU算法将描述符关闭。
- inactive:设置存活时间,默认是10s
- min_uses:设置在inactive时间段内,日志文件最少使用多少次后,该日志文件描述符记入缓存中,默认是1次
- valid:设置检查频率,默认60s
- off:禁用缓存
语法格式:
open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
默认值: open_log_file_cache off;
作用域: http, server, location
实例四:
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
四、nginx日志调试技巧
设置 Nginx 仅记录来自于你的 IP 的错误
当你设置日志级别成 debug,如果你在调试一个在线的高流量网站的话,你的错误日志可能会记录每个请求的很多消息,这样会变得毫无意义。
在events{...}
中配置如下内容,可以使 Nginx 记录仅仅来自于你的 IP 的错误日志。
events {
debug_connection 1.2.3.4;
}
调试 nginx rewrite 规则
调试rewrite规则时,如果规则写错只会看见一个404页面,可以在配置文件中开启nginx rewrite日志,进行调试。
server {
error_log /var/logs/nginx/example.com.error.log;
rewrite_log on;
}
rewrite_log on;
开启后,它将发送所有的 rewrite 相关的日志信息到 error_log 文件中,使用 [notice] 级别。随后就可以在error_log 查看rewrite信息了。
使用location记录指定URL的日志
server {
error_log /var/logs/nginx/example.com.error.log;
location /static/ {
error_log /var/logs/nginx/static-error.log debug;
}
}
配置以上配置后,/static/ 相关的日志会被单独记录在static-error.log文件中。
nginx日志共三个参数 access_log: 定义日志的路径及格式。 log_format: 定义日志的模板。 open_log_file_cache: 定义日志文件缓存。
proxy_set_header X-Forwarded-For :如果后端Web服务器上的程序需要获取用户IP,从该Header头获取。proxy_set_header X-Forwarded-For $remote_addr;
常用例子
main格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'$upstream_addr $upstream_response_time $request_time ';
access_log logs/access.log main;
json格式
log_format logstash_json '{"@timestamp":"$time_iso8601",'
'"host": "$server_addr",'
'"client": "$remote_addr",'
'"size": $body_bytes_sent,'
'"responsetime": $request_time,'
'"domain": "$host",'
'"url":"$request_uri",'
'"referer": "$http_referer",'
'"agent": "$http_user_agent",'
'"status":"$status",'
'"x_forwarded_for":"$http_x_forwarded_for"}';
解释:
$uri
请求中的当前URI(不带请求参数,参数位于$args
),不同于浏览器传递的$request_uri
的值,它可以通过内部重定向,或者使用index指令进行修改。不包括协议和主机名,例如/foo/bar.html。
$request_uri
这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri
更改或重写URI。
也就是说:$request_uri
是原始请求URL,$uri
则是经过nginx处理请求后剔除参数的URL,所以会将汉字表现为union。
坑点:
使用$uri
可以在nginx对URL进行更改或重写,但是用于日志输出可以使用$request_uri
代替,如无特殊业务需求,完全可以替换。
压缩格式
日志中增加了压缩的信息。
http {
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$gzip_ratio"';
server {
gzip on;
access_log /spool/logs/nginx-access.log compression;
...
}
}
upstream格式
增加upstream消耗的时间。
http {
log_format upstream_time '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"'
'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';
server {
access_log /spool/logs/nginx-access.log upstream_time;
...
}
}
参考文档
统计status 出现的次数
awk '{print $9}' access.log | sort | uniq -c | sort -rn
36461 200
483 500
87 404
9 400
3 302
1 499
1 403
1 301
显示返回302状态码的URL。
awk '($9 ~ /302/)' access.log | awk '{print $7}' | sort | uniq -c | sort -rn
1 /wp-login.php
1 /wp-admin/plugins.php?action=activate&plugin=ewww-image-optimizer%2Fewww-image-optimizer.php&_wpnonce=cc4a379131
1 /wp-admin/
日志分析脚本
1.脚本功能
- 访问IP统计(前10)
- 访问路径统计(前10)
- 状态码为40x的IP统计(前10)
- 状态码为404的访问路径统计(前10)
- 搜索引擎爬虫分析
- 总PV
- 独立访客数(UV)
先给个空数据的图给你们看看。
2.传入日志文件
# 检查是否提供了日志文件路径
if [ "$#" -ne 1 ]; then
echo "使用方法: $0 <nginx_access_log_file>"
exit 1
fi
LOG_FILE=$1
3.访问IP统计
#访问IP统计,并从高到低排序展示
echo -e "\033[1;31m访问IP统计(前10):\033[0m"awk '{print $1}' "$LOG_FILE" | sort -n |uniq -c | sort -rn | head -n 10
4.访问路径统计
#访问路径统计,并从高到低排序展示
echo -e "\033[1;31m访问路径统计(前10):\033[0m"
cat "$LOG_FILE" | awk '{path[$7]++} END {for (i in path) print i, path[i]}' | sort -rn -k2 | head -n 10
4.访问状态40X的IP统计
# 访问状态为40x的IP,并从高到低排序展示
echo -e "\033[1;31m状态码为40x的IP统计(前10):\033[0m"
cat "$LOG_FILE" | awk '$9 ~ /^4./ {ip40x[$1]++} END {for (i in ip40x) print i, ip40x[i]}' | sort -rn -k2 | head -n 10
6.访问状态码为404的路径统计
#状态码为404的访问路径统计
echo -e "\033[1;31m状态码为404的访问路径统计(前10):\033[0m"
cat "$LOG_FILE" | awk '$9 == "404" {url404[$7]++} END {for (i in url404) print i, url404[i]}' | sort -rn -k2 | head -n 10
7.常见爬虫分析
# 分析搜索引擎爬虫
echo -e "\033[1;31m搜索引擎爬虫分析(前10):\033[0m"
# 常见的搜索引擎爬虫User-Agent示例,可以根据实际情况增减
SEARCH_BOTS=("Googlebot" "bingbot" "Baiduspider" "Yahoo! Slurp" "DuckDuckBot" "AhrefsBot" "petalbot" "DataForSeoBot" "vuhuvBot" "Yisouspider" "Bytespider" "YandexBot" "360Spider" "Sogou web spider" "SemrushBot" "BLEXBot" "AdsBot" "MJ12bot" "DotBot" "Applebot" "CCbot" "yacybot" )
# 创建临时文件存储爬虫访问次数
tmpfile=$(mktemp)
# 遍历搜索引擎爬虫列表,统计访问次数并写入临时文件
for bot in "${SEARCH_BOTS[@]}";
do
COUNT=$(grep -i "$bot" "$LOG_FILE" | grep "$TODAY" | wc -l)
echo "$bot $COUNT" >> "$tmpfile"
done
# 读取临时文件内容,按访问次数排序并取前10
sort -k2,2nr "$tmpfile" | head -n 10
8.PV、UV统计
# 统计PV
total_pv=$(wc -l < "$LOG_FILE")
# 统计UV
unique_ips=$(awk '{split($4, a, /\[|\]/); print a[2]}' "$LOG_FILE" | sort | uniq | wc -l)
echo -e "\033[1;31m总PV: \033[0m $total_pv "
echo -e "\033[1;31m独立访客数(UV): \033[0m $unique_ips "