如何调试 PHP (Laravel) 中的 "Symfony\Component\Debug\Exception\FatalErrorException" 错误?
How to debug "Symfony\Component\Debug\Exception\FatalErrorException" errors in PHP (Laravel)?
我收到客户遇到的许多错误的报告
Symfony\Component\Debug\Exception\FatalErrorException
Maximum execution time of 30 seconds exceeded
我本人无法在本地计算机或生产服务器上复制它。这个 URL 遍布整个网站,所以,我猜这是全球性的东西,比如导致这个的中间件。
我正在使用 Sentry.io 收集数据,但异常跟踪只有 1 个条目指向 Symfony
基本代码中的某个代码,最常见的是:
vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php at line 73
vendor/symfony/finder/Iterator/DateRangeFilterIterator.php at line 45
vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php at line 69
很明显,似乎与文件系统有关,但由于没有踪迹,我看不到在站点代码中查找错误的位置。我猜这是某种无限循环或泄漏,但没有痕迹可以查看,也没有一致的方法来重现问题。
我应该如何查找问题并进行调试?
有没有我可以设置的设置,或者我可以使用的工具use/enable?
如果您不确定异常的原因,那么您可以通过两种方式处理
1
增加请求超时
ini_set('max_execution_time', 60); //60 秒 = 1 分钟
2 将您的代码包装在 try catch
中
try{
//logic goes here
}catch(\Excaption $e){
Log::error($e->getMessage().' '. $e->getFile().' '. $e->getLine());
return back()->with('error',$e->getMessage() );
}
我认为您现在不应该增加超时。如果您执行 "try catch",您可能会了解潜在的问题。如果不是,请检查在特定方法或 class 中执行的操作/功能。您可能正在查询一个巨大的 table 并且可能正在尝试使用该信息。
如果你这样做
\DB::listen(function ($sql) {
var_dump($sql);
});
这会告诉您有多少查询是 运行 操作
无法在 try catch 中捕获它,因为它实际上是 PHP 错误而不是异常。
为了能够对此进行调试,您有两种选择:
- 在代码中添加一些日志来识别超时的地方
- 您可以使用Laravel dump server package 来转储日志。这实际上将与 Laravel 5.7 一起运送,但您现在可以随时添加包裹
我安装了laravel-debugbar.I觉得对你有帮助。
作曲家要求barryvdh/laravel-debugbar
接下来打开 config/app.php 并在“providers”数组中添加:
Barryvdh\Debugbar\ServiceProvider::class,
在别名数组中 class:
'Debugbar' => Barryvdh\Debugbar\Facade::class,
您可以查看
Debugbar::measure('My long operation', function() {
// 做点什么……
});
可以注册关机功能吗?
即使发生超时,也会调用关闭函数。有了它,您可以打印或保存您想要的日志文件。
我不确定是否有更好的方法在 laravel 中获取回溯,但这就是我在纯 php 中可能会做的(调用 debug_backtrace)。
<?php
function timedOut() {
//save to a log file instead of printing
var_dump(debug_backtrace());
}
register_shutdown_function("timedOut");
http://php.net/manual/en/function.register-shutdown-function.php
阅读您的聊天对话后,我看到您正在使用此 .env
配置:
CACHE_DRIVER=file
SESSION_DRIVER=file
我认为这是问题所在...我解释得更好一些。
当您将 file
驱动程序用于缓存或会话时,Laravel 将创建大量文件来存储用户会话数据或应用程序缓存数据...
如果您的电子商务正在增长并产生大量流量,那么性能可能会降低,因为框架必须扫描大量文件。
我认为可能有两种可能的解决方案:
- 你的生产环境需要升级(我不知道你的生产服务器规格或你是否有足够的资源)。
- 文件驱动程序对于您的应用程序要求来说变得太慢了。
我通常使用 redis 作为缓存和会话驱动程序,它速度更快并且有很好的策略 "smart caching" 这是一个很棒的工具。
我认为如果可能的话你也应该尝试使用它。 Memcached 可能也是一个很好的解决方案。
老实说,最好的做法是安装 xdebug 并以老派的方式调试它,遍历整个请求以找到瓶颈并尝试找出瓶颈从何而来。 Laravel 以及其他框架旨在 运行 尽可能顺利。如果您遇到任何此类错误,则意味着您可能只是编写了错误的代码。
如果没有更多信息,也很难给您具体的建议。我的建议是它重新创建您的 Laravel 应用程序所面临的环境规格(您可以使用 Docker 或 Vagrant 或您想到的任何可行的东西)然后 运行用xdebug找问题所在。
您无法捕获 php 超时错误。当 php 解释器停止执行时会发生此错误。您只能增加时间限制,例如 ini_set('max_execution_time', 300) 或将长时间执行工作转换为 cron 作业,例如 laravel 任务计划。
我不习惯 Laravel 但我遇到过这个问题,我使用 PHP 的 register_shutdown_function.
解决了这个问题
我发现它在跟踪随机发生的错误方面非常有用。
这就是我在代码中执行此操作的方式。你可以把它放在一个在每个页面上执行的公共文件中的某个地方,index.php 对你来说是一个不错的选择,因为所有 Laravel 路由都经过它(我的假设)。
register_shutdown_function( "check_for_fatal" );
function check_for_fatal(){
$time = time(); //time when this error occurred
$error = error_get_last();
if (in_array($error["type"], [E_ERROR, E_CORE_ERROR, E_RECOVERABLE_ERROR])){
$email_body = [];
$email_body[] = 'Date: ' . date('m-d-Y H:i:s', $time);
ob_start();
var_dump($error);
$email_body[] = ob_get_clean();
//include any other data as needed
//$body[] = "add data as appropriate";
//You can email it to yourself, but if there are lots of errors you will be bombarded with emails
mail('your_email_address@example.com', 'Subject', implode("\r\n", $email_body));
//or you can save this to some log file
}
}
看起来 PHP 正在等待一些资源,例如。文件访问、数据库、邮件服务器(我认为是文件)。
- 您是否尝试过在一次会话中在多个选项卡上使用您的应用程序?
- 您是否尝试过从多台机器登录同一个帐户?
- 也许脚本的某些部分正在打开文件而不是关闭文件?
- 您是否跟踪了打开网站后的用户操作以获取此错误?
- 检查您的生产数据库 - 连接数限制可能很小?
编辑
我看到您正在使用 dannyvankooten/vat.php
向外部服务发出一些请求的库。这可能是您问题的根源。该库正在使用 curl 发出请求。作者正在设置 CURLOPT_CONNECTTIMEOUT
但未设置 CURLOPT_TIMEOUT
,您的脚本有时等待的时间可能会超过 max_execution_time
设置所限制的时间。
新的 sentry 版本将为您提供正确的堆栈跟踪。
您必须使用 "getsentry/sentry-php" 版本 >= "2.0"
我收到客户遇到的许多错误的报告
Symfony\Component\Debug\Exception\FatalErrorException
Maximum execution time of 30 seconds exceeded
我本人无法在本地计算机或生产服务器上复制它。这个 URL 遍布整个网站,所以,我猜这是全球性的东西,比如导致这个的中间件。
我正在使用 Sentry.io 收集数据,但异常跟踪只有 1 个条目指向 Symfony
基本代码中的某个代码,最常见的是:
vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php at line 73
vendor/symfony/finder/Iterator/DateRangeFilterIterator.php at line 45
vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php at line 69
很明显,似乎与文件系统有关,但由于没有踪迹,我看不到在站点代码中查找错误的位置。我猜这是某种无限循环或泄漏,但没有痕迹可以查看,也没有一致的方法来重现问题。
我应该如何查找问题并进行调试?
有没有我可以设置的设置,或者我可以使用的工具use/enable?
如果您不确定异常的原因,那么您可以通过两种方式处理
1 增加请求超时 ini_set('max_execution_time', 60); //60 秒 = 1 分钟
2 将您的代码包装在 try catch
中try{
//logic goes here
}catch(\Excaption $e){
Log::error($e->getMessage().' '. $e->getFile().' '. $e->getLine());
return back()->with('error',$e->getMessage() );
}
我认为您现在不应该增加超时。如果您执行 "try catch",您可能会了解潜在的问题。如果不是,请检查在特定方法或 class 中执行的操作/功能。您可能正在查询一个巨大的 table 并且可能正在尝试使用该信息。
如果你这样做
\DB::listen(function ($sql) {
var_dump($sql);
});
这会告诉您有多少查询是 运行 操作
无法在 try catch 中捕获它,因为它实际上是 PHP 错误而不是异常。
为了能够对此进行调试,您有两种选择:
- 在代码中添加一些日志来识别超时的地方
- 您可以使用Laravel dump server package 来转储日志。这实际上将与 Laravel 5.7 一起运送,但您现在可以随时添加包裹
我安装了laravel-debugbar.I觉得对你有帮助。
作曲家要求barryvdh/laravel-debugbar 接下来打开 config/app.php 并在“providers”数组中添加:
Barryvdh\Debugbar\ServiceProvider::class,
在别名数组中 class:
'Debugbar' => Barryvdh\Debugbar\Facade::class,
您可以查看
Debugbar::measure('My long operation', function() {
// 做点什么…… });
可以注册关机功能吗? 即使发生超时,也会调用关闭函数。有了它,您可以打印或保存您想要的日志文件。 我不确定是否有更好的方法在 laravel 中获取回溯,但这就是我在纯 php 中可能会做的(调用 debug_backtrace)。
<?php
function timedOut() {
//save to a log file instead of printing
var_dump(debug_backtrace());
}
register_shutdown_function("timedOut");
http://php.net/manual/en/function.register-shutdown-function.php
阅读您的聊天对话后,我看到您正在使用此 .env
配置:
CACHE_DRIVER=file
SESSION_DRIVER=file
我认为这是问题所在...我解释得更好一些。
当您将 file
驱动程序用于缓存或会话时,Laravel 将创建大量文件来存储用户会话数据或应用程序缓存数据...
如果您的电子商务正在增长并产生大量流量,那么性能可能会降低,因为框架必须扫描大量文件。
我认为可能有两种可能的解决方案:
- 你的生产环境需要升级(我不知道你的生产服务器规格或你是否有足够的资源)。
- 文件驱动程序对于您的应用程序要求来说变得太慢了。
我通常使用 redis 作为缓存和会话驱动程序,它速度更快并且有很好的策略 "smart caching" 这是一个很棒的工具。
我认为如果可能的话你也应该尝试使用它。 Memcached 可能也是一个很好的解决方案。
老实说,最好的做法是安装 xdebug 并以老派的方式调试它,遍历整个请求以找到瓶颈并尝试找出瓶颈从何而来。 Laravel 以及其他框架旨在 运行 尽可能顺利。如果您遇到任何此类错误,则意味着您可能只是编写了错误的代码。
如果没有更多信息,也很难给您具体的建议。我的建议是它重新创建您的 Laravel 应用程序所面临的环境规格(您可以使用 Docker 或 Vagrant 或您想到的任何可行的东西)然后 运行用xdebug找问题所在。
您无法捕获 php 超时错误。当 php 解释器停止执行时会发生此错误。您只能增加时间限制,例如 ini_set('max_execution_time', 300) 或将长时间执行工作转换为 cron 作业,例如 laravel 任务计划。
我不习惯 Laravel 但我遇到过这个问题,我使用 PHP 的 register_shutdown_function.
解决了这个问题我发现它在跟踪随机发生的错误方面非常有用。 这就是我在代码中执行此操作的方式。你可以把它放在一个在每个页面上执行的公共文件中的某个地方,index.php 对你来说是一个不错的选择,因为所有 Laravel 路由都经过它(我的假设)。
register_shutdown_function( "check_for_fatal" );
function check_for_fatal(){
$time = time(); //time when this error occurred
$error = error_get_last();
if (in_array($error["type"], [E_ERROR, E_CORE_ERROR, E_RECOVERABLE_ERROR])){
$email_body = [];
$email_body[] = 'Date: ' . date('m-d-Y H:i:s', $time);
ob_start();
var_dump($error);
$email_body[] = ob_get_clean();
//include any other data as needed
//$body[] = "add data as appropriate";
//You can email it to yourself, but if there are lots of errors you will be bombarded with emails
mail('your_email_address@example.com', 'Subject', implode("\r\n", $email_body));
//or you can save this to some log file
}
}
看起来 PHP 正在等待一些资源,例如。文件访问、数据库、邮件服务器(我认为是文件)。
- 您是否尝试过在一次会话中在多个选项卡上使用您的应用程序?
- 您是否尝试过从多台机器登录同一个帐户?
- 也许脚本的某些部分正在打开文件而不是关闭文件?
- 您是否跟踪了打开网站后的用户操作以获取此错误?
- 检查您的生产数据库 - 连接数限制可能很小?
编辑
我看到您正在使用 dannyvankooten/vat.php
向外部服务发出一些请求的库。这可能是您问题的根源。该库正在使用 curl 发出请求。作者正在设置 CURLOPT_CONNECTTIMEOUT
但未设置 CURLOPT_TIMEOUT
,您的脚本有时等待的时间可能会超过 max_execution_time
设置所限制的时间。
新的 sentry 版本将为您提供正确的堆栈跟踪。
您必须使用 "getsentry/sentry-php" 版本 >= "2.0"