log_format必须在http块中定义,用于指定Nginx访问日志格式,支持自定义名称与变量组合,可输出普通文本或JSON格式,并通过access_log指令在不同作用域启用。

在 Nginx 的 http 块中,log_format 用于定义访问日志的输出格式,是分析流量、排查问题和对接日志系统的关键配置。它必须在 http 层级声明,不能放在 server 或 location 内(除非使用 log_format 的继承与重定义机制,但基础定义只允许在 http 中)。
log_format 的基本语法与命名规则
log_format 后紧跟一个自定义名称(如 main、json),再跟由引号包裹的格式字符串。名称区分大小写,且不能含空格或特殊符号(建议用下划线或连字符)。Nginx 自带默认格式名为 combined 和 main(部分版本等价),可覆盖或另起新名:
log_format mylog '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';常用变量说明与实用组合
以下变量在 log_format 中高频使用,注意其生效条件:
-
$remote_addr:客户端真实 IP(若经代理,需配合real_ip模块和set_real_ip_from使用) -
$http_x_forwarded_for:代理链中的原始 IP 列表(不直接可靠,需结合real_ip校验) -
$request:完整请求行(如GET /api/v1/user?id=123 HTTP/1.1) -
$status:响应状态码(如200、404、502) -
$body_bytes_sent:响应体字节数(不含响应头,类似$bytes_sent,但更准确) -
$request_time:请求处理总耗时(秒,精度为毫秒,如0.023) -
$upstream_response_time:后端服务响应耗时(多个 upstream 用逗号分隔,如0.012, 0.008) -
$http_<i>header_name</i>:小写横线转下划线获取请求头,如$http_user_agent对应User-Agent
支持 JSON 格式日志(便于 ELK / Loki 接入)
将日志格式化为 JSON 字符串,需手动转义双引号并确保字段值合法(避免非法字符破坏结构)。推荐用单引号包裹整个格式串,内部双引号无需额外转义:
log_format json_log '{'
'"@timestamp":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"body_bytes_sent":$body_bytes_sent,'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time",'
'"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent"'
'}';注意:$upstream_response_time 可能为空或含多个值,生产环境建议用 map 指令预处理;JSON 日志需搭配 access_log 使用,且确保磁盘 I/O 足够支撑高并发写入。
启用与作用域控制
定义好 log_format 后,需在 http、server 或 location 块中用 access_log 指令引用它:
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
<pre class='brush:php;toolbar:false;'>server {
access_log /var/log/nginx/access.log main; # 引用名为 main 的格式
# 或指定不同路径与格式
location /api/ {
access_log /var/log/nginx/api_access.log json_log;
}
}}
同一层级多个 access_log 指令会同时写入;子块中定义的 access_log 会屏蔽父块的配置(除非显式用 access_log off 关闭继承)。










