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;
# ...
}
具体效果还没有机会实践,等以后有机会继续补充。