nginx多租户日志分离需用map提取tenant_id,结合log_format定义结构化格式,并通过access_log写入租户独立文件或syslog直发采集器;采集器须透传tenant_id标签以实现下游隔离。

在 Nginx 中为多租户系统配置独立日志收集代理,核心是按租户维度分离访问日志,并将日志定向到不同后端(如 Fluentd、Logstash 或 Loki),而非统一写入本地文件。这需要结合 log_format、map 指令提取租户标识,再通过 access_log 动态指定日志路径或借助 syslog 协议转发。
基于租户域名或请求头识别租户
多租户通常通过子域名(tenant1.example.com)、路径前缀(/t/tenant1/...)或自定义 Header(如 X-Tenant-ID)区分。Nginx 本身不支持直接向远程日志服务发送结构化日志,因此推荐先用 map 提取租户 ID,再用于日志格式或转发控制:
- 用
map从$host提取子域名:map $host $tenant_id { ~^(?<t>[a-z0-9\-]+)\.example\.com$ $t; default "default"; }</t> - 或从 Header 获取:
map $http_x_tenant_id $tenant_id { "" "default"; default $http_x_tenant_id; }
为每个租户生成独立日志格式
定义带租户字段的 log_format,便于后续日志采集器按租户过滤或路由:
- 在
http块中定义格式:log_format tenant_json escape=json '{' '"time": "$time_iso8601",' '"tenant": "$tenant_id",' '"remote_addr": "$remote_addr",' '"request": "$request",' '"status": "$status",' '"bytes_sent": "$bytes_sent",' '"upstream_time": "$upstream_response_time",' '"http_user_agent": "$http_user_agent"' '}'; - 在
server或location中启用该格式并写入本地文件(供 Filebeat 采集):access_log /var/log/nginx/tenants/$tenant_id-access.log tenant_json;
注意:$tenant_id必须已在当前作用域解析(需确保map在http级定义且变量可用)。
通过 syslog 协议直连日志收集代理
若日志收集器(如 Fluentd、rsyslog)监听 UDP/TCP syslog 端口,可跳过本地文件,直接由 Nginx 发送:
- 启用 syslog 日志目标(Nginx ≥ 1.7.1):
access_log syslog:server=127.0.0.1:5140,facility=local7,tag=nginx_tenant_$tenant_id tenant_json;
- Fluentd 示例配置(接收并路由):
<source> @type syslog port 5140 protocol_type udp tag nginx.tenant </source><filter nginx.tenant> @type record_transformer <strong>rewrite_tag</strong> nginx.tenant.${record["tenant"]} </filter>
配合采集器实现租户隔离与投递
Nginx 不处理日志归档、脱敏或投递逻辑,这部分交由专用采集器完成:
- Filebeat:使用
filebeat.inputs.paths按租户目录通配(如/var/log/nginx/tenants/*-access.log),并在processors中添加add_fields注入tenant_id字段; - Loki + Promtail:利用
pipeline_stages从日志行提取tenant标签,再通过labels路由到不同租户流; - 关键点:所有采集器必须将
tenant_id作为结构化字段或标签透传,下游存储(ES/Loki)才能按租户查询、限流和计费。











