feature #38940 [Messenger] Improve formatting of exception in failed message (Jeroen Noten)
This PR was merged into the 5.2-dev branch.
Discussion
----------
[Messenger] Improve formatting of exception in failed message
| Q | A
| ------------- | ---
| Branch? | 5.x
| Bug fix? | no
| New feature? | not really, enhancement of an existing feature
| Deprecations? | no
| Tickets | Fix #32310
| License | MIT
This PR improves the formatting of exception details in failed messenges when displayed using `messenger:failed:show <id> -vv`.
Before:
<img width="807" alt="Screen Shot 2020-11-01 at 1 05 24 PM" src="https://user-images.githubusercontent.com/4370753/97802602-ea593200-1c44-11eb-8bcb-7fcf2d3f1db0.png">
After:
<img width="803" alt="Screen Shot 2020-11-01 at 1 03 09 PM" src="https://user-images.githubusercontent.com/4370753/97802615-f0e7a980-1c44-11eb-8c12-46b2d4510364.png">
I created a `ThrownExceptionDetails` class which will be displayed as a normal exception when dumped with the VarDumper component. Not sure if this is the right way to do it and if the class is in the right namespace, but this is the best solution I could came up with to fix #32310. I'm open for other suggestions.
Commits
-------
2ad1adda69
[Messenger] Improve formatting of thrown exception in show failed message command
This commit is contained in:
commit
d2bac32525
@ -14,6 +14,7 @@ namespace Symfony\Component\Messenger\Command;
|
|||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Helper\Dumper;
|
use Symfony\Component\Console\Helper\Dumper;
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
use Symfony\Component\ErrorHandler\Exception\FlattenException;
|
||||||
use Symfony\Component\Messenger\Envelope;
|
use Symfony\Component\Messenger\Envelope;
|
||||||
use Symfony\Component\Messenger\Stamp\ErrorDetailsStamp;
|
use Symfony\Component\Messenger\Stamp\ErrorDetailsStamp;
|
||||||
use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
|
use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
|
||||||
@ -21,6 +22,11 @@ use Symfony\Component\Messenger\Stamp\SentToFailureTransportStamp;
|
|||||||
use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp;
|
use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp;
|
||||||
use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface;
|
use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface;
|
||||||
use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface;
|
use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface;
|
||||||
|
use Symfony\Component\VarDumper\Caster\Caster;
|
||||||
|
use Symfony\Component\VarDumper\Caster\TraceStub;
|
||||||
|
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
|
||||||
|
use Symfony\Component\VarDumper\Cloner\Stub;
|
||||||
|
use Symfony\Component\VarDumper\Cloner\VarCloner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ryan Weaver <ryan@symfonycasts.com>
|
* @author Ryan Weaver <ryan@symfonycasts.com>
|
||||||
@ -121,7 +127,7 @@ abstract class AbstractFailedMessagesCommand extends Command
|
|||||||
|
|
||||||
if ($io->isVeryVerbose()) {
|
if ($io->isVeryVerbose()) {
|
||||||
$io->title('Message:');
|
$io->title('Message:');
|
||||||
$dump = new Dumper($io);
|
$dump = new Dumper($io, null, $this->createCloner());
|
||||||
$io->writeln($dump($envelope->getMessage()));
|
$io->writeln($dump($envelope->getMessage()));
|
||||||
$io->title('Exception:');
|
$io->title('Exception:');
|
||||||
$flattenException = null;
|
$flattenException = null;
|
||||||
@ -130,7 +136,7 @@ abstract class AbstractFailedMessagesCommand extends Command
|
|||||||
} elseif (null !== $lastRedeliveryStampWithException) {
|
} elseif (null !== $lastRedeliveryStampWithException) {
|
||||||
$flattenException = $lastRedeliveryStampWithException->getFlattenException();
|
$flattenException = $lastRedeliveryStampWithException->getFlattenException();
|
||||||
}
|
}
|
||||||
$io->writeln(null === $flattenException ? '(no data)' : $flattenException->getTraceAsString());
|
$io->writeln(null === $flattenException ? '(no data)' : $dump($flattenException));
|
||||||
} else {
|
} else {
|
||||||
$io->writeln(' Re-run command with <info>-vv</info> to see more message & error details.');
|
$io->writeln(' Re-run command with <info>-vv</info> to see more message & error details.');
|
||||||
}
|
}
|
||||||
@ -172,4 +178,26 @@ abstract class AbstractFailedMessagesCommand extends Command
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function createCloner(): ?ClonerInterface
|
||||||
|
{
|
||||||
|
if (!class_exists(VarCloner::class)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cloner = new VarCloner();
|
||||||
|
$cloner->addCasters([FlattenException::class => function (FlattenException $flattenException, array $a, Stub $stub): array {
|
||||||
|
$stub->class = $flattenException->getClass();
|
||||||
|
|
||||||
|
return [
|
||||||
|
Caster::PREFIX_VIRTUAL.'message' => $flattenException->getMessage(),
|
||||||
|
Caster::PREFIX_VIRTUAL.'code' => $flattenException->getCode(),
|
||||||
|
Caster::PREFIX_VIRTUAL.'file' => $flattenException->getFile(),
|
||||||
|
Caster::PREFIX_VIRTUAL.'line' => $flattenException->getLine(),
|
||||||
|
Caster::PREFIX_VIRTUAL.'trace' => new TraceStub($flattenException->getTrace()),
|
||||||
|
];
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return $cloner;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Symfony\Component\Messenger\Tests\Command;
|
namespace Symfony\Component\Messenger\Tests\Command;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Tester\CommandTester;
|
use Symfony\Component\Console\Tester\CommandTester;
|
||||||
use Symfony\Component\Messenger\Command\FailedMessagesShowCommand;
|
use Symfony\Component\Messenger\Command\FailedMessagesShowCommand;
|
||||||
use Symfony\Component\Messenger\Envelope;
|
use Symfony\Component\Messenger\Envelope;
|
||||||
@ -234,4 +235,44 @@ EOF
|
|||||||
$tester = new CommandTester($command);
|
$tester = new CommandTester($command);
|
||||||
$tester->execute(['id' => 15]);
|
$tester->execute(['id' => 15]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testVeryVerboseOutputForSingleMessageContainsExceptionWithTrace()
|
||||||
|
{
|
||||||
|
$exception = new \RuntimeException('Things are bad!');
|
||||||
|
$exceptionLine = __LINE__ - 1;
|
||||||
|
$envelope = new Envelope(new \stdClass(), [
|
||||||
|
new TransportMessageIdStamp(15),
|
||||||
|
new SentToFailureTransportStamp('async'),
|
||||||
|
new RedeliveryStamp(0),
|
||||||
|
new ErrorDetailsStamp($exception),
|
||||||
|
]);
|
||||||
|
$receiver = $this->createMock(ListableReceiverInterface::class);
|
||||||
|
$receiver->expects($this->once())->method('find')->with(42)->willReturn($envelope);
|
||||||
|
|
||||||
|
$command = new FailedMessagesShowCommand('failure_receiver', $receiver);
|
||||||
|
$tester = new CommandTester($command);
|
||||||
|
$tester->execute(['id' => 42], ['verbosity' => OutputInterface::VERBOSITY_VERY_VERBOSE]);
|
||||||
|
$this->assertStringMatchesFormat(sprintf(<<<'EOF'
|
||||||
|
%%A
|
||||||
|
Exception:
|
||||||
|
==========
|
||||||
|
|
||||||
|
RuntimeException {
|
||||||
|
message: "Things are bad!"
|
||||||
|
code: 0
|
||||||
|
file: "%s"
|
||||||
|
line: %d
|
||||||
|
trace: {
|
||||||
|
%%s%%eTests%%eCommand%%eFailedMessagesShowCommandTest.php:%d {
|
||||||
|
Symfony\Component\Messenger\Tests\Command\FailedMessagesShowCommandTest->testVeryVerboseOutputForSingleMessageContainsExceptionWithTrace()
|
||||||
|
› {
|
||||||
|
› $exception = new \RuntimeException('Things are bad!');
|
||||||
|
› $exceptionLine = __LINE__ - 1;
|
||||||
|
}
|
||||||
|
%%A
|
||||||
|
EOF
|
||||||
|
,
|
||||||
|
__FILE__, $exceptionLine, $exceptionLine),
|
||||||
|
$tester->getDisplay(true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user