%D记录Apache层耗时(含网络接收与响应头发送),单位微秒;X-Process-Time需Java应用主动设置响应头,Apache用%{X-Process-Time}o捕获,二者相减可估算网络延时。
在虚拟主机中用 mod_log_config 记录“真实处理时长”和“网络延时”,关键要分清两个概念:apache 自身的请求生命周期耗时(含网络接收与响应头发送),以及 java 等后端应用内部的真实处理时间。apache 本身不感知后端逻辑,必须靠应用层配合才能拿到后者。
记录 Apache 层面的请求耗时(含网络环节)
这是最直接、无需应用修改的方式,反映从客户端发包到 Apache 发出响应头的总耗时,已包含网络接收延迟和 Apache 自身调度开销:
- 使用
%D格式符,单位为微秒 —— 表示“接收到第一个字节”到“响应头发送完毕”的时间 - 在虚拟主机配置中添加自定义日志格式,例如:
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/html
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" combined_with_apache_time
CustomLog logs/example_access.log combined_with_apache_time
</VirtualHost> - 日志末尾数字如
124589即约 124.6 ms,可直接用于分析网络抖动或 Apache 响应瓶颈
记录 Java 应用真实处理耗时(需后端配合)
若你用的是 Tomcat、Spring Boot 等 Java 后端,%D 不包含 Servlet 执行、数据库查询等时间。要补上这部分,必须由 Java 应用主动计算并写入响应头:
- Java 端(如 Filter 中)设置响应头:
response.setHeader("X-Process-Time", String.valueOf(System.currentTimeMillis() - startTime)); - Apache 配置中用
%{X-Process-Time}o捕获该值(注意o表示 output header):
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D %{X-Process-Time}o" java_full_timing - 确保 Java 应用确实设置了该头,否则日志对应位置显示
-
分离网络延时与后端处理延时
有了两组数据,就能做简单减法估算纯网络传输耗时(近似):
-
网络+Apache调度耗时 ≈
%D -
后端真实处理耗时 ≈
%{X-Process-Time}o(前提是应用设置准确) -
粗略网络延时(往返) ≈
%D - %{X-Process-Time}o(仅当后者 ≤ 前者且非空时成立) - 若差值持续较大(如 >50ms),说明网络链路或 Apache 接收/发送存在瓶颈;若
%D小但X-Process-Time大,则问题在后端
注意事项与常见陷阱
这些配置看似简单,但容易忽略几个细节:
-
%D统计截止点是“响应头发送完成”,不是整个响应体;若响应体很大(如文件下载),实际用户感知延迟会更高 - 不要用
%T替代%D—— 它只保留整秒,丢失毫秒级精度,无法支撑性能分析 - 虚拟主机若启用了 SSL/TLS,
%D已包含 TLS 握手后的 HTTP 处理时间,但不包括握手本身(握手耗时需用 OpenSSL 或 tcpdump 单独分析) - 若日志中
%{X-Process-Time}o大量为空,先检查 Java 应用是否在所有路径(包括异常分支)都设置了该头

















