13

Why errors from console tasks are not logged. For example Exception on php warning:

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

I see what printed in stdout, but nothing logged to logs. (I use console commands in cron). In web these exceptions logged with backtrace, which in this situation is more informational than just this exception.

As a solution: I enclose all process function in try..catch block and log the backtrace manually.

Is anyone know how to enable or configure logging in console tasks. I think it must be somewhere.

4 Answers 4

15

As I followed the code, there's actually no such an option to enable logging for commands. In app/console is this code:

use Symfony\Bundle\FrameworkBundle\Console\Application;

...

$application = new Application($kernel);
$application->run();

It calls Symfony\Component\Console\Application::run() in which there's try/catch block. On exception method renderException() is called, but no logging happens anywhere.

Also note that app/console always by default exits with error code on exception.

You can create you own Application class extending Symfony\Bundle\FrameworkBundle\Console\Application and modify app/console to use it. Than you can override run() method and add errors logging.

Or you can modify just app/console and handle erros like this:

// $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);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for explanation. I dig into launch files console & index.php but should dig deeper in Application class. But it seems that application classes in web & console share the same behavior.
yay for setCatchExceptions. this example could be improved by Throwable instead of Exception on newer php versions. :)
7

TL;DR : just use this bundle

From the cookbook :

To get your console application to automatically log uncaught exceptions for all of your commands, you can use console events.

Create a service tagged as an event listener for the console.exception event :

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

You can now do whatever you want with console exceptions :

<?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);
    }
}

1 Comment

Yes, since Symfony 2.3 this is a better solution.
6

If that's the matter of simply understanding what went wrong where, you can run your app with the verbose flag -v or --verbose, which will automatically print the exception trace on the screen.

3 Comments

You are right, but question was about writing errors to log (for ex. in file) It was necessary when i run cli commands from cron
True, sorry, missed the cron part. Couldn't figure out how get to the backtrace without complicating it all too much, decided to share the findings.
@IanBytchek, thank you anyway, your answer helped me a lot!
2

Another way is to implement your own custom OutputInterface class and override the writeln method to log the error there. Then use the new class when you execute the run() method.

This way you can adhere to the Open/Close Principle of Symfony without having to modify the base classes and still achieve your goals.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.