【问题标题】:Symfony 2 Logging exceptions in consoleSymfony 2 在控制台中记录异常
【发布时间】:2026-02-14 23:50:01
【问题描述】:

为什么不记录来自控制台任务的错误。 例如 php 警告异常:

[ErrorException]
Notice: Undefined offset: 1 in /var/www/project/vendor/doctrine/lib/Doctrine/ORM/Query.php line 298

我看到了标准输出中打印的内容,但没有记录到日志中。 (我在 cron 中使用控制台命令)。 在 Web 中,这些异常使用回溯记录,在这种情况下,它比仅此异常提供更多信息。

作为一种解决方案:我将所有进程函数包含在 try..catch 块中并手动记录回溯。

有谁知道如何在控制台任务中启用或配置日志记录。 我想它一定在某个地方。

【问题讨论】:

    标签: php logging symfony console-application error-logging


    【解决方案1】:

    当我按照代码进行操作时,实际上没有启用命令日志记录的选项。在app/console 中是这个代码:

    use Symfony\Bundle\FrameworkBundle\Console\Application;
    
    ...
    
    $application = new Application($kernel);
    $application->run();
    

    它调用Symfony\Component\Console\Application::run(),其中有try/catch 块。异常方法 renderException() 被调用,但任何地方都没有发生日志记录。

    另请注意,app/console 在默认情况下总是以异常错误代码退出。

    您可以创建自己的 Application 类扩展 Symfony\Bundle\FrameworkBundle\Console\Application 并修改 app/console 以使用它。你可以覆盖run() 方法并添加错误日志记录。

    或者您可以只修改app/console 并像这样处理错误:

    // $application->run();
    $application->setCatchExceptions(false);
    try {
        $output = new Symfony\Component\Console\Output\ConsoleOutput();
        $application->run(null, $output);
    } catch (Exception $e) {
        ... error logging ...
    
        $application->renderException($e, $output);
    
        $statusCode = $e->getCode();
        $statusCode = is_numeric($statusCode) && $statusCode ? $statusCode : 1;
        exit($statusCode);
    }
    

    【讨论】:

    • 感谢您的解释。我深入研究了启动文件控制台和 index.php,但应该更深入地研究 Application 类。但似乎 Web 和控制台中的应用程序类具有相同的行为。
    • 欢迎setCatchExceptions。这个例子可以通过Throwable 来改进,而不是Exception 在较新的php 版本上。 :)
    【解决方案2】:

    TL;DR:只需使用this bundle

    来自cookbook

    要让您的控制台应用程序自动记录所有命令的未捕获异常,您可以使用控制台事件。

    console.exception 事件创建一个标记为事件侦听器的服务:

    # services.yml
    services:
        kernel.listener.command_dispatch:
        class: Acme\DemoBundle\EventListener\ConsoleExceptionListener
        arguments:
            logger: "@logger"
        tags:
            - { name: kernel.event_listener, event: console.exception }
    

    你现在可以用控制台异常做任何你想做的事:

    <?php
    // src/Acme/DemoBundle/EventListener/ConsoleExceptionListener.php
    namespace Acme\DemoBundle\EventListener;
    
    use Symfony\Component\Console\Event\ConsoleExceptionEvent;
    use Psr\Log\LoggerInterface;
    
    class ConsoleExceptionListener
    {
        private $logger;
    
        public function __construct(LoggerInterface $logger)
        {
        $this->logger = $logger;
        }
    
        public function onConsoleException(ConsoleExceptionEvent $event)
        {
        $command = $event->getCommand();
        $exception = $event->getException();
    
        $message = sprintf(
            '%s: %s (uncaught exception) at %s line %s while running console command `%s`',
            get_class($exception),
            $exception->getMessage(),
            $exception->getFile(),
            $exception->getLine(),
            $command->getName()
        );
    
        $this->logger->error($message);
        }
    }
    

    【讨论】:

    • 是的,因为 Symfony 2.3 这是一个更好的解决方案。
    【解决方案3】:

    如果只是了解哪里出了问题,您可以使用详细标志-v--verbose 运行您的应用程序,这将在屏幕上显示automatically print the exception trace

    【讨论】:

    • 你是对的,但问题是关于将错误写入日志(例如在文件中)当我从 cron 运行 cli 命令时这是必要的
    • 是的,抱歉,错过了 cron 部分。无法弄清楚如何在不使事情复杂化的情况下进行回溯,决定分享这些发现。
    • @IanBytchek,还是谢谢你,你的回答对我帮助很大!
    【解决方案4】:

    另一种方法是实现您自己的自定义OutputInterface 类并覆盖writeln 方法以在那里记录错误。然后在执行run() 方法时使用新类。

    这样您就可以遵守 Symfony 的 Open/Close Principle 而无需修改基类并仍然实现您的目标。

    【讨论】: