将 OpenResty 的日志(主要是访问日志,错误日志也可适配)输出为标准的 JSON 格式,方便后续日志解析、检索(如对接 ELK、Loki 等日志系统)。提供完整的配置方法,包含核心的日志格式定义、转义处理(避免 JSON 格式不合法),以及可直接复用的配置示例。
核心原理
OpenResty/Nginx 的 log_format 指令支持自定义日志格式,通过拼接 JSON 字符串、引用 Nginx/OpenResty 内置变量,并对特殊字符(如双引号、换行、斜杠)做转义,即可生成合法的 JSON 日志。
一、完整配置示例(访问日志 JSON 化)
1. 基础配置(nginx.conf)
在 OpenResty 的主配置文件(如 /opt/tmp/openresty-test/nginx/conf/nginx.conf)中,按以下结构修改:
# 全局块(可选,优化日志相关参数)
worker_processes auto;
error_log logs/error.log warn; # 错误日志暂保持默认,后面会讲JSON化方案
pid logs/nginx.pid;
# HTTP 块:定义 JSON 格式的日志模板
http {
include mime.types;
default_type application/octet-stream;
# ========== 核心:定义 JSON 格式的访问日志模板 ==========
log_format json_log escape=json # escape=json 自动转义双引号/换行等特殊字符
'{'
'"@timestamp":"$time_iso8601",' # 日志时间(ISO8601格式,便于解析)
'"remote_addr":"$remote_addr",' # 客户端IP
'"x_forwarded_for":"$http_x_forwarded_for",' # 反向代理后的真实IP
'"remote_user":"$remote_user",' # 认证用户(无则为空)
'"request_method":"$request_method",' # 请求方法(GET/POST等)
'"request_uri":"$request_uri",' # 完整请求URL(含参数)
'"request_length":"$request_length",' # 请求体大小
'"status":"$status",' # 响应状态码
'"body_bytes_sent":"$body_bytes_sent",' # 响应体大小
'"bytes_sent":"$bytes_sent",' # 总发送字节数
'"referer":"$http_referer",' # 来源页
'"user_agent":"$http_user_agent",' # 客户端UA
'"request_time":"$request_time",' # 总请求耗时(秒,含小数)
'"upstream_connect_time":"$upstream_connect_time",' # 上游连接耗时
'"upstream_response_time":"$upstream_response_time",' # 上游响应耗时
'"server_name":"$server_name",' # 匹配的服务器名
'"scheme":"$scheme",' # http/https
'"host":"$host",' # 请求头的Host
'"nginx_version":"$nginx_version"' # Nginx/OpenResty版本
'}';
# 其他基础配置
sendfile on;
keepalive_timeout 65;
# ========== 应用 JSON 日志格式到具体服务 ==========
server {
listen 80;
server_name localhost;
# 引用上面定义的 json_log 格式,指定日志输出路径
access_log logs/access_json.log json_log;
# 测试接口(可选,用于验证日志)
location / {
default_type text/plain;
content_by_lua_block {
ngx.say("Hello OpenResty!")
}
}
}
}
2. 关键配置说明
| 配置项 | 作用 |
|---|---|
log_format json_log escape=json | 定义名为 json_log 的日志格式,escape=json 是核心:自动转义 JSON 中的特殊字符(如 " 转成 \"、换行符转成 \n),避免 JSON 格式非法 |
$time_iso8601 | 标准化时间格式(如 2026-01-12T10:00:00+08:00),比默认时间更易解析 |
各类 $xxx 变量 | OpenResty/Nginx 内置变量,对应请求的核心信息(完整变量列表可参考官方文档) |
二、错误日志 JSON 化(进阶)
OpenResty 的错误日志默认是纯文本格式,无法直接通过 log_format 定义 JSON,但可通过 lua-nginx-module 实现自定义错误日志输出:
1. 配置示例(在 http 块中添加)
http {
# 先定义错误日志的JSON输出函数(通过Lua)
lua_shared_dict error_log_dict 10m; # 共享内存(可选,用于缓存)
init_by_lua_block {
-- 自定义错误日志JSON格式化函数
function log_error_json(level, msg)
local error_json = {
["@timestamp"] = ngx.localtime(),
["level"] = level,
["message"] = msg,
["pid"] = ngx.worker.pid(),
["hostname"] = ngx.var.hostname or "unknown"
}
-- 将JSON写入错误日志文件(路径需和error_log一致)
local f = io.open(ngx.config.prefix() .. "/logs/error_json.log", "a")
if f then
f:write(cjson.encode(error_json) .. "\n")
f:close()
end
end
-- 注册全局错误日志钩子
ngx.log = function(level, ...)
local msg = table.concat({...}, " ")
log_error_json(ngx.errlog.level_by_num[level], msg)
-- 保留原生错误日志输出(可选)
require("ngx.errlog").log(level, msg)
end
}
# 禁用原生错误日志(或保留,根据需求)
error_log logs/error_json.log notice;
}
2. 注意事项
- 需确保 OpenResty 启用了
lua-nginx-module(你当前编译的版本已包含); - 依赖
cjson库(OpenResty 内置,无需额外安装); - 错误日志的 JSON 化属于进阶需求,若仅需解析访问日志,可忽略这一步。
三、验证配置是否生效
1. 检查配置语法
# 进入OpenResty的nginx目录
cd /opt/tmp/openresty-test/nginx/sbin
# 检查配置语法是否正确
./nginx -t
输出 nginx: configuration file /opt/tmp/openresty-test/nginx/conf/nginx.conf test is successful 即配置合法。
2. 重启 OpenResty
./nginx -s reload
3. 触发请求并查看日志
# 访问测试接口
curl http://localhost
# 查看JSON格式的访问日志
cat /opt/tmp/openresty-test/nginx/logs/access_json.log
预期输出(JSON 格式):
{
"@timestamp":"2026-01-12T10:15:30+08:00",
"remote_addr":"127.0.0.1",
"x_forwarded_for":"",
"remote_user":"",
"request_method":"GET",
"request_uri":"/",
"request_length":"0",
"status":"200",
"body_bytes_sent":"16",
"bytes_sent":"81",
"referer":"",
"user_agent":"curl/7.81.0",
"request_time":"0.000",
"upstream_connect_time":"-",
"upstream_response_time":"-",
"server_name":"localhost",
"scheme":"http",
"host":"localhost",
"nginx_version":"1.27.1"
}
四、常见问题与优化
1. JSON 格式非法(如双引号未转义)
- 必加
escape=json参数(在log_format后),OpenResty 会自动转义"、\、换行符等; - 避免在日志中手动拼接双引号,优先使用内置变量。
2. 日志字段缺失(如 $upstream_response_time 为空)
- 仅当请求转发到上游服务(如
proxy_pass)时,upstream_xxx变量才有值,否则显示-(正常); - 可通过
map指令替换空值为null(JSON 规范):http { map $upstream_response_time $upstream_time { "" "null"; default $upstream_response_time; } # 然后在log_format中使用 $upstream_time 替代 $upstream_response_time }
3. 日志性能优化
- 启用
access_log buffer=32k flush=5s:缓冲日志写入,减少磁盘 IO(适合高并发场景);access_log logs/access_json.log json_log buffer=32k flush=5s; - 避免在日志中添加过多冗余字段(如不使用的
$request_completion)。
总结
- 核心步骤:在
http块定义log_format json_log(带escape=json)→ 在server块引用access_log xxx json_log→ 重启验证; - 关键保障:
escape=json是避免 JSON 格式非法的核心,必须添加; - 进阶优化:错误日志可通过 Lua 自定义 JSON 输出,访问日志可开启缓冲提升性能。
这套配置可直接用于生产环境,输出的 JSON 日志能被大部分日志分析工具(ELK、Grafana Loki、Fluentd 等)无缝解析。