如何捕获并记录Apigility ZF2应用程序中的所有异常?

时间:2015-06-08 22:25:19

标签: logging exception-handling zend-framework2 apigility exception-logging

我想建立一个错误处理&将mecanism记录到Apigility Zend Framework 2应用程序和catch&记录所有异常。

经过一番研究后,我发现Stack Overflow answer有一个解决方案,似乎完全符合这个要求。以下是答案中的代码(带有一些小的命名和格式修改):

Module.php

...

use Zend\Mvc\ModuleRouteListener;
use Zend\Log\Logger;
use Zend\Log\Writer\Stream;

...

class Module implements ApigilityProviderInterface
{

    public function onBootstrap(MvcEvent $mvcEvent)
    {
        $eventManager = $mvcEvent->getApplication()->getEventManager();
        $moduleRouteListener = new ModuleRouteListener();
        $moduleRouteListener->attach($eventManager);
        /**
         * Log any Uncaught Exceptions, including all Exceptions in the stack
         */
        $sharedEventManager = $mvcEvent->getApplication()->getEventManager()->getSharedManager();
        $serviceManager = $mvcEvent->getApplication()->getServiceManager();
        $sharedEventManager->attach('Zend\Mvc\Application', MvcEvent::EVENT_DISPATCH_ERROR,
            function($mvcEvent) use ($serviceManager) {
                if ($mvcEvent->getParam('exception')){
                    $exception = $mvcEvent->getParam('exception');
                    do {
                        $serviceManager->get('Logger')->crit(
                            sprintf(
                               "%s:%d %s (%d) [%s]\n", 
                                $exception->getFile(), 
                                $exception->getLine(), 
                                $exception->getMessage(), 
                                $exception->getCode(), 
                                get_class($exception)
                            )
                        );
                    }
                    while($exception = $exception->getPrevious());
                }
            }
        );
    }

    ...

    public function getServiceConfig() {
        return array(
            'factories' => array(
                // V1
                ...
                'Logger' => function($sm){
                    $logger = new Logger;
                    $writer = new Stream('/var/log/httpd/sandbox-log');
                    $logger->addWriter($writer);
                    return $logger;
                },
            ),
            ...
        );
    }

}

所以现在我已经在代码中的多个位置(throw new \Exception('foo')Resource和{}中尝试了这一点(使用简单的Service) {1}}类)并期望得到缓存的异常并登录到我defiden的文件中。但它不起作用。

我做错了吗?什么?如何让它工作? 如何在Apigility驱动的Zend Framework 2应用程序中捕获并记录所有异常?

附加信息:代码中某个位置的示例,其中抛出异常:

Mapper

其他信息:休息中的跟踪(如果在class AddressResource extends AbstractResourceListener ... { public function fetch($id) { throw new \Exception('fetch_EXCEPTION'); $service = $this->getAddressService(); $entity = $service->getAddress($id); return $entity; } } 中设置为throw new \Exception('fetch_EXCEPTION');):

BarResource#fetch(...)

3 个答案:

答案 0 :(得分:1)

我们目前正在成功使用以下代码来捕获Apigility的所有错误响应:

$app = $event->getTarget();
$em = $app->getEventManager();

$sendResponseListener = $app->getServiceManager()->get('SendResponseListener');
$sendResponseListener->getEventManager()->attach(SendResponseEvent::EVENT_SEND_RESPONSE,  function(SendResponseEvent $event) {
    $response = $event->getResponse();
    if ($response instanceof ApiProblemResponse) {
          $error = $response->getApiProblem()->toArray();
          // inspect $error array and log the information you want
    }
});

答案 1 :(得分:0)

您将收听者与MvcEvent::EVENT_DISPATCH_ERROR事件相关联。您确定在发送期间(即在控制器中)抛出new \Exception('foo')。同样在the answer you linked to中,他们提到此解决方案用于捕获控制器中抛出的错误/异常。

例如,如果您在渲染侦听器时抛出异常将永远不会被触发。在这些情况下,您需要收听MvcEvent::EVENT_RENDER_ERROR

我想知道这种设置是否是最好的方法。也许您应该搜索其他示例,而不是简单地跟踪/复制StackOverflow的答案。

编辑:

如果您还在使用the ApiProblem module for Apigility,则可能会在您自己的侦听器之前在MvcEvent::EVENT_DISPATCH_ERROR事件上触发the ApiProblemListener

the onDispatchError method中,ApiProblemListener返回一个响应对象,这可能是此后其他事件(优先级较低)未被触发的原因。

ApiProblemListener附加如下:

$this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'onDispatchError'), 100);

尝试将侦听器的优先级从ApiProblemListener提高到100以上。那么你可能会取得成功。

答案 2 :(得分:0)

我遇到了记录发生任何异常的同样问题,

我尝试将自己的听众附加到MvcEvent::EVENT_DISPATCH_ERROR,即使高优先级[3000]无效,经过一些研究并阅读Apigility代码我发现 任何抛出的异常都会被ApiProblemListener捕获,并从此异常信息中创建新的ApiProblemonRender method

解决问题和记录任何异常的解决方法是覆盖AbstractResourceListener并创建自己的ResourceListener并强制任何Resource类扩展它,

您自己的ResourceListener必须覆盖dispatch方法并调用父方法来捕获抛出的异常并记录它然后返回新的响应

示例:

<?php

namespace API\V1\Listener;

class MyOwnListener  extends AbstractResourceListener
{

    /**
     * {@inheritdoc}
     */
    public function dispatch(ResourceEvent $event)
    {
        try {
            $response = parent::dispatch($event);
        } catch (\Throwable $exception) {
            // catch thrown exception
            // then return new APIProblem with message you want 
            $response = new ApiProblem(500, 'error message');
        }
        return $response;
    }
}
相关问题