0. 引言
在企业的生产环境中,我们时常需要通过nginx的访问日志来统计流量、排查调用问题等,而nginx默认的日志格式所包含的信息远无法满足我们使用,因此常常需要对日志进行自定义,所以今天我们就来看如何自定义nginx的访问日志格式,并了解nginx的访问日志支持多少参数。
1. 自定义日志格式
首先我们在默认的nginx.conf
文件中可以看到,对访问日志是有默认定义的,其中包含了定义日志格式,定义日志文件位置。如下所示,其中main
为定义的日志格式别名,你可以定义成其他的名称。
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
默认日志输出示例
nginx的访问日志定义的语法是:
log_format name [escape=default | json] string ...;
- name: 定义的格式名称,自定义,后续在access_log参数中引用
- escape: 设置日志格式,默认为default,即默认输出,或者支持json, 按照json格式输出
- string: 要定义的日志格式的内容,可以在里面设置要记录的日志参数
在默认日志格式中,定义的参数含义如下:
参数 | 说明 |
---|---|
$remote_addr | 客户端IP地址 |
$remote_user | 客户端用户名 |
$time_local | 请求时间 |
$request | 请求的URI和HTTP协议版本 |
$status | 请求返回的状态码 |
$body_bytes_sent | 发送给客户端的字节数 |
$http_referer | 引用的页面地址 |
$http_user_agent | 客户端代理信息, 比如浏览器信息等 |
nginx还支持的常用参数有:
参数 | 说明 |
---|---|
$http_host | 请求头中的 “Host” 字段的值,如果请求中没有 “Host” 字段,则会使用服务器监听的 server_name 中定义的第一个名称 |
$uri | 请求的 URI,即 URL 的后半部分,不包括查询字符串 |
$ssl_protocol | 使用的 SSL 协议版本,如 “SSLv3”、“TLSv1” 等 |
$ssl_cipher | 用于加密连接的加密算法,例如 “AES128-SHA” |
$http_x_forwarded_for | 当前端有代理服务器时,设置web节点记录客户端地址的配置,此参数生效的前提是代理服务器也要进行相关的x_forwarded_for设置 |
$upstream_addr | 后端服务器的地址和端口,用于识别请求被转发到的服务器 |
$request_body | 客户端发送的请求体,即请求消息的主体部分,通常用于 POST 请求 |
$upstream_status | 后端服务器的响应状态码,如 “200”、“404” 等 |
$upstream_header_time | 后端服务器处理请求并返回响应头的时间 |
$upstream_response_time | 后端服务器从开始处理请求到返回响应的整个时间 |
$bytes_sent | 发送给客户端的字节数 |
$connection | 连接序列号 |
$connection_requests | 当前通过连接发出的请求数量 |
$msec | 日志写入时间,单位为秒,精度是毫秒 |
$pipe | 如果请求是通过http流水线发送,则其值为"p",否则为“." |
$request_length | 请求长度(包括请求行,请求头和请求体) |
$request_time | 请求处理时长,单位为秒,精度为毫秒,从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端进行日志写入为止 |
$time_iso8601 | 标准格式的本地时间,形如“2017-05-24T18:31:27+08:00” |
$remote_addr | 客户端IP |
$request | 完整的原始请求行,如 “GET / HTTP/1.1” |
$request_uri | 完整的请求地址,如 “https://baidu.com” |
2. 日志配置案例
下面我们按照生产环境的日志标准配置一个样例,包括请求时间、地址、加密算法、响应时长、请求体大小等信息
log_format main escape=json '{"@timestamp":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"http_host":"$http_host",'
'"uri":"$uri",'
'"http_referer":"$http_referer",'
'"ssl_protocol":"$ssl_protocol",'
'"ssl_cipher":"$ssl_cipher",'
'"http_x_forwarded_for":"$http_x_forwarded_for",'
'"upstream_addr":"$upstream_addr",'
'"bytes":$body_bytes_sent,'
'"request":"$request",'
'"request_length":$request_length,'
'"request_time":$request_time,'
'"upstream_status":$upstream_status,'
'"upstream_header_time":$upstream_header_time,'
'"upstream_response_time":$upstream_response_time,'
'"status":"$status",'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent"'
'}';
access_log /var/log/nginx/access.log main;
配置好记得重启,让配置生效
# 检查语法
nginx -t
# 重启
nginx -s reload
输出样式:
可以看到日志就以json格式的形式输出了
3. 日志记录自定义请求头
某些场景下,我们需要打印自定义的请求头,比如设置请求头参数为这次请求的流水号,这样将其打印后,我们就能快速定位到这笔请求的nginx日志了
1、而打印也很简单,就直接在日志格式里添加上这个header即可,如下添加一个自定义header:http_x_seqno
,需要注意的是这里日志中引用的header变量,需要是原来的请求头名称小写,并且前面加上"http_“,比如请求头是"x_seqno”, 那么这里配置的就是"$http_x_seqno"
log_format main escape=json '{"@timestamp":"$time_iso8601",'
'"http_user_agent":"$http_user_agent",'
'""http_x_seqno":"$http_x_seqno"'
'}';
access_log /var/log/nginx/access.log main;
2、如果这里直接重启访问,会发现日志并不会打印该header值,这是因为我们还需要在http或server模块中开启underscores_in_headers
,以此支持读取下划线header
underscores_in_headers on; # 下划线支持,开启自定义header
然后重启nginx,测试访问
日志中会发现该header已经打印
4. 总结
如上,我们就掌握了关于nginx的访问日志的自定义,但还有一个问题,就是nginx的日志文件是一个,没有按天分割,时间一长,那么这个文件就会很大,影响我们维护阅读。于是如何实现nginx日志文件的按天分割呢?
以下提供几种思路,大家可以自己拓展:
- 1、借助脚本实现,通过编写脚本,通过
mv
指令将日志文件迁移到有带日期名的日志文件,该脚本添加到linux每日定时任务中 - 2、使用cronlog工具实现
- 3、使用Logrotate工具实现
尽量避免使用通过在nginx http模块用map定义变量,然后声明日志文件名,或者其他类似的通过nginx本身变量声明而修改日志文件名的形式,因为这样每次请求进来都要进行判断,影响性能。