Skip to content

Commit

Permalink
Log all reasons from a Amp\MultiReasonException
Browse files Browse the repository at this point in the history
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
  • Loading branch information
youwe-petervanderwal authored and mmenozzi committed Oct 19, 2020
1 parent c3b6e4c commit 82ceb70
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 12 deletions.
34 changes: 27 additions & 7 deletions src/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
}
46 changes: 41 additions & 5 deletions tests/Integration/UncaughtExceptionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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([
Expand All @@ -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));
}
}
}
31 changes: 31 additions & 0 deletions tests/MultiReasonInitFailingWorker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);

namespace Webgriffe\Esb;

use Amp\Promise;
use Amp\Success;
use Webgriffe\Esb\Model\JobInterface;
use function Amp\call;

final class MultiReasonInitFailingWorker implements WorkerInterface
{
/**
* @return Promise
*/
public function init(): Promise
{
return Promise\some([
call(function () { throw new \Exception('Exception number one'); } ),
call(function () { throw new \Exception('Exception number two'); } ),
], 2);
}

/**
* {@inheritDoc}
*/
public function work(JobInterface $job): Promise
{
return new Success();
}
}

0 comments on commit 82ceb70

Please sign in to comment.