如何调试 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 错误而不是异常。

为了能够对此进行调试,您有两种选择:

  1. 在代码中添加一些日志来识别超时的地方
  2. 您可以使用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

http://php.net/manual/en/function.debug-backtrace.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"