在 nginx 中,log_format 指令必须在 http 块内定义,且只能在 http 上下文中使用。它用于指定日志的格式模板和名称,随后在 access_log 指令中通过名称引用该格式。

如何定义包含变量和分隔符的日志格式
定义格式时,第一个参数是自定义的名称(如 main),后续参数是具体的日志内容字符串,可以包含 Nginx 内置变量(如 $remote_addr)和固定文本。Nginx 会按顺序解析这些变量并拼接成一行日志输出。

http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
server {
listen 80;
server_name example.com;
access_log /var/log/nginx/access.log main;
}
}上述配置定义了名为 main 的格式,包含客户端 IP、用户、时间、请求行、状态码、字节数、Referer 和 User-Agent。在 server 块中,通过 access_log 指令将 /var/log/nginx/access.log 文件关联到 main 格式。若未指定格式名称,默认使用 combined 格式。
如何添加自定义变量或修改现有格式
除了使用内置变量,还可以使用 map 指令在 http 块中创建自定义变量,然后在 log_format 中引用。例如,根据请求头或响应码设置自定义标签。注意,log_format 的定义必须位于任何 server 或 location 块之前,因为它是全局生效的配置。

http {
map $status $status_label {
~^[23] OK;
default Error;
}
log_format custom '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" status_type=$status_label';
server {
listen 80;
server_name example.com;
access_log /var/log/nginx/custom_access.log custom;
}
}此示例使用 map 指令将 HTTP 状态码映射为 OK 或 Error,并在 custom 日志格式中引用 $status_label。这样可以在日志中直接看到状态分类,无需事后解析。确保 map 指令也在 http 块中定义,且在 log_format 之前,以保证变量在使用前已初始化。
基于 $request 变量的具体问题分析
当 $request 变量在日志格式中被引用时,它会记录完整的请求行,包括方法、URI 和协议版本。如果请求 URI 中包含特殊字符或未正确编码,日志文件中可能会出现乱码或截断。此外,对于 HEAD 请求,$request 仍会显示为 HEAD /path HTTP/1.1,但实际响应体为空,这可能导致日志大小与实际传输数据不一致。建议在调试时检查 $request 的实际输出,确保 URI 编码符合预期。


















