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

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