日志记录不全主因是代码未覆盖所有路径,需主动调用日志函数、统一格式、校验写入结果、避免环境依赖,并确保关键操作100%落盘。

日志记录不全通常是因为代码没覆盖所有路径
PHP日志审计不全,90% 以上是代码里漏写了记录逻辑,不是 php.ini 或 error_log 配置问题。配置只控制“错误是否能被写入”,而审计日志必须由你主动调用 error_log()、file_put_contents() 或日志库(如 Monolog)写入——它不会自动捕获业务行为。
- 常见漏点:
try块外的分支、return提前退出前、异步任务(如pcntl_fork子进程)、CLI 脚本未统一入口 - 别依赖
register_shutdown_function()补漏:它只能捕获致命错误或脚本结束,无法记录正常业务操作(比如用户修改密码成功但没记日志) - 如果用了框架(Laravel、ThinkPHP),检查中间件/事件监听是否注册到所有路由,特别是 API 路由常被忽略
audit_log() 这类自定义函数容易因异常中断而丢日志
很多人封装了 audit_log() 函数统一写日志,但没处理写入失败场景。一旦磁盘满、目录无写权限、NFS 挂载异常,file_put_contents() 返回 false 却没做 fallback 或告警,日志就静默丢失。
- 务必检查返回值:
if (false === file_put_contents($path, $msg, FILE_APPEND | LOCK_EX)) { /* 记录失败本身,或抛异常 */ } - 避免在事务中同步写日志:MySQL 事务回滚时,日志已写入,导致“操作失败但日志显示成功”
- 不要用
echo或var_dump()替代日志:它们不落盘,且在 CLI 或异步上下文里可能被丢弃
日志格式混乱导致关键字段提取失败
审计日志不是“写进去就行”,后续要查、要告警、要对接 SIEM。如果每条日志结构不一致(比如有时带 user_id,有时只有 username;时间用 date() 有时用 microtime(true)),日志系统根本没法解析归一化。
- 强制统一字段:至少包含
timestamp、event_type(如 "login"、"delete_user")、user_id、ip、status(success/fail)、message - 用 JSON 格式写入(而非纯文本):
file_put_contents($log_file, json_encode($entry, JSON_UNESCAPED_UNICODE) . "\n", FILE_APPEND); - 避免在
message里拼接敏感信息(如明文密码、token),应只记操作类型和影响范围
CLI 和 Web 环境日志路径不一致引发丢失
同一个 audit_log() 函数,在 Web 请求里写到了 /var/log/myapp/web.log,但在 Cron 执行的 CLI 脚本里却试图写进 $_SERVER['DOCUMENT_ROOT'] 下的路径——而 CLI 没这个超全局变量,结果路径变成 //audit.log 或直接报错终止。
立即学习“PHP免费学习笔记(深入)”;
- 不要依赖
$_SERVER构建日志路径,改用__DIR__或配置文件定义绝对路径 - CLI 脚本需显式初始化日志目录:
is_dir($dir) || mkdir($dir, 0755, true); - 检查
getcwd()在不同入口下的值,尤其使用chdir()后,相对路径会失效
真正难的不是“怎么写一行日志”,而是让每条关键操作都经过同一套可验证、可追溯、不因环境切换而断裂的日志路径。很多团队卡在“以为配对了就完事”,其实连 file_put_contents() 的返回值都没检查过。



















