Skip to content

Commit 3b1cf07

Browse files
committed
[HttpKernel] Add support for configuring log level, and status code by exception class
1 parent 7b52f24 commit 3b1cf07

File tree

13 files changed

+171
-9
lines changed

13 files changed

+171
-9
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG
88
* Deprecate the `AdapterInterface` autowiring alias, use `CacheItemPoolInterface` instead
99
* Deprecate the public `profiler` service to private
1010
* Deprecate `get()`, `has()`, `getDoctrine()`, and `dispatchMessage()` in `AbstractController`, use method/constructor injection instead
11+
* Add support for configuring log level, and status code by exception class
1112

1213
5.3
1314
---

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Doctrine\Common\Annotations\PsrCachedReader;
1616
use Doctrine\Common\Cache\Cache;
1717
use Doctrine\DBAL\Connection;
18+
use Psr\Log\LogLevel;
1819
use Symfony\Bundle\FullStack;
1920
use Symfony\Component\Asset\Package;
2021
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
@@ -139,6 +140,7 @@ public function getConfigTreeBuilder()
139140
$this->addPropertyInfoSection($rootNode, $enableIfStandalone);
140141
$this->addCacheSection($rootNode, $willBeAvailable);
141142
$this->addPhpErrorsSection($rootNode);
143+
$this->addExceptionsSection($rootNode);
142144
$this->addWebLinkSection($rootNode, $enableIfStandalone);
143145
$this->addLockSection($rootNode, $enableIfStandalone);
144146
$this->addMessengerSection($rootNode, $enableIfStandalone);
@@ -1163,6 +1165,64 @@ private function addPhpErrorsSection(ArrayNodeDefinition $rootNode)
11631165
;
11641166
}
11651167

1168+
private function addExceptionsSection(ArrayNodeDefinition $rootNode)
1169+
{
1170+
$logLevels = (new \ReflectionClass(LogLevel::class))->getConstants();
1171+
1172+
$rootNode
1173+
->children()
1174+
->arrayNode('exceptions')
1175+
->info('Exception handling configuration')
1176+
->beforeNormalization()
1177+
->ifArray()
1178+
->then(function (array $v): array {
1179+
if (!\array_key_exists('exception', $v)) {
1180+
return $v;
1181+
}
1182+
1183+
// Fix XML normalization
1184+
$data = isset($v['exception'][0]) ? $v['exception'] : [$v['exception']];
1185+
$exceptions = [];
1186+
foreach ($data as $exception) {
1187+
$config = [];
1188+
if (\array_key_exists('log-level', $exception)) {
1189+
$config['log_level'] = $exception['log-level'];
1190+
}
1191+
if (\array_key_exists('status-code', $exception)) {
1192+
$config['status_code'] = $exception['status-code'];
1193+
}
1194+
$exceptions[$exception['name']] = $config;
1195+
}
1196+
1197+
return $exceptions;
1198+
})
1199+
->end()
1200+
->prototype('array')
1201+
->fixXmlConfig('exception')
1202+
->children()
1203+
->scalarNode('log_level')
1204+
->info('The level of log message. Null to let Symfony decide.')
1205+
->validate()
1206+
->ifTrue(function ($v) use ($logLevels) { return !\in_array($v, $logLevels); })
1207+
->thenInvalid(sprintf('The log level is not valid. Pick one among "%s".', implode('", "', $logLevels)))
1208+
->end()
1209+
->defaultNull()
1210+
->end()
1211+
->scalarNode('status_code')
1212+
->info('The status code of the response. Null to let Symfony decide.')
1213+
->validate()
1214+
->ifTrue(function ($v) { return !\in_array($v, range(100, 499)); })
1215+
->thenInvalid('The log level is not valid. Pick one among between 100 et 599.')
1216+
->end()
1217+
->defaultNull()
1218+
->end()
1219+
->end()
1220+
->end()
1221+
->end()
1222+
->end()
1223+
;
1224+
}
1225+
11661226
private function addLockSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone)
11671227
{
11681228
$rootNode

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,8 @@ public function load(array $configs, ContainerBuilder $container)
428428
$this->registerPropertyAccessConfiguration($config['property_access'], $container, $loader);
429429
$this->registerSecretsConfiguration($config['secrets'], $container, $loader);
430430

431+
$container->getDefinition('exception_listener')->replaceArgument(3, $config['exceptions']);
432+
431433
if ($this->isConfigEnabled($container, $config['serializer'])) {
432434
if (!class_exists(\Symfony\Component\Serializer\Serializer::class)) {
433435
throw new LogicException('Serializer support cannot be enabled as the Serializer component is not installed. Try running "composer require symfony/serializer-pack".');

src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<xsd:element name="cache" type="cache" minOccurs="0" maxOccurs="1" />
3030
<xsd:element name="workflow" type="workflow" minOccurs="0" maxOccurs="unbounded" />
3131
<xsd:element name="php-errors" type="php-errors" minOccurs="0" maxOccurs="1" />
32+
<xsd:element name="exceptions" type="exceptions" minOccurs="0" maxOccurs="1" />
3233
<xsd:element name="lock" type="lock" minOccurs="0" maxOccurs="1" />
3334
<xsd:element name="messenger" type="messenger" minOccurs="0" maxOccurs="1" />
3435
<xsd:element name="http-client" type="http_client" minOccurs="0" maxOccurs="1" />
@@ -341,6 +342,18 @@
341342
<xsd:attribute name="logLevel" type="xsd:string" />
342343
</xsd:complexType>
343344

345+
<xsd:complexType name="exceptions">
346+
<xsd:sequence>
347+
<xsd:element name="exception" type="exception" minOccurs="0" maxOccurs="unbounded" />
348+
</xsd:sequence>
349+
</xsd:complexType>
350+
351+
<xsd:complexType name="exception">
352+
<xsd:attribute name="name" type="xsd:string" use="required" />
353+
<xsd:attribute name="log-level" type="xsd:string" />
354+
<xsd:attribute name="status-code" type="xsd:int" />
355+
</xsd:complexType>
356+
344357
<xsd:complexType name="marking_store">
345358
<xsd:sequence>
346359
<xsd:element name="argument" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />

src/Symfony/Bundle/FrameworkBundle/Resources/config/web.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
param('kernel.error_controller'),
103103
service('logger')->nullOnInvalid(),
104104
param('kernel.debug'),
105+
abstract_arg('an exceptions to log & status code mapping'),
105106
])
106107
->tag('kernel.event_subscriber')
107108
->tag('monolog.logger', ['channel' => 'request'])

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,7 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
578578
'name_based_uuid_version' => 5,
579579
'time_based_uuid_version' => 6,
580580
],
581+
'exceptions' => [],
581582
];
582583
}
583584
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
4+
5+
$container->loadFromExtension('framework', [
6+
'exceptions' => [
7+
BadRequestHttpException::class => [
8+
'log_level' => 'info',
9+
'status_code' => 422,
10+
],
11+
],
12+
]);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" ?>
2+
<container xmlns="http://symfony.com/schema/dic/services"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:framework="http://symfony.com/schema/dic/symfony"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
6+
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
7+
8+
<framework:config>
9+
<framework:exceptions>
10+
<framework:exception name="Symfony\Component\HttpKernel\Exception\BadRequestHttpException" log-level="info" status-code="422" />
11+
</framework:exceptions>
12+
</framework:config>
13+
</container>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
framework:
2+
exceptions:
3+
Symfony\Component\HttpKernel\Exception\BadRequestHttpException:
4+
log_level: info
5+
status_code: 422

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,18 @@ public function testPhpErrorsWithLogLevels()
522522
], $definition->getArgument(2));
523523
}
524524

525+
public function testExceptionsConfig()
526+
{
527+
$container = $this->createContainerFromFile('exceptions');
528+
529+
$this->assertSame([
530+
\Symfony\Component\HttpKernel\Exception\BadRequestHttpException::class => [
531+
'log_level' => 'info',
532+
'status_code' => 422,
533+
],
534+
], $container->getDefinition('exception_listener')->getArgument(3));
535+
}
536+
525537
public function testRouter()
526538
{
527539
$container = $this->createContainerFromFile('full');

0 commit comments

Comments
 (0)