Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 291b1e4

Browse filesBrowse files
jameshalsallchalasr
authored andcommitted
Add basic support for automatic console exception logging
1 parent f8b02ed commit 291b1e4
Copy full SHA for 291b1e4

File tree

Expand file treeCollapse file tree

4 files changed

+202
-0
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+202
-0
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ public function load(array $configs, ContainerBuilder $container)
8181
}
8282

8383
$loader->load('fragment_renderer.xml');
84+
$loader->load('console.xml');
8485

8586
// Property access is used by both the Form and the Validator component
8687
$loader->load('property_access.xml');
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<services>
8+
<service id="console.exception_listener" class="Symfony\Component\Console\EventListener\ExceptionListener">
9+
<tag name="kernel.event_subscriber" />
10+
<argument type="service" id="logger" on-invalid="null" />
11+
</service>
12+
</services>
13+
</container>
+90Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console\EventListener;
13+
14+
use Psr\Log\LoggerInterface;
15+
use Symfony\Component\Console\ConsoleEvents;
16+
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
17+
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
18+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
19+
20+
/**
21+
* Console exception listener.
22+
*
23+
* Attempts to log exceptions or abnormal terminations of console commands.
24+
*
25+
* @author James Halsall <james.t.halsall@googlemail.com>
26+
*/
27+
class ExceptionListener implements EventSubscriberInterface
28+
{
29+
/**
30+
* @var LoggerInterface
31+
*/
32+
protected $logger;
33+
34+
/**
35+
* Constructor.
36+
*
37+
* @param LoggerInterface $logger A logger
38+
*/
39+
public function __construct(LoggerInterface $logger = null)
40+
{
41+
$this->logger = $logger;
42+
}
43+
44+
/**
45+
* Handles console command exception.
46+
*
47+
* @param ConsoleExceptionEvent $event Console event
48+
*/
49+
public function onKernelException(ConsoleExceptionEvent $event)
50+
{
51+
if (null === $this->logger) {
52+
return;
53+
}
54+
55+
$exception = $event->getException();
56+
$input = (string) $event->getInput();
57+
58+
$this->logger->error('Exception thrown while running command: "{command}". Message: "{message}"', array('exception' => $exception, 'command' => $input, 'message' => $exception->getMessage()));
59+
}
60+
61+
/**
62+
* Handles termination of console command.
63+
*
64+
* @param ConsoleTerminateEvent $event Console event
65+
*/
66+
public function onKernelTerminate(ConsoleTerminateEvent $event)
67+
{
68+
if (null === $this->logger) {
69+
return;
70+
}
71+
72+
$exitCode = $event->getExitCode();
73+
74+
if ($exitCode === 0) {
75+
return;
76+
}
77+
78+
$input = (string) $event->getInput();
79+
80+
$this->logger->error('Command "{command}" exited with status code "{code}"', array('command' => (string) $input, 'code' => $exitCode));
81+
}
82+
83+
public static function getSubscribedEvents()
84+
{
85+
return array(
86+
ConsoleEvents::EXCEPTION => array('onKernelException', -128),
87+
ConsoleEvents::TERMINATE => array('onKernelTerminate', -128),
88+
);
89+
}
90+
}
+98Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console\Tests\EventListener;
13+
14+
use Psr\Log\LoggerInterface;
15+
use Symfony\Component\Console\Command\Command;
16+
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
17+
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
18+
use Symfony\Component\Console\EventListener\ExceptionListener;
19+
use Symfony\Component\Console\Input\ArrayInput;
20+
use Symfony\Component\Console\Tests\Output\TestOutput;
21+
22+
class ExceptionListenerTest extends \PHPUnit_Framework_TestCase
23+
{
24+
public function testOnKernelException()
25+
{
26+
$logger = $this->getLogger();
27+
$listener = new ExceptionListener($logger);
28+
29+
$exception = new \RuntimeException('An error occurred');
30+
31+
$logger
32+
->expects($this->once())
33+
->method('error')
34+
->with('Exception thrown while running command: "{command}". Message: "{message}"', array('exception' => $exception, 'command' => '\'test:run\' --foo=baz buzz', 'message' => 'An error occurred'))
35+
;
36+
37+
$input = array(
38+
'name' => 'test:run',
39+
'--foo' => 'baz',
40+
'bar' => 'buzz'
41+
);
42+
43+
$listener->onKernelException($this->getConsoleExceptionEvent($exception, $input, 1));
44+
}
45+
46+
public function testOnKernelTerminateForNonZeroExitCodeWritesToLog()
47+
{
48+
$logger = $this->getLogger();
49+
$listener = new ExceptionListener($logger);
50+
51+
$logger
52+
->expects($this->once())
53+
->method('error')
54+
->with('Command "{command}" exited with status code "{code}"', array('command' => '\'test:run\'', 'code' => 255))
55+
;
56+
57+
$listener->onKernelTerminate($this->getConsoleTerminateEvent(array('name' => 'test:run'), 255));
58+
}
59+
60+
public function testOnKernelTerminateForZeroExitCodeDoesNotWriteToLog()
61+
{
62+
$logger = $this->getLogger();
63+
$listener = new ExceptionListener($logger);
64+
65+
$logger
66+
->expects($this->never())
67+
->method('error')
68+
;
69+
70+
$listener->onKernelTerminate($this->getConsoleTerminateEvent(array('name' => 'test:run'), 0));
71+
}
72+
73+
public function testGetSubscribedEvents()
74+
{
75+
$this->assertEquals(
76+
array(
77+
'console.exception' => array('onKernelException', -128),
78+
'console.terminate' => array('onKernelTerminate', -128),
79+
),
80+
ExceptionListener::getSubscribedEvents()
81+
);
82+
}
83+
84+
private function getLogger()
85+
{
86+
return $this->getMockForAbstractClass(LoggerInterface::class);
87+
}
88+
89+
private function getConsoleExceptionEvent(\Exception $exception, $input, $exitCode)
90+
{
91+
return new ConsoleExceptionEvent(new Command('test:run'), new ArrayInput($input), new TestOutput(), $exception, $exitCode);
92+
}
93+
94+
private function getConsoleTerminateEvent($input, $exitCode)
95+
{
96+
return new ConsoleTerminateEvent(new Command('test:run'), new ArrayInput($input), new TestOutput(), $exitCode);
97+
}
98+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.