Nginx日志配置与分析


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通常被用来告知应用程序重载配置文件
    1. 停止接受新的连接,等待当前连接停止;
    2. 重新载入配置文件;
    3. 重新打开日志文件;
    4. 重载配置文件,从而实现相对平滑的不关机更新配置
  • 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.脚本功能

  1. 访问IP统计(前10)
  2. 访问路径统计(前10)
  3. 状态码为40x的IP统计(前10)
  4. 状态码为404的访问路径统计(前10)
  5. 搜索引擎爬虫分析
  6. 总PV
  7. 独立访客数(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 "

图片