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

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