Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony 2.4: Why are 500 errors not caught by kernel.exception listener

I'm trying to create a listener for listening 403, 404, and 500 exceptions. This works fine for 403 and 404 exceptions but not for 500 exceptions. For 500 exceptions (or exceptions that will be returned as 500 errors for the client) the method onKernelException is never called. It appears to be the same in my current Symfony project and when the code is added to a clean Symfony 2.4.1 install.

I then introduce a 500 error by executing a non-existent function.

In the development environment I get a Symfony generated page saying "Whoops, looks like something went wrong." and then views information about the thrown "UndefinedFunctionException" along with the 500 status code.

In the production environment I get an empty page along with the 500 status code. In the error log prod.log I get a "PHP Fatal error: Call to undefined function" error with a stack trace.

Since Symfony obviously catches this error, why can I not catch the corresponding exception with a kernel.exception listener?

The class I'm using is:

<?php

namespace SystemBundle\Listener;

use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;

/**
 * This exception listener will listen to 500, 404, and 403 errors and render a corresponding view
 *
 * @SuppressWarnings("static")
 * @SuppressWarnings("else")
 */
class ExceptionListener
{
    protected $templating;
    protected $kernel;

    public function __construct(EngineInterface $templating, $kernel)
    {
        $this->templating = $templating;
        $this->kernel = $kernel;
    }

    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        $container = $this->kernel->getContainer();

        // Exception object
        $exception = $event->getException();

        // Create Response object
        $response = new Response();

        // Get view name
        $viewName = $container->getParameter('theme') . ':Exception:exception.html.twig';
        if (!$this->templating->exists($viewName)) {
            $viewName = 'AckebrinkChallengerSystemBundle:Exception:exception.html.twig';
        }

        // Set response content
        $response->setContent($this->templating->render($viewName, array('exception' => $exception)));

        // HttpExceptionInterface is a special type of exception that
        // holds status code and header details
        if ($exception instanceof HttpExceptionInterface) {
            $response->setStatusCode($exception->getStatusCode());
            $response->headers->replace($exception->getHeaders());
        } else {
            $response->setStatusCode(500);
        }

        // set the new $response object to the $event
        $event->setResponse($response);
    }
}

and the service configuration I use is:

services:
    kernel.listener.system_exception_listener:
        class: SystemBundle\Listener\ExceptionListener
        arguments:
            - @templating
            - @kernel
        tags:
            - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
like image 295
tirithen Avatar asked Jan 15 '14 13:01

tirithen


1 Answers

First of all, ensure you cleared the Prod cache.

Second, see if something in the web server is catching errors for you, ie fastcgi_intercept_errors in Nginx, but this is unlikely to happen.

Third, try throwing an exception rather than calling a non-declared function.

Fourth, try to $event->setResponse as early as possible in the exception listener to ensure there's no error in the handler itself.

Other than that, I have no idea. The code seems to be Ok. Have you tried with XDebug to see how the code flows?

like image 90
Nico Andrade Avatar answered Oct 16 '22 10:10

Nico Andrade