ThinkPHP需配置log.php的level包含error/notice/alert、file路径为绝对路径、single设为false,并在入口注册register_shutdown_function捕获Fatal Error;同时将flush_interval设为1确保日志实时写入。
如何让ThinkPHP自动记录完整错误日志到指定文件
默认情况下,ThinkPHP在
时只写
下的日志,且不包含堆栈、请求参数等关键信息——这会导致线上问题排查困难。
必须手动配置日志驱动和级别:
在
中设置
,并确保
(不能只留
,否则
类警告不会被捕获)
要指向有写权限的绝对路径,相对路径在CLI模式下容易错位
务必关闭
(默认为
),否则每天日志会覆盖,丢掉异常时间线
捕获未被try-catch兜住的致命错误(Fatal Error)
ThinkPHP内置的
对
无能为力,因为PHP在解析或执行阶段崩溃时根本进不了框架生命周期。
需在入口文件
最顶部注册底层处理器:
立即学习
“
PHP免费学习笔记(深入)
”;
注意:
只能拿到最后一次错误,所以这个钩子必须放在所有其他
之前;另外
不包含
,别误以为它能捕获所有报错。
异常触发企业微信/钉钉告警的最小可行配置
不要直接在
里发HTTP请求——框架尚未完成初始化,
、
可能不可用,且阻塞响应。
推荐用异步+队列方式落地:
在
的
方法里,只做轻量动作:
单独写一个
命令,用
或
调用钉钉机器人Webhook,超时设为
,失败自动重试最多2次
避免在
里发告警——那是渲染错误页面用的,用户还没看到页面就收到告警,体验奇怪
为什么
有时没写进文件,但
却有
这是ThinkPHP日志缓冲机制导致的:默认启用
,即每10条日志才刷一次磁盘。如果进程意外退出(如超时kill),最后几条就丢了。
线上环境建议:
把
,牺牲一点性能换日志完整性
禁用
(默认
),JSON格式在日志切割或grep时反而难处理
确认
不为0,否则修改了
配置也不会生效
监控不是配完就完事,真正难的是让每一条
都留下痕迹,而不是靠重启后看有没有新日志来反推问题。
APP_DEBUG = falseruntime/log/config/log.php'default' => 'file''level' => ['error', 'notice', 'alert']'error'trigger_error()'file' => ['path' => '/var/log/thinkphp/']'single' => truefalsethink\exception\HandleFatal errorpublic/index.phpregister_shutdown_function(function () {
if ($error = error_get_last()) {
if (in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
$log = date('Y-m-d H:i:s') . " FATAL: {$error['message']} in {$error['file']}:{$error['line']}\n";
file_put_contents('/var/log/thinkphp/fatal.log', $log, FILE_APPEND | LOCK_EX);
}
}
});error_get_last()register_shutdown_functionE_ERRORE_WARNINGAppExceptionHandleConfigLogapp/exception/Handle.phpreport()queue_push('alert', ['msg' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()])command/AlertSendcurlfile_get_contents3srender()Log::error()error_log()'flush_interval' => 10'flush_interval' => 1'json' => truefalseopcache.revalidate_freqlog.phpFatal error