php – How can I display Exception trace in laravel console command?-ThrowExceptions

Exception or error:

I’m using Laravel 5.1 to create a console based application. During development I would like to display the exception trace when an error occurs. However, even if I use -v -vv or -vvv option in php artisan, I don’t get an exception trace for my custom commands. I set APP_DEBUG=true in my .env, still no exception trace.

Output of php artisan some:unknowncommand is:

[InvalidArgumentException]                              
There are no commands defined in the "some" namespace.

Output of php artisan -v some:unknowncommand is:

[InvalidArgumentException]                              
  There are no commands defined in the "some" namespace.  

Exception trace:
 () at /Users/dirkpostma/Dropbox/Domains/dpepp/vendor/symfony/console/Application.php:501
 Symfony\Component\Console\Application->findNamespace() at /Users/dirkpostma/Dropbox/Domains/dpepp/vendor/symfony/console/Application.php:535
 Symfony\Component\Console\Application->find() at /Users/dirkpostma/Dropbox/Domains/dpepp/vendor/symfony/console/Application.php:192
 Symfony\Component\Console\Application->doRun() at /Users/dirkpostma/Dropbox/Domains/dpepp/vendor/symfony/console/Application.php:126
...

Now, I created a very simple console command called dp:test, with following handle function:

/**
 * Execute the console command.
 *
 * @return mixed
 */
public function handle()
{
    generate error here
}

Output of php artisan dp:test is:

[Symfony\Component\Debug\Exception\FatalErrorException]
syntax error, unexpected 'error' (T_STRING)    

Output of php artisan -v dp:test is the same.
Output of php artisan -vvv dp:test is the same.

The log file DOES show the exception trace, so somehow it should be possible to display it in cli. I don’t even see the filename and linenumer where the error occurs… How can I take care of this?

Thanks in advance!

EDIT:

Is digged a bit further. In case I use this in my Command:

public function handle()
{
    throw new \Exception("test exception");
}

and I issue the command php artisan -v dp:test, the error trace IS printed. The trace is only not printed when the exception is thrown due to a PHP error. In Illuminate/Foundation/Bootstrap/HandleExceptions.php method bootstrap PHP errors are converted to Exceptions. When this occurs, an exception is thrown, but the -v is somehow ignored when printing. This is very inconvenient because it makes debugging CLI apps hard.

I think the solution can be found in vendor/symfony/console/Application.php, method renderException.

I’m going to dig further later, unless someone else can point the solution faster than me 🙂

How to solve:

I found reason why -v is ignored:

in Illuminate/Foundation/Bootstrap/HandleExceptions.php, the renderForConsole methode instantiates a ConsoleOutput object, with default settings, not taking into account the verbosity settings the user asked for:

protected function renderForConsole($e)
{
    $this->getExceptionHandler()->renderForConsole(new ConsoleOutput, $e);
}

For this reason, whatever -v -vv or -vvv is set, the $output->getVerbosity() in vendor/symfony/console/Application.php is always lower than OutputInterface::VERBOSITY_VERBOSE, for that reason, the stack trace is not printed.

I probably start an issue on github for this, because I think it’s much more convenient if errors are shown in CLI if user sets -v.

Answer:

You can set the verbosity to whatever level you’d like by adding the following use statement:

use Symfony\Component\Console\Output\OutputInterface;

And then adding this to the top of your handle function:

$this->output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);

See the documentation for symfony console here http://symfony.com/doc/current/console/verbosity.html
for more information.

Answer:

If you look at Illuminate\Console\Command class you will see the definition of the function that writes the error string to the console:

/**
 * Write a string as error output.
 *
 * @param  string  $string
 * @return void
 */
public function error($string)
{
    $this->output->writeln("<error>$string</error>");
}

Now that you see it only writes the error string, you can play just a little bit with it to achieve what you want. You can get the function call back trace and output as many lines and files backwards as you wish. Just create class that extends command, override the function and make all of your commands to inherit that command class:

/**
 * Write a string as error output.
 *
 * @param  string  $string
 * @return void
 */
public function error($string)
{
    $this->output->writeln("<error>$string</error>");
    $trace = debug_backtrace();
    foreach ($trace as $t) 
    {
        $this->output->writeln("Trace : " . $t['file'] . " on line " . $t['line'] . " function " . $t['function']);
    }

}

Leave a Reply

Your email address will not be published. Required fields are marked *