diff --git a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php new file mode 100644 index 0000000000000..561af6f3948b6 --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php @@ -0,0 +1,74 @@ + + * + * 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 + */ +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; + } +} diff --git a/src/Symfony/Bridge/Monolog/Tests/Handler/FingersCrossed/HttpCodeActivationStrategyTest.php b/src/Symfony/Bridge/Monolog/Tests/Handler/FingersCrossed/HttpCodeActivationStrategyTest.php new file mode 100644 index 0000000000000..9f0b0b3735e44 --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Tests/Handler/FingersCrossed/HttpCodeActivationStrategyTest.php @@ -0,0 +1,81 @@ + + * + * 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)); + } +}