【问题标题】:Exception Eventlistener is not catching Exceptions from RabbitMQ consumer异常事件侦听器未捕获来自 RabbitMQ 消费者的异常
【发布时间】:2019-04-29 11:12:06
【问题描述】:

我正在 Symfony 中创建一个微服务,我需要使用 RabbitMQ 来使用消息来创建一个文档。消费者正在工作,但每当抛出异常时,我想以某种格式和单独的日志文件记录异常。

我使用的是 Symfony 4.2,所有抛出的异常都记录在 dev.log 中。我在 Monolog 中创建了一个新频道并调用了异常,以便我可以管理我的日志记录。

对于这种方式,我使用了 ExceptionListener 并按照 Symfony 文档中的说明进行操作。

我的消费者设置如下

public function execute(AMQPMessage $msg): int
    {
        try {
            return $this->documentService->createDocument($this->serializer->deserialize($msg->body, 'array', 'json'));
        } catch (\Exception $e) {
             $this->logger->error($e);

            return ConsumerInterface::MSG_REJECT;
        }
    }

在服务中我有以下内容:

try {
...

    $template = $this->templateRepository->findOneByName($messageData['template']);
    if ($template === null) throw new \Exception('Template does not exist');

...

    return ConsumerInterface::MSG_ACK;
} catch (\Exception $e) {
    $this->logger->error($e);

    return ConsumerInterface::MSG_REJECT;
}

我正在登录这两个类,但是当抛出异常时,我在控制台中得到了异常,但侦听器没有捕获到 ExceptionEvent。

我尝试了不同的事件并将 http-kernel 包添加到 Symfony,因为我使用的是 Symfony Flex,所以我没有所有包。

我在 services.yaml 中注册了我的监听器,如下所示:

    App\EventListener\DocumentExceptionListener:
        tags:
            - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
        arguments:
            $logger: '@monolog.logger.exception' # Log all exceptions to a separate log file

我的 ExceptionListener 如下:

public function __construct(LoggerInterface $logger, SerializerInterface $serializer)
    {
        $this->logger = $logger;
        $this->serializer = $serializer;

        $this->logger->info('Starting to listen...');
    }

    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        $this->logger->info('currently listening...');

        $this->log($event->getException());
    }

    private function log(\Exception $exception)
    {
        $log = [
            'code' => $exception->getCode(),
            'message' => $exception->getMessage(),
            'called' => [
                'file' => $exception->getTrace()[0]['file'],
                'line' => $exception->getTrace()[0]['line'],
            ],
            'occurred' => [
                'file' => $exception->getFile(),
                'line' => $exception->getLine(),
            ],
        ];

        if ($exception->getPrevious() instanceof Exception) {
            $log += [
                'previous' => [
                    'message' => $exception->getPrevious()->getMessage(),
                    'exception' => get_class($exception->getPrevious()),
                    'file' => $exception->getPrevious()->getFile(),
                    'line' => $exception->getPrevious()->getLine(),
                ],
            ];
        }

        $this->logger->error($this->serializer->serialize($log, 'json'));
    }

我现在的输出是:

exception.INFO: Starting to listen... [] []

【问题讨论】:

  • 由于您已经在服务中捕获了异常,因此永远不会使用第二个 catch 块(在您的使用者中)。从外观上看,您只在 Consumer 中使用自定义记录器,并且由于未调用 catch 块,因此永远不会使用它。
  • 也不使用 ExceptionListener,因为您在侦听器可以处理异常之前捕获它。您必须重新抛出异常或确保您的服务已经使用新的记录器
  • 我更新了我的代码,并从我的服务和我的消费者中删除了 Try Catch 语句......但侦听器仍然没有捕获。
  • 即使我在函数的第一行添加了一个 throw,我的 Listener 也不会进入 onKernelException 方法
  • 是的,ExceptionListener 仅适用于应用程序内部未捕获的异常。每当您抓住它们时,它都不会触发。也许不是让 ExceptionListener 尝试像$this->logger->log($e->getMessage(), ['exception' => $e]); 这样的东西,这将记录消息和完整的堆栈跟踪,而不需要特殊的侦听器

标签: php symfony error-handling rabbitmq consumer


【解决方案1】:

我在您的问题中看到了“控制台”一词。 如果是控制台异常(因为它是关于命令执行),您必须以另一种方式标记您的侦听器:

tags:
    - { name: kernel.event_listener, event: console.error }

在此处查看console.error 事件名称。

在此处查看更多信息:Events and Event Listeners

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-26
    • 2021-06-07
    • 2016-02-28
    • 2021-11-22
    • 2018-02-09
    • 2016-05-10
    • 1970-01-01
    相关资源
    最近更新 更多