Nginx变量无法直接拼接结构化键值对,但可通过log_format组合变量与固定字符串,并配合日志解析工具实现;推荐空格分隔、显式键名、小写下划线命名,支持map提取业务字段、$arg_XXX获取参数,Lua可实现动态组装。

Nginx 变量本身不支持直接拼接成结构化键值对(如 user_id=123&action=view),但可通过 log_format 中组合多个变量 + 固定字符串,配合日志解析工具(如 Logstash、Fluentd 或 ELK)实现语义清晰的复合日志字段。关键在于“格式可控、分隔明确、语义可析”。
用 log_format 定义含变量的自定义日志模板
在 http 或 server 块中定义日志格式,用双引号包裹,变量以 $ 开头,固定字符(如 =、&、空格)直接写入:
log_format custom_kv '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'req_time=$request_time '
'upstream_time=$upstream_response_time '
'user_id=$cookie_uid '
'trace_id=$http_x_request_id ';
</font><p>注意:<br>
– 每个键(如 <code>req_time=</code>)显式写出,值为对应变量;<br>
– 键名建议小写+下划线,避免空格和特殊符号;<br>
– 若变量可能为空(如未携带 <code>Cookie</code>),对应位置将输出空字符串,不影响整体格式。</p><H3>提取动态上下文并构造业务键值对</H3><p>利用 Nginx 内置变量或 <code>map</code> 指令生成逻辑字段,再注入日志:</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill11702" title="Nginx Reverse Proxy"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20e695c2374.jpg" alt="Nginx Reverse Proxy" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill11702" title="Nginx Reverse Proxy">Nginx Reverse Proxy</a>
<p>配置 Nginx 反向代理,实现域名绑定。用户说“绑定域名”“配置 Nginx”“反向代理”时触发,将域名绑定到指定 IP:端口。</p>
</div>
<a href="/xiazai/skill11702" title="Nginx Reverse Proxy" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><ul><li>用 <code>map</code> 将请求路径映射为操作类型:<br><font color="#666"><pre class="brush:php;toolbar:false;">map $request_uri $action {
~^/api/v1/users/\d+/profile$ "update_profile";
~^/api/v1/orders$ "create_order";
default "other";
}log_format 中加入:action=$action uri=$request_uri;$arg_XXX(如 $arg_product_id),无需额外模块。确保日志可被下游系统准确切分
复合键值对日志不是 JSON,但要便于解析器识别字段边界:
- 推荐用空格分隔不同键值对(如
user_id=123 status=200),避免嵌套或等号出现在值中; - 若值含空格或特殊字符(如 User-Agent),仍用引号包裹整个字段,但键值对内部保持
key=value形式; - 日志采集端(如 Filebeat)可配置
dissect或kv过滤器,按空格切分后自动解析等号左右为 key/value。
进阶:用 Lua 实现更灵活的键值组装(需 lua-nginx-module)
当需要条件拼接、JSON 编码或调用外部服务时,可借助 ngx.var 和 set_by_lua*:
set_by_lua_block $kv_pairs {
local kv = {}
kv["user_id"] = ngx.var.cookie_uid or "anon"
kv["is_mobile"] = ngx.var.http_user_agent:match("Mobile") and "1" or "0"
kv["latency_ms"] = math.floor(ngx.var.request_time * 1000)
return table.concat({
"user_id=" .. kv.user_id,
"is_mobile=" .. kv.is_mobile,
"latency_ms=" .. kv.latency_ms
}, " ")
}
log_format lua_kv '$remote_addr - $remote_user [$time_local] "$request" $status '
'$body_bytes_sent "$http_referer" "$http_user_agent" $kv_pairs';该方式适合复杂业务逻辑,但会略微增加请求开销,建议仅在必要时启用。

















