2012-07-02 6 views
11

Quiero ser alertado cuando suceden cosas malas en mi aplicación Symfony2. En este momento solo busco ERROR en los registros. Desafortunadamente, "HTTP 404 - archivo no encontrado" (NotFoundHttpException) se registra como un error, al igual que "HTTP 403 - prohibido" (AccessDeniedHttpException).¿Cómo puedo reducir la gravedad de NotFoundHttpException?

Esto no garantiza un error; a lo sumo estas deberían ser advertencias. ¿Cómo puedo hacer estos registros en un nivel menos severo?

Ejemplo de 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 [] [] 

Respuesta

8

he encontrado algo que funciona. La mención Symfony2 internals doc on the kernel.exeption event que una respuesta se puede establecer en el evento, y la GetResponseForExceptionEvent docs dicen

The propagation of this event is stopped as soon as a response is set.

I remendado un oyente que aparece para hacer precisamente lo que quiero:

<?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()); 
    } 

} 
+2

aleatoria nota lateral: se debe utilizar 'instaceof' en lugar de' tipo $ === 'bla '' http://php.net/manual/en/internals2.opcodes.instanceof.php – MDrollette

+0

buena llamada. Reparado, gracias! –

+0

[Lachlan Pease escribió] (http://article.gmane.org/gmane.comp.php.symfony.symfony2/9774 /): "La alternativa sería subclasificar Symfony \ Component \ HttpKernel \ EventListener \ ExceptionListener y cambiar la lógica a warn() en NotFoundHttpExceptions - esto tendría el beneficio de no necesitar múltiples oyentes de excepción (algo poco importante)), pero tendrías que mantener todo el código de generación de respuestas en tu propia subclase, que es una pesadilla de mantenimiento ". (¡Gracias, Lachlan, eso suena aún mejor!) –

6

Aquí está una manera con menos código :)

1. Extender clase Symfonys ExceptionListner y anular el método de registro:

<?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. Configurar el parámetro twig.exception_listener.class:

parameters: 
    twig.exception_listener.class: "MyBundle\EventListener\ExceptionListener" 
+4

Vale la pena observar que todos los que todavía usan la versión 2.1 fallarán al implementar este método debido a que la versión 2.1 de la clase 'ExceptionListener' no tiene una Método 'logException' (https://github.com/symfony/symfony/blob/2.1/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php) – akluth

0

También puede utilizar la estrategia de la actividad a nivel de error (en realidad incorporado 404 errores de Symfony con exclusión se hace uso de esta, así que supongo que esta es una forma correcta de hacerlo).

config.yml

monolog: 
    handlers: 
     main: 
      type: fingers_crossed 
      handler: loggly 
      activation_strategy: 'mybundle.monolog.fingers_crossed.activation_strategy' 
     loggly: 
      type: loggly 
      token: %loggly_token% 
      level: error 
      tag: %loggly_tag% 

services.yml (tenga en cuenta que el nivel de acción se establece aquí, no en config.yml)

services: 
    mybundle.monolog.fingers_crossed.activation_strategy: 
     class: MyBundle\Handler\FingersCrossed\ErrorLevelActivationStrategy 
     arguments: 
      - '@request_stack' 
      - 'error' 

ErrorLevelActivationStrategy.php

<?php 
namespace MyBundle\Handler\FingersCrossed; 

use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy as BaseErrorLevelActivationStrategy; 
use Symfony\Component\HttpKernel\Exception\HttpException; 
use Symfony\Component\HttpFoundation\RequestStack; 

/** 
* Activation strategy that ignores client errors (4xx) 
*/ 
class ErrorLevelActivationStrategy extends BaseErrorLevelActivationStrategy 
{ 
    protected $requestStack; 
    public function __construct(RequestStack $requestStack, $actionLevel) 
    { 
     parent::__construct($actionLevel); 
     $this->requestStack = $requestStack; 
    } 
    /** 
    * {@inheritdoc} 
    */ 
    public function isHandlerActivated(array $record) 
    { 
     $isActivated = parent::isHandlerActivated($record); 
     if (
      $isActivated 
      && isset($record['context']['exception']) 
      && $record['context']['exception'] instanceof HttpException 
      && $record['context']['exception']->getStatusCode() >= 400 
      && $record['context']['exception']->getStatusCode() <= 499 
      && ($request = $this->requestStack->getMasterRequest()) 
     ) { 
      $isActivated = false; 
     } 
     return $isActivated; 
    } 
} 

https://gist.github.com/sobstel/d791d0347ee1f4e47b6e

Cuestiones relacionadas