从Nginx过滤打印user-agent为clb-healthcheck的日志聊聊Nginx的日志自定义打印
# 缘起
通常我们的南北流量的链路是从云的 LB 到服务器的 Nginx 集群,为了利用好 lb 自动检测 Nginx 的功能,通常你会打开健康检查,此时,Nginx 的日志当中就会打印大量的健康检查日志,令人不胜其烦。
# 解决
此时,你可以通过如下配置方式,将健康检查的日志过滤掉,通常,健康检查的日志大概如下:
{
"remote_addr": "1.1.1.1",
"@timestamp": "2023-10-24T09:44:41+08:00",
"request_uri": "/webStatus",
"verb": "GET",
"httpversion": "HTTP/1.1",
"response": "200",
"body_bytes_sent": "0",
"referrer": "-",
"user_agent": "clb-healthcheck",
"http_x_forwarded_for": "-",
"server_name": "test.eryajf.net",
"request_time": "0.000",
"upstream_response_time": "-",
"upstream_addr": "-",
"realpath_root": "/usr/local/nginx/html",
"request_body": "-",
"nginx_version": "1.14.0",
"scheme": "http"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
可以观察到一个特征,所有健康检查的日志的 ua,都是 clb-healthcheck
,于是,我们可以在 Nginx 配置中增加如下配置:
map $http_user_agent $log_ua {
clb-healthcheck 0;
default 1;
}
access_log /data/log/tmp.log json if=$log_ua;
2
3
4
5
6
7
简单说明:此处通过一个 map 来声明一个规则,并通过 0 和 1 表示是否匹配,然后 access_log 中通过 if 判断来应用这个规则。此规则表示如果该条日志中 ua 包括 clb-healthcheck 则不进行记录,否则记录。
可以看到,第一条请求日志正常打印,应用如上规则之后,同样的 ua 的第二条请求则不再输出对应日志,而非此 ua 的第三条请求,日志正常输出打印。
# 扩展
事实上除了上边基于 ua 的方式之外,Nginx 所有的内置变量 (opens new window)都是支持这么定义的。里边变量比较多,我们常用的变量如下:
$host
:访问域名
$uri
:请求 uri
$status
:http 状态码
$request_method
:请求方法
$request_completion
:请求是否完成
$upstream_addr
:反向代理的 upstream
$upstream_status
:upstream 响应值
$scheme
:请求的协议
$http_referer
:referer 来源
$http_user_agent
:浏览器的 user agent
$http_cookie
: 本地所有 cookie,也可以打印指定 cookie,如打印 session: $http_session
$args 或$arg\_
: 请求时的参数
这里摘出几个简单做下示例。
基于域名的规则
map $host $log_host {
~nixops.me 1;
~nixops1.me 1;
default 0;
}
server {
[…]
access_log /var/log/nginx/access.log main;
access_log /var/log/nginx/nixops.me.log main if=$log_host;
}
2
3
4
5
6
7
8
9
10
11
这样 /var/log/nginx/nixops.me.log 里面就只有 nixops.me 和 nixops1.me 这两个域名的日志了。
基于http状态码的规则
map $status $log_status {
~^[50] 1;
404 1;
default 0;
}
server {
[…]
access_log /var/log/nginx/access.log main;
access_log /var/log/nginx/http_error.log main if=$log_status;
}
2
3
4
5
6
7
8
9
10
11
这样就输出 502、503、504、404 日志到 /var/log/nginx/http_error.log
。
基于指定uri的规则
map $uri $log_uri {
~*admin 1;
/api 1;
default 0;
}
server {
[…]
access_log /var/log/nginx/access.log main;
access_log /var/log/nginx/http_uri.log main if=$log_uri;
}
2
3
4
5
6
7
8
9
10
11
另一种写法:
server {
[…]
set $log_uri 0;
if ( $uri ~ ^/api ) {
set $log_uri 1;
}
access_log /var/log/nginx/access.log main;
access_log /var/log/nginx/http_uri.log main if=$log_uri;
}
2
3
4
5
6
7
8
9
这种不使用 map 的方式可以支持正则表达式。
多个条件
上边的例子都是单项的条件,事实上还可以基于多个条件进行过滤。
使用 map 的方式配置:
map $http_user_agent $log_ua {
~*Googlebot 1;
~*Baiduspider 1;
default 0;
}
map $http_cookie $log_cookie {
~PHPSESSION 1;
default "";
}
map “$log_ua:$log_cookie” $logging {
“1:1” 1;
default 0;
}
server {
[…]
access_log /var/log/nginx/access.log main;
access_log /var/log/nginx/http_multi_conditions.log main if=$logging;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
使用 if 的方式进行过滤:
server {
[…]
set $logging 0;
set $logtmp "$log_ua$log_cookie"
if ( $logtmp = "11" ) {
set $logging 1;
}
access_log /var/log/nginx/access.log main if=$logging;
}
2
3
4
5
6
7
8
9
10
11
12
13