Nginx快速入门:访问日志access.log参数详解 |访问日志记录自定义请求头(三)

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本身变量声明而修改日志文件名的形式,因为这样每次请求进来都要进行判断,影响性能。