I want to be alerted when bad things happen in my Symfony2 app. Right now I just look for ERROR
in the logs. Unfortunately, "HTTP 404 - file not found" (NotFoundHttpException) gets logged as an error, as does "HTTP 403 - forbidden" (AccessDeniedHttpException).
This doesn't warrant an error; at the most these should be warnings. How can I make these log at a less severe level?
Example error:
[2012-07-02 16:58:21] request.ERROR: Symfony\Component\HttpKernel\Exception\NotFoundHttpException: No route found for "GET /foo" (uncaught exception) at /home/user/Symfony2_v2.0.12/vendor/symfony/src/Symfony/Bundle/FrameworkBundle/EventListener/RouterListener.php line 83 [] []
I found something that works. The Symfony2 internals doc on the kernel.exeption event mention that a response can be set on the event, and the GetResponseForExceptionEvent docs say
The propagation of this event is stopped as soon as a response is set.
I cobbled together a listener that appears to do just what I want:
<?php
namespace Acme\DemoBundle\Listener;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
class ExceptionLoggingListener {
private $logger;
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
public function onKernelException(GetResponseForExceptionEvent $event) {
if(!$event) {
$this->logger->err("Unknown kernel.exception in ".__CLASS__);
return;
}
$notFoundException = '\Symfony\Component\HttpKernel\Exception\NotFoundHttpException';
$e = $event->getException();
$type = get_class($e);
if ($e instanceof $notFoundException) {
$this->logger->info($e->getMessage());
$response = new Response(Response::$statusTexts[404], 404);
$event->setResponse($response);
return;
}
$accessDeniedException = '\Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException';
if ($e instanceof $accessDeniedException) {
$this->logger->info($e->getMessage());
$response = new Response(Response::$statusTexts[403], 403);
$event->setResponse($response);
return;
}
$this->logger->err("kernel.exception of type $type. Message: '".$e->getMessage()."'\nFile: ".$e->getFile().", line ".$e->getLine()."\nTrace: ".$e->getTraceAsString());
}
}
Here's a way with less code :)
1. Extend Symfonys ExceptionListner class and override the logging method:
<?php
use Symfony\Component\HttpKernel\EventListener\ExceptionListener as BaseListener;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ExceptionListener extends BaseListener
{
/**
* Logs an exception.
*
* @param \Exception $exception The original \Exception instance
* @param string $message The error message to log
* @param Boolean $original False when the handling of the exception thrown another exception
*/
protected function logException(\Exception $exception, $message, $original = true)
{
$isCritical = !$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500;
if (null !== $this->logger) {
if ($isCritical) {
$this->logger->critical($message);
} else {
if ($exception instanceof NotFoundHttpException) {
$this->logger->info($message);
} else {
$this->logger->error($message);
}
}
} elseif (!$original || $isCritical) {
error_log($message);
}
}
}
2. Configure the twig.exception_listener.class parameter:
parameters:
twig.exception_listener.class: "MyBundle\EventListener\ExceptionListener"
Just add excluded_404s
to your configuration:
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_404s:
- ^/
nested:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
See http://symfony.com/doc/current/logging/monolog_regex_based_excludes.html for a reference
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With