vendor/sentry/sentry-symfony/src/EventListener/MessengerListener.php line 80

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Sentry\SentryBundle\EventListener;
  4. use Sentry\Event;
  5. use Sentry\EventHint;
  6. use Sentry\ExceptionMechanism;
  7. use Sentry\State\HubInterface;
  8. use Sentry\State\Scope;
  9. use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
  10. use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
  11. use Symfony\Component\Messenger\Exception\DelayedMessageHandlingException;
  12. use Symfony\Component\Messenger\Exception\HandlerFailedException;
  13. use Symfony\Component\Messenger\Exception\WrappedExceptionsInterface;
  14. use Symfony\Component\Messenger\Stamp\BusNameStamp;
  15. final class MessengerListener
  16. {
  17.     /**
  18.      * @var HubInterface The current hub
  19.      */
  20.     private $hub;
  21.     /**
  22.      * @var bool Whether to capture errors thrown while processing a message that
  23.      *           will be retried
  24.      */
  25.     private $captureSoftFails;
  26.     /**
  27.      * @param HubInterface $hub              The current hub
  28.      * @param bool         $captureSoftFails Whether to capture errors thrown
  29.      *                                       while processing a message that
  30.      *                                       will be retried
  31.      */
  32.     public function __construct(HubInterface $hubbool $captureSoftFails true)
  33.     {
  34.         $this->hub $hub;
  35.         $this->captureSoftFails $captureSoftFails;
  36.     }
  37.     /**
  38.      * This method is called for each message that failed to be handled.
  39.      *
  40.      * @param WorkerMessageFailedEvent $event The event
  41.      */
  42.     public function handleWorkerMessageFailedEvent(WorkerMessageFailedEvent $event): void
  43.     {
  44.         if (!$this->captureSoftFails && $event->willRetry()) {
  45.             return;
  46.         }
  47.         $this->hub->withScope(function (Scope $scope) use ($event): void {
  48.             $envelope $event->getEnvelope();
  49.             $exception $event->getThrowable();
  50.             $scope->setTag('messenger.receiver_name'$event->getReceiverName());
  51.             $scope->setTag('messenger.message_class', \get_class($envelope->getMessage()));
  52.             /** @var BusNameStamp|null $messageBusStamp */
  53.             $messageBusStamp $envelope->last(BusNameStamp::class);
  54.             if (null !== $messageBusStamp) {
  55.                 $scope->setTag('messenger.message_bus'$messageBusStamp->getBusName());
  56.             }
  57.             $this->captureException($exception$event->willRetry());
  58.         });
  59.         $this->flushClient();
  60.     }
  61.     /**
  62.      * This method is called for each handled message.
  63.      *
  64.      * @param WorkerMessageHandledEvent $event The event
  65.      */
  66.     public function handleWorkerMessageHandledEvent(WorkerMessageHandledEvent $event): void
  67.     {
  68.         // Flush normally happens at shutdown... which only happens in the worker if it is run with a lifecycle limit
  69.         // such as --time=X or --limit=Y. Flush immediately in a background worker.
  70.         $this->flushClient();
  71.     }
  72.     /**
  73.      * Creates Sentry events from the given exception.
  74.      *
  75.      * Unpacks multiple exceptions wrapped in a HandlerFailedException and notifies
  76.      * Sentry of each individual exception.
  77.      *
  78.      * If the message will be retried the exceptions will be marked as handled
  79.      * in Sentry.
  80.      */
  81.     private function captureException(\Throwable $exceptionbool $willRetry): void
  82.     {
  83.         if ($exception instanceof WrappedExceptionsInterface) {
  84.             $exception $exception->getWrappedExceptions();
  85.         } elseif ($exception instanceof HandlerFailedException && method_exists($exception'getNestedExceptions')) {
  86.             $exception $exception->getNestedExceptions();
  87.         } elseif ($exception instanceof DelayedMessageHandlingException && method_exists($exception'getExceptions')) {
  88.             $exception $exception->getExceptions();
  89.         }
  90.         if (\is_array($exception)) {
  91.             foreach ($exception as $nestedException) {
  92.                 $this->captureException($nestedException$willRetry);
  93.             }
  94.             return;
  95.         }
  96.         $hint EventHint::fromArray([
  97.             'exception' => $exception,
  98.             'mechanism' => new ExceptionMechanism(ExceptionMechanism::TYPE_GENERIC$willRetry),
  99.         ]);
  100.         $this->hub->captureEvent(Event::createEvent(), $hint);
  101.     }
  102.     private function flushClient(): void
  103.     {
  104.         $client $this->hub->getClient();
  105.         if (null !== $client) {
  106.             $client->flush();
  107.         }
  108.     }
  109. }