最可靠方式是在PHP请求入口统一拦截,用microtime(true)打点、ob_start()捕获响应体,结构化记录$_GET/$_POST/$_SERVER等,避免漏记、格式不一及耗时不准。

怎么在 PHP 请求入口统一记录入参、出参和耗时
直接在框架或原生入口处加一层拦截最可靠,不依赖中间件机制也能生效。核心是用 microtime(true) 打点,配合 ob_start() 捕获响应体,再把原始 $_GET、$_POST、$_SERVER 等结构化记录。
- 别在每个控制器方法里手动写日志——漏记、格式不一致、耗时统计不准
- 避免用
register_shutdown_function()捕获响应——可能被exit或异常中断,ob_get_contents()拿不到完整输出 - 注意
$_FILES和大文件上传场景:记录时只存文件名/类型,别序列化整个数组,否则日志爆炸 - 如果用了 Swoole 或 Hyperf,得改用协程上下文(
Co::getContext())存请求 ID,不能依赖全局变量
用 Monolog 记录接口日志时怎么避免性能拖慢
默认 FileHandler 同步写磁盘,高并发下容易阻塞。必须异步化,但不是简单加个 StreamHandler 就完事。
- 用
RotatingFileHandler替代StreamHandler,并设置$maxFiles = 7防止日志滚雪球 - 日志通道必须独立,别和业务日志混用同一个 Handler,否则接口慢会拖垮整个日志系统
- 敏感字段如
password、token要在写入前用正则或白名单过滤,别等日志落盘后再脱敏 - 不要在日志里
json_encode($GLOBALS)—— 可能含资源句柄或递归引用,直接触发致命错误
为什么 var_export($_REQUEST) 会导致日志写入失败
var_export() 遇到资源类型(比如 MySQLi 连接、cURL 句柄)会直接报 PHP Warning: var_export does not handle circular references,导致后续日志逻辑跳过。
- 改用
print_r($data, true)+strip_tags()清理控制字符,更健壮 - 对超长参数(如 Base64 图片)要截断,建议限制单字段 ≤2048 字符,避免日志文件单行过大
- JSON 格式记录更省空间,但得先用
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR),并检查返回是否为false - 如果框架用了 PSR-7 Request 对象(如 Slim、Laminas),别直接 dump
$request->getParsedBody(),它可能已被解析成对象,需先toArray()或getParams()
Apache / Nginx 下怎么拿到真实客户端 IP 和请求路径
反向代理后 $_SERVER['REMOTE_ADDR'] 是内网地址,$_SERVER['REQUEST_URI'] 可能被重写,直接记录会失真。
- 真实 IP 优先读
$_SERVER['HTTP_X_FORWARDED_FOR'](逗号分隔),取第一个非私有地址; fallback 到$_SERVER['HTTP_X_REAL_IP'];最后才用$_SERVER['REMOTE_ADDR'] - 请求路径用
$_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']拼,比$_SERVER['PHP_SELF']更准 - Nginx 需确保配置了
proxy_set_header X-Real-IP $remote_addr;和proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - Apache mod_proxy 下还要加
RequestHeader set X-Real-IP "%{REMOTE_ADDR}s",否则HTTP_X_REAL_IP为空
记录耗时不是简单减法,microtime(true) 必须在 ob_start() 前就打点,且响应体捕获要在 ob_end_flush() 之后立即做——中间夹了任何 echo 或异常处理,耗时就不准了。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











