Nginx日志管理
导航: 这里将Nginx的一些配置进行整合。根据导航比较容易找到对应的文档。资料来自于weixueyuan 5.Nginx 缓存 |
Nginx 的日志分为访问日志和错误日志两种。访问日志中记录了用户的来源 IP、浏览器信息、响应状态等,使用者也可通过 Nginx 的日志格式指令添加更多有用的信息并输出到访问日志中。通过对访问日志的分析,可以让网站管理者清晰地了解网站的安全性、性能、可用性及网站运行的 PV、UV 等数据。
错误日志则会记录 Nginx 加载配置时的配置指令检查出的异常、Nginx 运行时请求处理的异常及服务器调试信息等。通过错误日志可以为排查问题或优化 Nginx 配置参数、提升高并发处理能力提供帮助。
1.Nginx访问日志配置
Nginx 的访问日志主要记录用户客户端的请求信息(见下表)。用户的每次请求都会记录在访问日志中,access_log 指令可以设置日志的输出方式及引用的日志格式。
名称 | 访问日志指令 |
指令 | access_log |
作用域 | http、stream、server、location、if in location、limit except |
默认值 | logs/access.log combined; |
指令值格式 | off 或 path[format[buffer=size][gzip[=level]][flush=time][if=condition]]; |
指令说明 | 设置访问日志输出方式及引用的日志格式 |
关于 access_log 指令有以下几点需要说明:
-
- 在同一级别的指令域中,也可指定多个日志;
- 指令值中的第一个参数用于设置输出日志的方式,默认是输出到本地的文件中。该指令也支持输出到 syslog 或内存缓冲区中;
- 该指令在 stream 指令域中时,默认值为 off;
access_log off;
-
- 参数 path,设置日志输出的文件路径或 syslog 服务器地址;
access_log logs/access.log combined;
-
- 参数 format,设置关联 log_format 指令定义的日志格式名;
- 参数 buffer,设置日志文件缓冲区大小。当缓冲区日志数据超出该值时,缓冲区日志数据会被写到磁盘文件。默认缓冲区大小为 64KB;
- 参数 flush,设置日志缓冲区刷新的时间间隔,缓冲区日志的保护时间超过这个设定值时,缓冲区日志数据会被写到磁盘文件;
- 参数 gzip,设置缓冲区数据的压缩级别,缓冲区数据会被压缩后再写出到磁盘文件。压缩级别范围 1~9,级别越高压缩比越高,系统资源消耗也最大,默认级别为 1;
access_log logs/log.gz combined gzip flush=5m;
-
- 参数 if,设置是否记录日志,当参数值的条件成立,即不为 0 或空时,才记录日志。
map $status $loggable { ~^[23] 0; default 1; } access_log logs/access.log combined if=$loggable;
日志格式指令如下表所示。
名称 | 日志格式指令 |
指令 | log_format |
作用域 | http、stream |
默认值 | combined"..."; |
指令值格式 | name[escape=default 或 json 或 none]string...; |
指令说明 | 设置访问日志输出方式及输出日志格式 |
关于 log_format 指令有以下几点需要说明:
-
- 指令值参数 name 用于设置日志格式名。该名称全局唯一,可以被 access_log 引用;
- 指令值参数 escape 用于设置日志输出字符串编码格式,json 支持中文字符内容输出;
- 指令值参数 string 用于设置日志输出格式字符串。该字符串由 Nginx 公共变量和仅在日志写入时存在的变量组成。HTTP 常用变量如下表所示。
变量名 | 变量说明 |
$time_iso8601 | ISO 8601 时间格式 |
$time_local | 用户请求的时间和时区 |
$msec | 毫秒级别的日志记录时间 |
$remote_addr | 发起与 Nginx 建立连接的网络客户端的 IP,有时会是上层代理服务器的 IP |
$http_x_forwarded_for | 可以记录客户端 IP,通过代理服务器来记录客户端的 IP |
$remote_user | 用于记录远程客户端的用户名称 |
$http_user_agent | 用户客户端浏览器标识 |
$connection | 网络连接编号 |
$connection_requests | 当前连接的请求数 |
$request | 用户请求的 URI 及请求方法 |
$request_method | 用户请求方法 |
$request_uri | 用户请求的 URI 及请求方法 |
$server_protocol | 请求协议 |
$request_time | 请求时间 |
$request_length | 请求数据大小 |
$status | 用户请求响应状态码 |
$bytes_sent | 发送到客户端响应数据的大小 |
$body_bytes_sent | 用户请求返回的响应体字节数 |
$http_referer | HTTP 请求头中属性字段 referer |
配置样例如下:
# 普通格式日志 log_format main '$remote_addr - $connection - $remote_user [$time_local] "$request" - $upstream_addr' '$status - $body_bytes_sent - $request_time - "$http_referer" ' '"$http_user_agent" - "$http_x_forwarded_for" - '; # JSON格式日志 log_format json '{"@timestamp": "$time_iso8601", ' '"connection": "$connection", ' '"remote_addr": "$remote_addr", ' '"remote_user": "$remote_user", ' '"request_method": "$request_method", ' '"request_uri": "$request_uri", ' '"server_protocol": "$server_protocol", ' '"status": "$status", ' '"body_bytes_sent": "$body_bytes_sent", ' '"http_referer": "$http_referer", ' '"http_user_agent": "$http_user_agent", ' '"http_x_forwarded_for": "$http_x_forwarded_for", ' '"request_time": "$request_time"}';
Nginx TCP/UDP 的访问日志的变量与 HTTP 的访问日志的变量是不同的,TCP/UDP 常见日志变量如下表所示。
变量名 | 变量说明 |
$time_iso8601 | ISO 8601 时间格式 |
$time_local | 用户请求的时间和时区 |
$connection | 网络连接编号 |
$remote_addr | 发起与 Nginx 建立连接的网络客户端的 IP,有时会是上层代理服务器的 IP |
$server_addr | Nginx 服务器地址 |
$server_port | Nginx 服务器端口 |
$status | 用户请求响应状态码 |
$upstream_addr | 被代理服务器地址 |
$bytes_received | 接收字节数 |
$bytes_sent | 发送字节数 |
$session_time | 连接会话时间 |
$proxy_protocol_addr | 代理协议地址 |
$proxy_protocol_port | 代理协议端口 |
Nginx 的 TCP/UDP 的日志处理是在连接处理阶段结束时才发生,所以 TCP/UDP 代理的访问日志只在连接关闭时才被记录。访问日志格式配置样例如下:
# 普通格式日志 log_format main '$remote_addr - $connection - $remote_user [$time_local] "$request" - $upstream_addr' '$status - $body_bytes_sent - $request_time - "$http_referer" ' '"$http_user_agent" - "$http_x_forwarded_for" - '; # JSON格式日志 log_format json '{"@timestamp": "$time_iso8601", ' '"connection": "$connection", ' '"remote_addr": "$remote_addr", ' '"remote_user": "$remote_user", ' '"request_method": "$request_method", ' '"request_uri": "$request_uri", ' '"server_protocol": "$server_protocol", ' '"status": "$status", ' '"body_bytes_sent": "$body_bytes_sent", ' '"http_referer": "$http_referer", ' '"http_user_agent": "$http_user_agent", ' '"http_x_forwarded_for": "$http_x_forwarded_for", ' '"request_time": "$request_time"}';
打开日志缓存指令见下表。
名称 | 打开日志缓存指令 |
指令 | open_log_file_cache |
作用域 | http、stream、server、location |
默认值 | off |
指令值格式 | off 或 max=N [inactive=time][min_uses=N][valid=time]; |
指令说明 | 设置存储日志文件描述符(文件句柄)的缓存 |
关于 open_log_file_cache 指令有以下几点需要说明:
-
- 默认配置下,Nginx 每次将缓冲区日志数据保存到磁盘中,都需要先打开文件并获得文件描述符,然后向该文件描述符的文件中写入日志数据,最后关闭该文件描述符的文件。该指令把打开文件的文件描述符(文件句柄)存储在缓存中,进而提升写入日志的效率;
- 指令值 max 用于设置缓存中存储的文件描述符的最大数量,超过该值时,将按照 LRU 算法对缓存中文件描述符进行关闭;
- 指令值参数 inactive 用于设置缓存中每个文件描述符存活的时间,默认为 10s;
- 指令值参数 min_uses 用于设置可被缓存文件描述符的最小使用次数,默认为 1 次;
- 指令值参数 valid 用于设置缓存检查频率,默认为 60s;
- 指令值 off 用于关闭打开日志缓存的功能。
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
logs/access.log combined;
2.Nginx error_log:错误日志配置
Nginx 的错误日志可以帮助用户及时判断 Nginx 配置及运行时出错的原因,错误日志也可以通过 Nginx 内置指令进行配置,但不支持格式定义。配置指令如下表所示。
说明 | 错误日志指令组成 |
主指令 | error_log |
作用域 | main、http、mail、stream、server、location |
默认值 | logs/error.log error; |
指令说明 | 设置错误日志输出方式及输出日志级别 |
关于 error_log 指令有以下几点需要说明:
-
- 在同一级别的指令域中,也可指定多个日志;
- 指令值中的第一个参数是输出日志的方式,默认是输出到本地的文件中。该指令也支持输出到 syslog 或内存缓冲区中;
error_log syslog:server=192.168.2.109 error; error_log memory:32m debug; error_log /dev/null; # 访问文件不存在时,记入错误日志 log_not_found on;
指令值中第二个参数是输出日志的级别,指定的级别将包含自身及级别值比其小的所有级别日志,日志内容会保存到第一个参数设定的输出位置。
错误日志级别及相关说明如下表所示。
级别 | 级别值 | 级别说明 |
debug | 8 | 代码中标记为 NGX_LOG_DEBUG 的输出,输出最为详细,配合调试使用 |
info | 7 | 代码中标记为 NGX_LOG_INFO 的输出,因包括除 debug 级别的所有输出,故同样会消耗大量磁盘 IO 资源 |
notice | 6 | 代码中标记为 NGX_LOG_NOTICE 的输出 |
warn | 5 | 代码中标记为 NGX_LOG_WARN 的输出 |
error | 4 | 代码中标记为 NGX_LOG_ERROR 的输出,实际生产环境中常用的输出级别 |
crit | 3 | 代码中标记为 NGX_LOG_CRIT 的输出 |
alert | 2 | 代码中标记为 NGX_LOG_ALERT 的输出 |
emerg | 1 | 代码中标记为 NGX_LOG_EMERG 的输出 |
3.Nginx Logrotate:日志归档
Nginx 日志存储为文件时,同一 access_log 指令设置的日志文件是以单文件形式存储的,在日常使用中为方便维护,通常需要将日志文件按日期进行归档。虽然 Nginx 本身并没有这一功能,但实现日志归档的方法仍有很多,此处推荐使用 Logrotate 实现日志归档管理。
Logrotate 是 CentOS 操作系统内置日志管理工具,该工具可对系统中生成的大量日志文件进行归档管理,其允许对日志文件实行压缩、删除或邮寄等操作。Logrotate 可以按照每天、周、月或达到某一大小的日志文件进行归档操作,Logrotate 基于 anacrontab 实现计划任务,只需在 /etc/logrotate.d 目录下编写相关日志管理配置文件,就可以无须人工干预使用自动化方式完成日志归档操作。
1) Logrotate 安装
yum -y install logrotate
2) Logrotate 文件目录
/etc/logrotate.conf # logrotate主配置文件 /usr/sbin/logrotate # logrotate二进制文件 /etc/logrotate.d/ # 自定义logrotate配置文件 /var/lib/logrotate/logrotate.status # logrotate管理日志执行记录的状态文件
3) Logrotate 命令参数
-d, --debug # 测试归档配置文件 -f, --force # 立即执行归档操作 -m, --mail=command # 指定发送邮件的命令(默认为'/bin/mail') -s, --state=statefile # 设置logrotate.status文件路径,可用于区分在同 # 一系统下以不同用户身份运行的logrotate任务 -v, --verbose # 显示配置详细信息 -l, --log=STRING # 将Logrotate执行的详情输出到指定的文件 logrotate -v /etc/logrotate.conf # 显示配置文件详细信息 logrotate -d /etc/logrotate.d/syslog -l /var/log/logrotate.log # 配置文件,执行测试 logrotate -f /etc/logrotate.d/syslog # 立即执行当前配置文件
4) Logrotate 配置指令
Logrotate 配置指令如下表所示。
指令 | 指令说明 |
归档执行周期 | |
hourly | 日志归档周期为 1 小时,默认 Logrotate 的最小周期为 1 天,需额外调整该参数才可生效 |
daily | 日志归档周期为 1 天 |
weekly | 日志归档周期为 1 周 |
monthly | 日志归档周期为 1 月,通常为每月的第一天 |
归档执行条件 | |
include | 读取外部参数文件 |
missingok | 如果日志文件不存在,则不显示错误信息 |
nomissingok | 如果日志文件不存在,则显示错误信息。默认配置 |
size | 日志文件可被归档的最小值 |
minsize | 日志文件可被归档的最小值,没到归档周期执行时间,不会执行归档操作 |
maxsize | 日志文件超过设定值时,即使没到归档周期执行时间,也会执行归档操作 |
ifempty | 即使日志文件为空,也执行归档操作 |
notifempty | 如果日志文件为空,则不进行归档。默认设置 |
tabooext | 不对设置扩展名的日志文件执行归档操作 |
归档文件命名 | |
start count | 使用日志文件归档次数作为归档文件扩展名,count 默认值为 1,默认配置 |
dateext | 为归档文件名添加日期,默认追加到扩展名后 |
dateformat | 设置归档文件名中的日期格式,使用“%Y%m%d%H”作为说明符,默认为-%Y%m%d |
dateyesterday | 使用前一天的日期而非创建归档文件时的日期作为归档文件的文件名中的日期 |
extension | 指定日志的扩展名,并将其设置为归档文件的扩展名,启用压缩时,压缩的扩展名在最后 |
compressext | 启用压缩时,自定义归档文件扩展名,如将“.gz”改为“.ddd” |
归档文件保存方式 | |
compress | 对归档文件启用压缩,默认为 gzip 压缩 |
nocompress | 不压缩归档文件。默认设置 |
compresscmd | 指定压缩归档文件的命令,默认为 gzip 压缩 |
uncompresscmd | 指定解压归档文件的命令,默认为 gunzip 解压 |
compressoptions | 启用压缩时,设置压缩工具的命令选项 |
delaycompress | 在下一个归档周期再对当前归档文件进行压缩 |
nodelaycompress | 不延迟压缩。默认设置 |
归档执行方式 | |
copy | 为日志文件复制一个副本后再进行归档 |
nocopy | 不复制源日志文件。默认配置 |
copytruncate | 复制日志文件后清空日志文件的内容 |
nocopytruncate | 复制源日志文件后,不清空源文件。默认设置 |
create mode owner group, create owner group | 重命名日志文件,创建与日志文件同名的文件,默认 mode=0644 uid=0 gid=0,与 copy 指令不能同时使用 |
nocreate | 不创建与日志文件同名的文件。默认设置 |
olddir | 设置归档文件保存目录 |
noolddir | 归档文件与源文件在同一目录。默认设置 |
createolddir mode owner group | 如果 olddir 参数指定的目录不存在,则创建目录并指定属组,默认 mode = 0777 uid = 0 gid = 0 |
nocreateolddir | 当 olddir 参数设定目录不存在时,不创建目录。默认设置 |
prerotate ... endscript | 归档执行之前执行脚本,日志文件名为传入的第一个参数 |
postrotate ... endscript | 归档执行之后执行脚本,日志文件名为传入的第一个参数 |
firstaction ... endscript | prerotate 脚本之前,仅当第一个日志文件被开始执行归档操作时才执行脚本,日志文件名为传入的第一个参数 |
lastaction ... endscript | postrotate 脚本之后,仅当最后一个日志文件执行归档操作结束时才执行脚本,日志文件名为传入的第一个参数 |
preremove ... endscript | 删除日志文件之前执行脚本,日志文件名为传入的第一个参数 |
sharedscripts |
当匹配的日志文件为多个时,prerotate 和 postrotate 脚本会在每个日志文件执行归档操作时都执行一次, 启用共享模式会让 prerotate 和 postrotate 脚本在全局只运行一次 |
nosharedscripts | 当匹配的日志文件为多个时,prerotate 和 postrotate 脚本会在每个日志文件执行归档操作时都执行一次。默认设置 |
su user group | 指定操作源文件执行归档操作的用户及属组 |
归档文件清理 | |
设置接收归档文件的邮件地址 | |
nomail | 不将归档文件发送到任何邮件地址 |
mailfirst | 将刚生成的归档文件发送到设置的邮箱 |
maillast | 将要超过 maxage 设置时间的归档文件发送到设置的邮箱 |
maxage | 设置过期归档文件的天数 |
rotate | 保留归档文件数,默认为 0 |
shred | 彻底删除 |
shredcycles count | 彻底删除时,覆盖文件的次数,默认为 3 |
noshred | 不彻底删除 |
关于上表有以下几点需要说明:
-
- copy 与 create 是两种互斥的归档执行方式;
- copy 方式是将日志文件复制一份后清空原日志文件的内容,并对复制的文件进行归档操作,应用程序继续向原日志文件输出日志。因日志文件复制与清空操作存在时间间隔,所以切割操作会因日志量的大小及实时产生的频率存在丢失的情况;
- create 方式是将日志文件重命名,因日志文件的 inode 编号不变,应用程序会向新命名的文件输出日志。Logrotate 新创建原日志文件名的文件后执行重启或以信号机制通知应用程序重新向新日志文件输出日志内容,完成切割操作;
- 当与同一自定义配置匹配的日志文件为多个时,会并发执行归档操作。
5) Logrotate 管理 Nginx 日志
根据 Logrotate 的功能特点,建议选择 create 方式进行日志归档管理,配置样例如下:
vi /etc/logrotate.d/nginx /usr/local/nginx/logs/*.log { daily # 日志归档周期为1天 size 1 # 日志文件最小为1字节时才执行归档 minsize 1 # 日志文件最小为1字节时才执行归档 notifempty # 日志文件不为空时才执行归档 dateext # 归档文件名添加时间字符串 dateformat -%Y%m%d%H # 归档文件名时间字符串格式为-%Y%m%d%H dateyesterday # 归档文件名时间字符串以归档操作的前一天为时间戳 extension .log # 归档文件名中保留日志的扩展名 compress # 归档文件执行压缩 delaycompress # 在归档执行的下个周期再进行压缩 create # 以创建新文件方式实现日志归档 olddir /data/backup/nginx_logs # 归档文件存储目录 createolddir # 归档文件存储目录不存在时自动创建 postrotate # 归档执行后执行脚本 /usr/local/nginx/sbin/nginx -s reopen -g "pid /run/nginx.pid;" # 通知Nginx重新打开日志文件 endscript sharedscripts # 启用脚本共享模式 maxage 7 # 归档文件最多保留7天 rotate 7 # 归档文件最多保留7份 }
4.Nginx日志分析简述
Nginx 通常被置于服务器访问的入口,其访问日志可以全局记录用户访问的来源、响应时间,以及用户行为热点等数据,通过对访问日志的分析,可以清晰地了解用户来源、用户行为习惯及自身服务器性能等情况。借助 ELK 的高性能处理能力,可以实时地将数据分析结果展现给服务器的维护人员及应用的开发人员,进而不断提高业务的可用性及产品的用户体验。
Nginx 的日志分析可以分为安全分析、性能分析、可用性分析及访问统计分析 4 个方面。
1) 安全分析
通常黑客对互联网应用的入侵都是先从 Web 服务器漏洞扫描开始的,最常用的扫描方式就是在 URL 中加入特定的脚本、命令或字符串不断尝试访问,并根据返回结果判断被扫描网站是否存在漏洞或后门。如 SQL 注入攻击会在访问的 URL 中带有 select、and、or、order by 等常见的 SQL 语句,XSS 攻击会在访问的 URL 中带有 javascript、vbscript、onmouseover、eval 等 Javascript 或 VBscript 脚本命令。
另外,对管理后台入口的扫描也是常用的手段之一,多数情况下管理后台的安全加固是最容易被忽视的,往往认为不提供访问链接就高枕无忧了,而 admin、manage 等关键词通常会轻而易举地被穷举出来。
这些不安全的访问痕迹都会被 Nginx 服务器记录到访问日志中,并通过 ELK 对 Nginx 访问日志中的 request_uri 字段进行关键字过滤和展示,以求在第一时间了解这些不安全事件并提前做好防范工作。
2) 性能分析
一个网站性能的最直接体现就是请求的响应时间。通常用户的请求响应时间都是以毫秒为单位计算的,若用户的请求响应时间以秒为单位时,将极大地加大用户的等待时间,进而影响用户体验。为方便对请求响应的分析,可以将下表所示的 Nginx 服务器提供的变量添加到访问日志中,以记录请求链中消耗的时间。
变量 | 变量名 | 变量说明 |
$request_time | 完全请求时间 | 从 Nginx 在客户端获取请求的第一个字节到 Nginx 发送给客户端响应数据的最后一个字节间的时间 |
$upstream_connect_time | 代理建立连接时间 | 与后端代理服务器建立连接消耗的时间 |
$upstream_header_time | 代理请求时间 | 从与后端代理服务器建立连接到接收到响应数据第一个字节间的时间 |
$upstream_response_time | 响应时间 | 从与后端代理服务器建立连接到接收到响应数据最后一个字节间的时间 |
对请求响应时间的分析,可以通过 ELK 对访问日志 $request_time 字段的时间做排名,对时间值比较大的 URL 从 SQL、代码、架构等多方面分析原因。
3) 可用性分析
HTTP
请求的每条访问都会有相应的访问状态码,访问状态码标识了请求成功或失败的状态。通过 ELK 对访问日志按照状态码维度统计总访问量,可以很直观地展示当前网站的可用性比率。
4) 访问统计分析
访问统计分析,可以让网站管理者最直观地了解网站被访问及用户的访问情况,常见的是 PV 及 UV 统计。
PV(Page View)即页面浏览量或点击量,可以让网站管理者清晰地了解当前网站的访问量;UV(Unique Visitor)即独立访客量,以每个同一 IP(remote_addr)、同一客户端类型(http_user_agent)可被识别为独立访客作为统计单位。
PV 体现了用户的访问量,UV 体现了访问当前网站的人数。URL 的访问数量统计,可以清晰地展示网站的哪些功能被大量使用,可以让网站管理者知道用户对网站功能的喜好,以便进行相关的产品优化。
代码中标记为 NGX_LOG_EMERG 的输出