feature #23707 [Monolog Bridge][DX] Add a Monolog activation strategy for ignoring specific HTTP codes (simshaun, fabpot)
This PR was merged into the 4.1-dev branch. Discussion ---------- [Monolog Bridge][DX] Add a Monolog activation strategy for ignoring specific HTTP codes | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #9712 | License | MIT | Doc PR | symfony/symfony-docs#8235 This PR introduces a Monolog activation strategy that makes it easy to ignore specific HTTP codes. e.g. Stopping logs from being flooded with 403s, 404s, and 405s. Relevant Symfony integration PR on symfony/monolog-bundle: https://github.com/symfony/monolog-bundle/pull/221 Commits -------6fc1cc3ec3
added some validationc11a8eb92e
Add a Monolog activation strategy for ignoring specific HTTP codes
This commit is contained in:
commit
ee51f74a8c
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\Monolog\Handler\FingersCrossed;
|
||||||
|
|
||||||
|
use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activation strategy that ignores certain HTTP codes.
|
||||||
|
*
|
||||||
|
* @author Shaun Simmons <shaun@envysphere.com>
|
||||||
|
*/
|
||||||
|
class HttpCodeActivationStrategy extends ErrorLevelActivationStrategy
|
||||||
|
{
|
||||||
|
private $exclusions;
|
||||||
|
private $requestStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $exclusions each exclusion must have a "code" and "urls" keys
|
||||||
|
*/
|
||||||
|
public function __construct(RequestStack $requestStack, array $exclusions, $actionLevel)
|
||||||
|
{
|
||||||
|
foreach ($exclusions as $exclusion) {
|
||||||
|
if (!array_key_exists('code', $exclusion)) {
|
||||||
|
throw new \LogicException(sprintf('An exclusion must have a "code" key'));
|
||||||
|
}
|
||||||
|
if (!array_key_exists('urls', $exclusion)) {
|
||||||
|
throw new \LogicException(sprintf('An exclusion must have a "urls" key'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($actionLevel);
|
||||||
|
|
||||||
|
$this->requestStack = $requestStack;
|
||||||
|
$this->exclusions = $exclusions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isHandlerActivated(array $record)
|
||||||
|
{
|
||||||
|
$isActivated = parent::isHandlerActivated($record);
|
||||||
|
|
||||||
|
if (
|
||||||
|
$isActivated
|
||||||
|
&& isset($record['context']['exception'])
|
||||||
|
&& $record['context']['exception'] instanceof HttpException
|
||||||
|
&& ($request = $this->requestStack->getMasterRequest())
|
||||||
|
) {
|
||||||
|
foreach ($this->exclusions as $exclusion) {
|
||||||
|
if ($record['context']['exception']->getStatusCode() !== $exclusion['code']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$urlBlacklist = null;
|
||||||
|
if (count($exclusion['urls'])) {
|
||||||
|
return !preg_match('{('.implode('|', $exclusion['urls']).')}i', $request->getPathInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isActivated;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\Monolog\Tests\Handler\FingersCrossed;
|
||||||
|
|
||||||
|
use Monolog\Logger;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
|
|
||||||
|
class HttpCodeActivationStrategyTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @expectedException \LogicException
|
||||||
|
*/
|
||||||
|
public function testExclusionsWithoutCode()
|
||||||
|
{
|
||||||
|
new HttpCodeActivationStrategy(new RequestStack(), array(array('urls' => array())), Logger::WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \LogicException
|
||||||
|
*/
|
||||||
|
public function testExclusionsWithoutUrls()
|
||||||
|
{
|
||||||
|
new HttpCodeActivationStrategy(new RequestStack(), array(array('code' => 404)), Logger::WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider isActivatedProvider
|
||||||
|
*/
|
||||||
|
public function testIsActivated($url, $record, $expected)
|
||||||
|
{
|
||||||
|
$requestStack = new RequestStack();
|
||||||
|
$requestStack->push(Request::create($url));
|
||||||
|
|
||||||
|
$strategy = new HttpCodeActivationStrategy(
|
||||||
|
$requestStack,
|
||||||
|
array(
|
||||||
|
array('code' => 403, 'urls' => array()),
|
||||||
|
array('code' => 404, 'urls' => array()),
|
||||||
|
array('code' => 405, 'urls' => array()),
|
||||||
|
array('code' => 400, 'urls' => array('^/400/a', '^/400/b')),
|
||||||
|
),
|
||||||
|
Logger::WARNING
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $strategy->isHandlerActivated($record));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isActivatedProvider()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array('/test', array('level' => Logger::ERROR), true),
|
||||||
|
array('/400', array('level' => Logger::ERROR, 'context' => $this->getContextException(400)), true),
|
||||||
|
array('/400/a', array('level' => Logger::ERROR, 'context' => $this->getContextException(400)), false),
|
||||||
|
array('/400/b', array('level' => Logger::ERROR, 'context' => $this->getContextException(400)), false),
|
||||||
|
array('/400/c', array('level' => Logger::ERROR, 'context' => $this->getContextException(400)), true),
|
||||||
|
array('/401', array('level' => Logger::ERROR, 'context' => $this->getContextException(401)), true),
|
||||||
|
array('/403', array('level' => Logger::ERROR, 'context' => $this->getContextException(403)), false),
|
||||||
|
array('/404', array('level' => Logger::ERROR, 'context' => $this->getContextException(404)), false),
|
||||||
|
array('/405', array('level' => Logger::ERROR, 'context' => $this->getContextException(405)), false),
|
||||||
|
array('/500', array('level' => Logger::ERROR, 'context' => $this->getContextException(500)), true),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getContextException($code)
|
||||||
|
{
|
||||||
|
return array('exception' => new HttpException($code));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user