Nginx 记录日志的几种方法

Nginx的日志记录主机设置

server {
listen       80;
server_name a8z8.com;
root /etc/www/abc;

access_log /var/log/www/abc/access.log;
location / {
index  index.htm index.htm;
}
}


默认情况下,access_log 会使用 combined 的配置来记录访问日志

log_format combined ‘$remote_addr – $remote_user [$time_local]  ‘
‘”$request” $status $body_bytes_sent ‘
‘”$http_referer” “$http_user_agent”‘;
通常这样就足够了。

如果是为了更加方便的日志分析,通常我们会使用特殊字符(如 ^A) 来作为日志字段的分隔符,
这样无论是过滤还是排序都会十分方便。甚至可以直接导入 mysql/hive 中,使用强大的 sql 来做查询分析。

为了排版方便,所有特殊字符都使用了展开的写法,请自行替换 ^A 为 ctrl+v,ctrl+a (nginx 日志格式不支持 \1 的写法)。

自定义日志格式:

server {
listen       80;
server_name a8z8.com;
root /etc/www/abc;

# 更多日志可用字段(基本上都是 nginx 的变量),见
#
#
#
log_format abc “$remote_addr^A$remote_user^A$time_local^A$request_method^A$uri^A$args^A$server_protocol”
“^A$status^A$body_bytes_sent^A$http_referer”
“^A$http_user_agent”;
access_log /var/log/www/abc/access.log abc;
location / {
index  index.htm index.htm;
}
}
当把日志使用 ^A 分割以后,后续就可以使用 sort 和 grep 之类工具对特定url做分析了,
比如统计各url请求量倒排取前50个
awk -F^A ‘{print $5}’ /var/log/www/abc/access.log | sort | uniq -c | sort -nr | head -50
有时候可能想对记录的字段做一些处理,比如 $arg_q 可能是搜索关键词,记录的时候如果 unescape 一下,
会更方便分析,存储上也会更小,
那么可以使用 NginxHttpSetMiscModule 模块提供的指令( )实现:
set_unescape_uri $q $arg_q;

log_format abc “$q”;
有时候,我们需要对字段做 hash 转换,可以使用 HttpMapModule 提供的功能()
# 需要放到 http 里面,不能放到 server 里
# 根据 url 地址计算分类,便于后续统计
# 具体根据需求做变换就好了
# 第一列是匹配规则,后面的是赋值 ~ 开头的匹配规则是正则
map $uri $typ {
default               -;

~/login              user;
~/my                 user;
~/static             static;
}

log_format abc “$typ^A$uri”;
如果使用 nginx 比较多,可能会尝试使用 if ,建议不要使用,因为nginx的if比较让人混乱。
如果有更多复杂的字段处理需求,可以使用 ngx_lua ()。
ngx_lua 里面操作 nginx 变量
# 实现上面 map 类似的功能
# 用法详见
# lua 语法见
set_by_lua $typ ”
local uri = ngx.var.uri
local _m = string.match
local v = ‘-’
if _m(uri, ‘^/login’) then
v = ‘user’
elseif _m(uri, ‘^/my’) then
v = ‘user’
elseif _m(uri, ‘^/static’) then
v = ‘static’
end

return v
“;
某些情况下,可能我们的字段处理需要查询缓存(如redis)、数据库(如mysql)等,
这些都是可以使用 ngx_openresty 高效完成的()。
这些功能就不在这一篇详细描述了,后续篇章会补充这些功能。
再描述一些复杂的日志记录功能吧。

有时候我们希望根据请求,来判断是否需要记录这一条日志。
在web的访问日志中这种需求比较少,但是独立的日志收集服务器一般有这样的需求的。
比如我需要判定,请求参数 arg_id 必须存在且为数字的时候我才记录日志,可以这样实现
server {
listen       80;
server_name a8z8.com;
root /etc/www/abc;

log_format abc “$msec^A$args^A$q^A$ie^A$oe^A$ref”
“^A$http_user_agent”;
access_log off;
location / {
# 专门记日志的服务,对非合法请求,直接断开连接 或者根据需求302到自己的站点
# 但是这种302一般不会被用户看到 可以综合考虑做法
# 444 的意义见
return 444;
}
location = /i-log {
internal;

set_unescape_uri $q $arg_q;
set_unescape_uri $ie $arg_ie;
set_unescape_uri $oe $arg_oe;
set_unescape_uri $ref $arg_ref;

# 这个很重要,否则不会记录的
log_subrequest on;

access_log /var/log/www/abc/access.log abc;
# 这个指令需要 HttpEchoModule () 的支持
# 因为这个地址只是为了辅助记录日志,所以不需要返回内容
echo ”;
}
location = /1.gif {
default_type  image/gif;
access_log off;

access_by_lua ”
local q = ngx.var.arg_q
if q then
q = ngx.unescape_uri(q)
if q and #q > 0 then
ngx.location.capture(‘/i-log?’ .. ngx.var.args)
end
end
“;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/8863833c275e47da5f8d04b6909caeeb.html