怎样配置 log_format 捕获 $body_bytes_sent 变量精准统计网站静态资源的外发流量带宽

作者:袖梨 2026-06-17
精准统计网站静态资源外发流量需在http块定义含$body_bytes_sent的log_format,各server块独立启用并指定唯一access_log路径,$body_bytes_sent准确记录压缩后响应体字节数,验证时检查日志第6字段是否为非零值。

要精准统计网站静态资源的外发流量带宽,核心是让 log_format 稳定捕获 $body_bytes_sent,并确保它能真实反映 JS、CSS、图片等静态内容发出的字节数(不含响应头)。这个变量本身不需额外模块,但必须显式写入日志格式,且配置位置和上下文要正确。

必须在 http 块中定义含 $body_bytes_sent 的自定义格式

不能依赖默认 combined 格式——它不含 $body_bytes_sent。需在 http{...} 区块内明确定义:

log_format static_flow '$host $remote_addr [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';

说明:

  • $host$server_name 更适合多租户场景,它取自请求头 Host 字段,能区分同一 IP 下不同域名;
  • $body_bytes_sent 是纯响应体字节数,对 200/304/206 均有效,gzip 压缩后的体积已自动计入;
  • 避免把 $body_bytes_sent 放在日志末尾以外的位置,否则后续用 awk 提取时列数易错;
  • 若站点启用了 CDN 回源,该字段仍准确记录 Nginx 实际发出的字节数,可用于比对缓存命中率。

每个 server 块必须独立启用该格式并指定日志路径

不能多个站点共用一个 access_log 文件——否则无法按站分离统计。例如:

server {
  server_name example.com;
  root /var/www/example;
  access_log /var/log/nginx/example.com-static.log static_flow;
}

关键点:

  • 每个 server 必须有唯一 access_log 路径,推荐按域名命名;
  • 静态资源(如 .js.png)由 Nginx 直接返回时,天然计入 $body_bytes_sent,无需额外 location ~* .(js|css) 配置;
  • 若使用了 try_filesalias,只要最终响应来自本地文件系统,该变量就有效。

验证是否生效与常见失效原因

重载配置后,立即访问一个静态资源(如 /style.css),检查日志是否出现非零数字:

example.com 192.168.1.100 [16/Jun/2026:19:30:22 +0800] "GET /style.css HTTP/1.1" 200 12480 "https://example.com/" "Mozilla/5.0..."

若第 6 字段(即 $body_bytes_sent)为 -0,常见原因有:

  • Nginx 版本低于 1.3.12(该变量自此时起稳定支持);
  • 请求触发了 304(Not Modified)或 204(No Content)响应,此时响应体为空,值为 0 —— 这属于正常行为,不是配置错误;
  • 日志路径所在目录不可写,或磁盘满导致日志未落盘,看似没输出;
  • 配置修改后未执行 nginx -s reload,旧进程仍在运行。

轻量实时统计方法(不依赖外部系统)

日志就绪后,可用以下命令秒级查看各站点当前静态流量趋势:

tail -f /var/log/nginx/*.log | awk '$6 == 200 && $7 ~ /.(js|css|png|jpg|webp|woff2?)$/ {sum[$1] += $6} NR % 50 == 0 {for (h in sum) print h, sum[h] "B"; delete sum}'

说明:

  • 过滤状态码 200 且路径匹配典型静态后缀,排除动态接口干扰;
  • $1$host$6$body_bytes_sent(按上面定义的格式顺序);
  • NR % 50 == 0 表示每累计 50 条匹配日志输出一次汇总,适合中低流量站点;
  • 高流量场景建议改用 nginxlog-exporter 接入 Prometheus,用 rate(nginx_log_entry_body_bytes_sent_sum[1m]) 计算实时带宽(单位 bytes/sec)。

相关文章

精彩推荐