NGINX Conditional Logging

本文内容主要来自于:https://www.nginx.com/blog/sampling-requests-with-nginx-conditional-logging/

今日在排查问题时,高度怀疑某个客户端调用服务端的一个接口时传递了错误的输入。

为了抓取到具体的问题,想到可以通过nginx日志输出完整的请求内容来进行排查。因为nginx可以修改配置文件后热更新,所以可以方便的进行不停服的修改。

但如果将每个请求的输入全部输出到日志中,可能会导致日志量过大,如果是线上系统则可能会导致性能问题。

Nginx有两种方法可以实现针对某个URL打印不同的日志:

Conditional Logging#

http{
    log_format access '$remote_addr - $remote_user [$time_local]  '
                '"$request" $status $body_bytes_sent '
                '"$http_referer" "$http_user_agent" '
                '$request_time $upstream_response_time $pipe';
    log_format notes '[$time_local] $remote_addr "$request" $status $request_body';
    server{
        set $logme 0;
        if ( $uri ~ ^/api/v1/config ) {
            set $logme 1;
        }
        access_log  /var/log/nginx/config_access.log notes if=$logme;
        access_log /var/log/nginx/access.log access;
    }
}

上面配置中先定义了两个日志:access和notes,notes日志中通过 $request_body 打印请求内容,之后在server的配置中通过条件决定是否启用notes日志。

Sub Block#

第二种方法其实更加简单,但可能会有一些局限,通过在子模块中重新定义 access log 也可以实现目的:

http{
    log_format access '$remote_addr - $remote_user [$time_local]  '
                '"$request" $status $body_bytes_sent '
                '"$http_referer" "$http_user_agent" '
                '$request_time $upstream_response_time $pipe';
    log_format notes '[$time_local] $remote_addr "$request" $status $request_body';
    server{
        access_log /var/log/nginx/access.log access;
        location /api/v1/config{
            access_log  /var/log/nginx/config_access.log notes;
        }
    }
}

采样日志#

对于一个负载很高的服务器,可能针对某个URL进行特殊的日志输出也会产生问题,此时可以通过采样的方式降低日志输出量。

下面是参考文章中给出的例子,通过设置,只对 1% 的请求进行日志输出:

split_clients $request_id $logme {
    1%     1;
    *      0;
}

server {
    listen 80;

    access_log  /var/log/nginx/secure.log notes if=$logme;

    # ...
}

具体效果还没有机会实践,等以后有机会继续补充。

comments powered by Disqus