nginx 适配 grafana loki 的关键是输出 rfc3339 时间戳的结构化 json 日志并配置 promtail 提取标签;需定义含 app、level 等字段的 log_format,启用 access_log,再在 promtail 中通过 json 解析器映射字段为 labels。

要让 Nginx 日志适配 Grafana Loki,关键不是“完全匹配 Loki 规范”(Loki 本身不定义日志格式),而是输出结构清晰、带关键标签字段(如 level、app、host)的 JSON 日志,并确保时间戳为 RFC3339 格式(如 2024-05-20T14:23:15.123Z),便于 Promtail 正确解析和打标签。
1. 定义兼容 Loki 的 JSON log_format
Loki 依赖 Promtail 提取日志中的 label 字段(如 {app="nginx", level="info"})。推荐使用 log_format 输出标准 JSON,包含常用可观测字段:
log_format loki_json '{"@timestamp":"$time_iso8601",'
'"app":"nginx",'
'"level":"$status",'
'"method":"$request_method",'
'"path":"$request_uri",'
'"status":$status,'
'"bytes_sent":$bytes_sent,'
'"body_bytes_sent":$body_bytes_sent,'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time",'
'"upstream_addr":"$upstream_addr"}';
说明:
-
$time_iso8601是 RFC3339 兼容时间戳,Promtail 默认能识别为timestamp -
"level":"$status"是临时映射(也可用 map 指令映射 2xx→info、4xx→warn、5xx→error) - 所有字段都加双引号、转义特殊字符(Nginx 1.11.8+ 原生支持 JSON 转义,无需额外模块)
- 避免在 JSON 中拼接未过滤的用户输入(如
$request_uri可能含双引号或换行,实际生产建议用$request_uri或更安全的$uri+$args分离)
2. 在 server 或 http 块中启用该格式
指定 access_log 使用刚定义的格式,并推荐关闭默认日志以避免重复:
access_log /var/log/nginx/access.log loki_json; error_log /var/log/nginx/error.log warn; # error_log 不支持自定义 format,保持文本即可
注意:
- 确保
/var/log/nginx/目录存在且 Nginx 进程有写入权限 - 若需多 server 区分 app 标签,可为不同虚拟主机定义不同 format,例如
"app":"api-gateway"
3. 配合 Promtail 正确提取 labels(关键一步)
Nginx 日志本身只是文本,真正打 label 是 Promtail 的职责。需在 Promtail 配置中启用 json 解析器,并将字段映射为 labels:
scrape_configs:
- job_name: nginx
static_configs:
- targets:
- localhost
pipeline_stages:
- json:
expressions:
app: app
level: level
status: status
method: method
path: path
remote_addr: remote_addr
- labels:
app:
level:
status:
method:
这样 Promtail 会从每条 JSON 日志中提取 app 和 level 等字段,自动作为 Loki 的流标签(stream selector),例如:{app="nginx", level="404"}
4. 可选:增强 level 字段语义(推荐)
直接用 $status 作 level 不够语义化。可用 Nginx 的 map 指令做映射:
map $status $log_level {
~^[2] info;
~^[3] info;
~^[4] warn;
~^[5] error;
default info;
}
<p>log_format loki_json '{"@timestamp":"$time_iso8601",'
'"app":"nginx",'
'"level":"$log_level",'
...</p>再配合 Promtail 的 labels 阶段,就能得到更准确的 {level="warn"} 标签,方便 Loki 查询告警日志。











