要让 apache 的 mod_logio 真正记录每个请求的出入流量,必须同时启用模块、为每个虚拟主机单独定义含 %i/%o 的日志格式,并将日志写入独立文件;%b 仅统计响应体,而 %i/%o 才准确反映真实收发字节数。

要让 Apache 的 mod_logio 真正记录每个请求的出入流量,关键不是“开了模块就行”,而是模块启用 + 每站点独立日志格式 + 正确字段解析三步缺一不可。默认日志里的 %b 只反映响应体大小,不包含响应头、gzip 压缩后体积、chunked 分隔符等真实发出量,统计带宽会严重偏低。
确认并启用 mod_logio 模块
模块未加载时,%I 和 %O 在日志中恒为 -,不是配置错,是功能根本不可用:
- Debian/Ubuntu 系统:运行
apache2ctl -M | grep logio,看到logio_module (shared)才算成功;若无输出,执行a2enmod logio && systemctl reload apache2 - RHEL/CentOS 系统:运行
httpd -M | grep logio,若无结果,编辑/etc/httpd/conf/httpd.conf,取消#LoadModule logio_module modules/mod_logio.so的注释,再systemctl reload httpd - 验证方式:临时在 LogFormat 中加
%I %O,访问一次页面,检查 access_log 对应行是否输出数字而非- -
为每个虚拟主机单独定义带宽日志格式
不能复用全局 common 或 combined 格式——它们不含 %I/%O,也无法区分站点流量。必须在 <virtualhost></virtualhost> 块内定义专属格式:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- 写入如下配置(示例):
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" site_a_bandwidth - %I 是客户端发来的原始 HTTP 请求字节数(含请求头、CRLF、请求体)
-
%O 是 Apache 实际调用
send()发出的响应总字节数(含响应头、gzip 后内容、chunked 分隔符、代理追加头等) - 二者均为纯整数,单位字节,无逗号、无单位,适合脚本直接累加
绑定独立日志路径并启用 per-vhost 统计
多个站点必须使用不同日志文件,否则数据混杂、无法归因:
- 在同一个
<virtualhost></virtualhost>块中添加:CustomLog /var/log/apache2/example.com-bandwidth.log site_a_bandwidth - 路径需确保 Apache 进程有写权限(如
chown root:www-data /var/log/apache2/) - 错误日志也建议分离:
ErrorLog /var/log/apache2/example.com-error.log - 无需额外开启
LogIOTrackTTFB或LogIOTrackInput/Output——这些控制内部指标采集,%I/%O记录只依赖模块加载和格式正确引用
实时提取与静态资源带宽聚合
日志有了,下一步是聚焦路径特征过滤,避免全量扫描:
- 基础实时统计(每行匹配后累加):
tail -f /var/log/apache2/example.com-bandwidth.log | awk '$7 ~ /\.(js|css|png|jpg|webp|woff2?|ttf|svg)$/ && $6 == 200 {sum += $12} END {print "Static KB:", int(sum/1024)}' - 注意列数:假设
%O是第 12 列,实际需按你LogFormat字段顺序从左往右数(空格分隔) - 更实用的是固定窗口滚动统计(如最近 100 行):
while true; do tail -n 100 /var/log/apache2/example.com-bandwidth.log | awk '$7 ~ /\.(js|css|png)$/ && $6 == 200 {sum += $12} END {print strftime("%H:%M:%S"), "KB:", int(sum/1024)}; sleep 10; done










