Nginx日志的一些简单记录


=Start=

缘由:

内部数据安全分析依赖的数据源中Nginx的日志是一个非常重要的组成部分,常规的字段有:

unix_timestamp
user_name
remote_addr
request_method
scheme
domain
uri
args
http_user_agent
http_referer
status
http_x_forwarded_for
http_content_type

因为各种原因(安全隐私、存储成本、性能损耗、……),Nginx日志中请求body和响应body一般没有记录:

request_body
response_body

在前期没有条件的情况下,只能先用以下字段做替代:

request_length
upstream_response_length
bytes_sent

这里简单介绍一下Nginx日志中相关字段的含义,方便后面有需要的时候参考。

正文:

参考解答:
# 官方说明

$request
full original request line
完整的原始请求行

$request_body
request body
请求体

$request_length
request length (including request line, header, and request body)
请求的字节数(包括请求行、请求头和请求体)。

$bytes_sent
number of bytes sent to a client (1.3.8, 1.2.5)
nginx返回给客户端的字节数,包括响应头和响应体。

$body_bytes_sent
number of bytes sent to a client, not counting the response header; this variable is compatible with the “%B” parameter of the mod_log_config Apache module
nginx返回给客户端的响应体的字节数(不含响应头),这个变量和apache模块中的 %B 是兼容的。

$upstream_response_length
keeps the length of the response obtained from the upstream server (0.7.27); the length is kept in bytes. Lengths of several responses are separated by commas and colons like addresses in the $upstream_addr variable.
保存的是从上游upstream服务器获得的响应的长度(0.7.27),长度以字节为单位。多个响应的长度由逗号和冒号分隔,就像$upstream_addr变量中的地址一样。

$bytes_sent(1.3.8, 1.2.5):nginx返回给客户端的字节数,包括响应头和响应体。

$body_bytes_sent:nginx返回给客户端的响应体的字节数(即不含响应头)。

$content_length:“Content-Length”请求头的值,等同于$http_content_length。即,nginx从客户端收到的请求头中Content-Length字段的值,不是nginx返回给客户端响应中的Content-Length字段($sent_http_content_length)的值。

$request_length(1.3.12, 1.2.7):请求的字节数(包括请求行、请求头和请求体)。注意,由于$request_length是请求解析过程中不断累加的,如果解析请求时出现异常或提前完成,则$request_length只是已经累加部分的长度,并不是nginx从客户端收到的完整请求的总字节数(包括请求行、请求头、请求体)。例如,向nginx的静态文件的URL POST数据,则POST的数据(即请求体)不会计算在内。

$upstream_response_length(0.7.27):保存从upstream服务器获得的响应体的字节数,不包括响应头,1.11.4中增加的$upstream_bytes_received变量是包括响应头的。如果有多个响应长度的话使用逗号和冒号分隔,就像$upstream_addr中的地址那样。

如果想记录请求头内容,可以使用
lua_need_request_body on;
log_format log_body '[$time_local] "$request" "$request_body"';

server {
  location / {
    content_by_lua 'ngx.say("ok")';
    access_log /var/log/nginx/lua.log log_body;
  }
}
如果想记录响应体大小,需要记录的字段
$bytes_sent
$upstream_response_length

# 如果Nginx是作为代理服务器使用的,一般 bytes_sent 的值会比 upstream_response_length 要大,因为在代理层可能会注入一些内容
log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';


# 使用 body_filter_by_lua 记录响应内容的配置样例
worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
    log_format log_req_resp '$remote_addr - $remote_user [$time_local] '
        '"$request" $status $body_bytes_sent '
        '"$http_referer" "$http_user_agent" $request_time req_body:"$request_body" resp_body:"$resp_body"';

    server {
        listen 8082;
        access_log logs/access.log log_req_resp;

        lua_need_request_body on;

        set $resp_body "";
        body_filter_by_lua '
            local resp_body = string.sub(ngx.arg[1], 1, 1000)
            ngx.ctx.buffered = (ngx.ctx.buffered or "") .. resp_body
            if ngx.arg[2] then
                ngx.var.resp_body = ngx.ctx.buffered
            end
        ';

        location / {
            echo "Hello World!";
        }
    }
}
1. 获取到所有请求的响应数据
2. 对所有请求的响应数据进行敏感信息检测
3. 检测到敏感数据响应,进行脱敏处理后再进行响应

-- access_by_lua_file:
ngx.say("123")
ngx.say("456")

-- body_filter_by_lua_file:
local chunk, eof = ngx.arg[1], ngx.arg[2]
print(chunk, eof)

-- 结果
-- body_filter_by_lua*首次调用时:123 false
-- body_filter_by_lua*第二次调用时:456 false
-- body_filter_by_lua*第三次调用时: 空 true
参考链接:

$bytes_sent、$body_bytes_sent、$content_length、$request_length、$upstream_response_length详解
https://www.jianshu.com/p/11ec806f3c42

Module ngx_http_log_module
https://nginx.org/en/docs/http/ngx_http_log_module.html

Module ngx_http_core_module – Embedded Variables
https://nginx.org/en/docs/http/ngx_http_core_module.html#var_bytes_sent

Module ngx_http_upstream_module – Embedded Variables
https://nginx.org/en/docs/http/ngx_http_upstream_module.html

Logging Request/Response size in access_log of Nginx
https://serverfault.com/questions/346853/logging-request-response-size-in-access-log-of-nginx

浅谈OpenResty中的body_filter_by_lua*
https://zhuanlan.zhihu.com/p/67904411

OpenResty – 执行阶段概念
https://moonbingbing.gitbooks.io/openresty-best-practices/content/ngx_lua/phase.html

body_filter_by_lua
https://github.com/openresty/lua-nginx-module#body_filter_by_lua

body_filter_by_lua_file
https://github.com/openresty/lua-nginx-module#body_filter_by_lua_file

Is it possible to log the response data in nginx access log?
https://serverfault.com/questions/361556/is-it-possible-to-log-the-response-data-in-nginx-access-log

Full request/response body logging in nginx
https://gist.github.com/morhekil/1ff0e902ed4de2adcb7a

NGINX Plus – Admin Guide – Monitoring – Configuring Logging
https://docs.nginx.com/nginx/admin-guide/monitoring/logging/

听说你的Nginx还不会记录Response Body?
https://juejin.cn/post/6844904147570032648

How to change Content-length in body_filter_by_lua* in openresty
https://stackoverflow.com/questions/45356766/how-to-change-content-length-in-body-filter-by-lua-in-openresty

How to log request body
https://onelinerhub.com/nginx-lua/how-to-log-request-body

=END=


发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注