Symfony 2 Регистрация исключений в консоли
Почему ошибки из консольных задач не регистрируются.
Например, Исключение при вызове php:
[ErrorException]
Notice: Undefined offset: 1 in /var/www/project/vendor/doctrine/lib/Doctrine/ORM/Query.php line 298
Я вижу, что напечатано в stdout, но ничего не записывается в журналы. (Я использую консольные команды в cron).
В Интернете эти исключения регистрируются с backtrace, которые в этой ситуации более информативны, чем просто это исключение.
В качестве решения: я включаю всю функцию процесса в try..catch block и записываю обратную трассировку вручную.
Кто-нибудь знает, как включить или настроить ведение журнала в консольных задачах.
Я думаю, что это должно быть где-то.
Ответы
Ответ 1
Поскольку я следил за кодом, на самом деле нет такой опции, чтобы включить ведение журнала для команд. В app/console
находится этот код:
use Symfony\Bundle\FrameworkBundle\Console\Application;
...
$application = new Application($kernel);
$application->run();
Он вызывает Symfony\Component\Console\Application::run()
, в котором есть try/catch block. Вызывается метод исключения renderException()
, но нигде не регистрируется нигде.
Также обратите внимание, что app/console
всегда по умолчанию выходит с кодом ошибки при исключении.
Вы можете создать собственный Application
класс, расширяющий Symfony\Bundle\FrameworkBundle\Console\Application
, и измените app/console
, чтобы использовать его. Чем вы можете переопределить метод run()
и добавить журнал ошибок.
Или вы можете изменить только app/console
и обработать erros следующим образом:
// $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);
}
Ответ 2
TL; DR: просто используйте этот комплект
Из 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);
}
}
Ответ 3
Если вы просто понимаете, что пошло не так, вы можете запустить свое приложение с помощью флагов -v
или --verbose
, который будет автоматически напечатайте трассировку исключения на экране.
![]()
Ответ 4
Другой способ - реализовать собственный собственный класс OutputInterface
и переопределить метод writeln
, чтобы зарегистрировать там ошибку. Затем используйте новый класс при выполнении метода run()
.
Таким образом вы можете придерживаться принципа Open/Close Symfony, не изменяя базовые классы и не достигших своих целей.