Commit 7a3dc7f2 authored by Fabien Potencier's avatar Fabien Potencier

feature #973 made the logger more configurable (fabpot)

This PR was merged into the 2.0.x-dev branch.

Discussion
----------

made the logger more configurable

Made the logger listener more configurable (see #924.)

Commits
-------

10535580 made the logger more configurable
parents 55cb6a17 10535580
......@@ -28,6 +28,9 @@ Parameters
* **monolog.name** (optional): Name of the monolog channel,
defaults to ``myapp``.
* **monolog.exception.logger_filter** (optional): An anonymous function that
filters which exceptions should be logged.
Services
--------
......@@ -91,7 +94,7 @@ it by extending the ``monolog`` service::
By default, all requests, responses and errors are logged by an event listener
registered as a service called `monolog.listener`. You can replace or remove
this service if you want to modify or disable the informations logged.
this service if you want to modify or disable the logged information.
Traits
------
......
......@@ -12,6 +12,7 @@
namespace Silex\EventListener;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
......@@ -24,15 +25,27 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Log request, response and exceptions
* Logs request, response, and exceptions.
*/
class LogListener implements EventSubscriberInterface
{
protected $logger;
protected $exceptionLogFilter;
public function __construct(LoggerInterface $logger)
public function __construct(LoggerInterface $logger, $exceptionLogFilter = null)
{
$this->logger = $logger;
if (null === $exceptionLogFilter) {
$exceptionLogFilter = function (\Exception $e) {
if ($e instanceof HttpExceptionInterface && $e->getStatusCode() < 500) {
return LogLevel::ERROR;
}
return LogLevel::CRITICAL;
};
}
$this->exceptionLogFilter = $exceptionLogFilter;
}
/**
......@@ -80,7 +93,7 @@ class LogListener implements EventSubscriberInterface
*/
protected function logRequest(Request $request)
{
$this->logger->info('> '.$request->getMethod().' '.$request->getRequestUri());
$this->logger->log(LogLevel::DEBUG, '> '.$request->getMethod().' '.$request->getRequestUri());
}
/**
......@@ -90,27 +103,18 @@ class LogListener implements EventSubscriberInterface
*/
protected function logResponse(Response $response)
{
$message = '< '.$response->getStatusCode();
if ($response instanceof RedirectResponse) {
$this->logger->info('< '.$response->getStatusCode().' '.$response->getTargetUrl());
} else {
$this->logger->info('< '.$response->getStatusCode());
$message .= ' '.$response->getTargetUrl();
}
$this->logger->log(LogLevel::DEBUG, $message);
}
/**
* Logs an exception
*
* @param Exception $e
*/
protected function logException(\Exception $e)
{
$message = sprintf('%s: %s (uncaught exception) at %s line %s', get_class($e), $e->getMessage(), $e->getFile(), $e->getLine());
if ($e instanceof HttpExceptionInterface && $e->getStatusCode() < 500) {
$this->logger->error($message, array('exception' => $e));
} else {
$this->logger->critical($message, array('exception' => $e));
}
$this->logger->log(call_user_func($this->exceptionLogFilter, $e), sprintf('%s: %s (uncaught exception) at %s line %s', get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()), array('exception' => $e));
}
public static function getSubscribedEvents()
......
......@@ -17,9 +17,6 @@ use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Silex\Application;
use Silex\Api\BootableProviderInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bridge\Monolog\Handler\DebugHandler;
use Silex\EventListener\LogListener;
......@@ -69,12 +66,13 @@ class MonologServiceProvider implements ServiceProviderInterface, BootableProvid
};
$app['monolog.listener'] = function () use ($app) {
return new LogListener($app['logger']);
return new LogListener($app['logger'], $app['monolog.exception.logger_filter']);
};
$app['monolog.name'] = 'myapp';
$app['monolog.bubble'] = true;
$app['monolog.permission'] = null;
$app['monolog.exception.logger_filter'] = null;
}
public function boot(Application $app)
......
......@@ -11,6 +11,7 @@
namespace Silex\Tests\EventListener;
use Psr\Log\LogLevel;
use Silex\EventListener\LogListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
......@@ -34,8 +35,8 @@ class LogListenerTest extends \PHPUnit_Framework_TestCase
$logger = $this->getMock('Psr\\Log\\LoggerInterface');
$logger
->expects($this->once())
->method('info')
->with($this->equalTo('> GET /foo'))
->method('log')
->with(LogLevel::DEBUG, '> GET /foo')
;
$dispatcher = new EventDispatcher();
......@@ -53,8 +54,8 @@ class LogListenerTest extends \PHPUnit_Framework_TestCase
$logger = $this->getMock('Psr\\Log\\LoggerInterface');
$logger
->expects($this->once())
->method('info')
->with($this->equalTo('< 301'))
->method('log')
->with(LogLevel::DEBUG, '< 301')
;
$dispatcher = new EventDispatcher();
......@@ -71,15 +72,14 @@ class LogListenerTest extends \PHPUnit_Framework_TestCase
{
$logger = $this->getMock('Psr\\Log\\LoggerInterface');
$logger
->expects($this->once())
->method('critical')
->with($this->equalTo('RuntimeException: Fatal error (uncaught exception) at '.__FILE__.' line '.(__LINE__+14)))
->expects($this->at(0))
->method('log')
->with(LogLevel::CRITICAL, 'RuntimeException: Fatal error (uncaught exception) at '.__FILE__.' line '.(__LINE__ + 13))
;
$logger
->expects($this->once())
->method('error')
->with($this->equalTo('Symfony\Component\HttpKernel\Exception\HttpException: Http error (uncaught exception) at '.__FILE__.' line '.(__LINE__+10)))
->expects($this->at(1))
->method('log')
->with(LogLevel::ERROR, 'Symfony\Component\HttpKernel\Exception\HttpException: Http error (uncaught exception) at '.__FILE__.' line '.(__LINE__ + 9))
;
$dispatcher = new EventDispatcher();
......@@ -88,7 +88,6 @@ class LogListenerTest extends \PHPUnit_Framework_TestCase
$kernel = $this->getMock('Symfony\\Component\\HttpKernel\\HttpKernelInterface');
$dispatcher->dispatch(KernelEvents::EXCEPTION, new GetResponseForExceptionEvent($kernel, Request::create('/foo'), HttpKernelInterface::SUB_REQUEST, new \RuntimeException('Fatal error')));
$dispatcher->dispatch(KernelEvents::EXCEPTION, new GetResponseForExceptionEvent($kernel, Request::create('/foo'), HttpKernelInterface::SUB_REQUEST, new HttpException(400, 'Http error')));
}
}
......@@ -38,8 +38,8 @@ class MonologServiceProviderTest extends \PHPUnit_Framework_TestCase
$request = Request::create('/foo');
$app->handle($request);
$this->assertTrue($app['monolog.handler']->hasInfo('> GET /foo'));
$this->assertTrue($app['monolog.handler']->hasInfo('< 200'));
$this->assertTrue($app['monolog.handler']->hasDebug('> GET /foo'));
$this->assertTrue($app['monolog.handler']->hasDebug('< 200'));
$this->assertTrue($app['monolog.handler']->hasInfo('Matched route "GET_foo" (parameters: "_controller": "{}", "_route": "GET_foo")'));
}
......@@ -108,7 +108,7 @@ class MonologServiceProviderTest extends \PHPUnit_Framework_TestCase
$request = Request::create('/foo');
$app->handle($request);
$this->assertTrue($app['monolog.handler']->hasInfo('< 302 /bar'));
$this->assertTrue($app['monolog.handler']->hasDebug('< 302 /bar'));
}
public function testErrorLoggingGivesWayToSecurityExceptionHandling()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment