From 82ceb70eb2d47eb20dc12092fb81cc7936d93816 Mon Sep 17 00:00:00 2001 From: Peter van der Wal Date: Mon, 5 Oct 2020 14:07:08 +0200 Subject: [PATCH] Log all reasons from a Amp\MultiReasonException Instead of logging the message "Fatal error: Uncaught Amp\MultiReasonException: Multiple errors encountered; use Amp\MultiReasonException::getReasons() to retrieve the array of exceptions thrown in ~" log all individual exceptions so you can see what's actually going wrong --- src/Kernel.php | 34 +++++++++++---- tests/Integration/UncaughtExceptionTest.php | 46 ++++++++++++++++++--- tests/MultiReasonInitFailingWorker.php | 31 ++++++++++++++ 3 files changed, 99 insertions(+), 12 deletions(-) create mode 100644 tests/MultiReasonInitFailingWorker.php diff --git a/src/Kernel.php b/src/Kernel.php index 4fbe088..f9dcfaf 100644 --- a/src/Kernel.php +++ b/src/Kernel.php @@ -5,6 +5,7 @@ namespace Webgriffe\Esb; use Amp\Loop; +use Amp\MultiReasonException; use Doctrine\Common\Annotations\AnnotationRegistry; use Psr\Log\LoggerInterface; use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException; @@ -86,13 +87,7 @@ public function errorHandler(\Throwable $exception): void $logger = $this->getContainer()->get(LoggerInterface::class); $logger->critical( 'An uncaught exception occurred, ESB will be stopped now!', - [ - 'code' => $exception->getCode(), - 'message' => $exception->getMessage(), - 'file' => $exception->getFile(), - 'line' => $exception->getLine(), - 'trace' => $exception->getTrace() - ] + $this->getExceptionLogContext($exception) ); throw $exception; } @@ -164,4 +159,29 @@ private function loadLocalConfiguration(YamlFileLoader $loader): void $loader->load($this->localConfigFilePath); } } + + /** + * Builds the log context of an exception. If this is an \Amp\MultiReasonException all reasons are included + * @param \Throwable $exception + * @return mixed[] + */ + private function getExceptionLogContext(\Throwable $exception): array + { + $context = [ + 'code' => $exception->getCode(), + 'message' => $exception->getMessage(), + 'file' => $exception->getFile(), + 'line' => $exception->getLine(), + 'trace' => $exception->getTrace() + ]; + + if ($exception instanceof MultiReasonException) { + $context['reasons'] = []; + foreach ($exception->getReasons() as $reason) { + $context['reasons'][] = $this->getExceptionLogContext($reason); + } + } + + return $context; + } } diff --git a/tests/Integration/UncaughtExceptionTest.php b/tests/Integration/UncaughtExceptionTest.php index d787278..b4f5691 100644 --- a/tests/Integration/UncaughtExceptionTest.php +++ b/tests/Integration/UncaughtExceptionTest.php @@ -2,15 +2,14 @@ namespace Webgriffe\Esb\Integration; +use Monolog\Logger; use Webgriffe\Esb\DummyFilesystemWorker; use Webgriffe\Esb\DummyRepeatProducer; +use Webgriffe\Esb\MultiReasonInitFailingWorker; use Webgriffe\Esb\KernelTestCase; class UncaughtExceptionTest extends KernelTestCase { - /** - * @expectedException \Amp\Beanstalk\ConnectException - */ public function testUncaughtExceptionIsLoggedAndThrown() { self::createKernel([ @@ -27,8 +26,45 @@ public function testUncaughtExceptionIsLoggedAndThrown() ] ] ]); - self::$kernel->boot(); - $this->logHandler()->hasCriticalThatContains('An uncaught exception occurred, ESB will be stopped now!'); + try { + $this->expectException(\Amp\Beanstalk\ConnectException::class); + self::$kernel->boot(); + } finally { + $this->assertTrue($this->logHandler()->hasCriticalThatContains('An uncaught exception occurred, ESB will be stopped now!')); + } + } + + public function testMultiReasonExceptionIsLoggedAndThrown() + { + self::createKernel([ + 'services' => [ + DummyRepeatProducer::class => ['class' => DummyRepeatProducer::class, 'arguments' => []], + MultiReasonInitFailingWorker::class => [], + ], + 'flows' => [ + 'sample_tube' => [ + 'description' => 'Flow', + 'producer' => ['service' => DummyRepeatProducer::class], + 'worker' => ['service' => MultiReasonInitFailingWorker::class], + ] + ] + ]); + + try { + $this->expectException(\Amp\MultiReasonException::class); + self::$kernel->boot(); + } finally { + $this->assertTrue($this->logHandler()->hasRecordThatPasses(function ($record) { + $context = $record['context']; + // Verify log message + return $record['message'] === 'An uncaught exception occurred, ESB will be stopped now!' + // Verify log context contains all reasons + && isset($context['reasons']) && is_array($context['reasons']) + && count($context['reasons']) === 2 + && $context['reasons'][0]['message'] === 'Exception number one' + && $context['reasons'][1]['message'] === 'Exception number two'; + }, Logger::CRITICAL)); + } } } diff --git a/tests/MultiReasonInitFailingWorker.php b/tests/MultiReasonInitFailingWorker.php new file mode 100644 index 0000000..d7be9be --- /dev/null +++ b/tests/MultiReasonInitFailingWorker.php @@ -0,0 +1,31 @@ +