8000 Add Console ExceptionListener · symfony/symfony@07a2966 · GitHub
[go: up one dir, main page]

Skip to content

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 07a2966

Browse files
committed
Add Console ExceptionListener
Handle non string-castable inputs Cleanup input for display Naming changes InputInterface doesnt have a toString() Logger must be private Remove useless doc blocks Tweak tests
1 parent a290788 commit 07a2966

File tree

5 files changed

+81
-62
lines changed

5 files changed

+81
-62
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
66

77
<services>
8+
89
<service id="console.exception_listener" class="Symfony\Component\Console\EventListener\ExceptionListener">
910
<tag name="kernel.event_subscriber" />
1011
<argument type="service" id="logger" on-invalid="null" />
1112
</service>
13+
1214
</services>
1315
</container>

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"require-dev": {
3535
"symfony/asset": "~2.8|~3.0",
3636
"symfony/browser-kit": "~2.8|~3.0",
37-
"symfony/console": "~2.8.8|~3.0.8|~3.1.2|~3.2",
37+
"symfony/console": "~3.3",
3838
"symfony/css-selector": "~2.8|~3.0",
3939
"symfony/dom-crawler": "~2.8|~3.0",
4040
"symfony/polyfill-intl-icu": "~1.0",

src/Symfony/Component/Console/EventListener/ExceptionListener.php

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Console\EventListener;
1313

1414
use Psr\Log\LoggerInterface;
15+
use Symfony\Component\Console\Event\ConsoleEvent;
1516
use Symfony\Component\Console\ConsoleEvents;
1617
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
1718
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
@@ -20,71 +21,60 @@
2021
/**
2122
* Console exception listener.
2223
*
23-
* Attempts to log exceptions or abnormal terminations of console commands.
24-
*
2524
* @author James Halsall <james.t.halsall@googlemail.com>
25+
* @author Robin Chalas <robin.chalas@gmail.com>
2626
*/
2727
class ExceptionListener implements EventSubscriberInterface
2828
{
29-
/**
30-
* @var LoggerInterface
31-
*/
32-
protected $logger;
33-
34-
/**
35-
* Constructor.
36-
*
37-
* @param LoggerInterface $logger A logger
38-
*/
29+
private $logger;
30+
3931
public function __construct(LoggerInterface $logger = null)
4032
{
4133
$this->logger = $logger;
4234
}
4335

44-
/**
45-
* Handles console command exception.
46-
*
47-
* @param ConsoleExceptionEvent $event Console event
48-
*/
49-
public function onKernelException(ConsoleExceptionEvent $event)
36+
public function onConsoleException(ConsoleExceptionEvent $event)
5037
{
5138
if (null === $this->logger) {
5239
return;
5340
}
5441

5542
$exception = $event->getException();
56-
$input = (string) $event->getInput();
5743

58-
$this->logger->error('Exception thrown while running command: "{command}". Message: "{message}"', array('exception' => $exception, 'command' => $input, 'message' => $exception->getMessage()));
44+
$this->logger->error('Exception thrown while running command: "{command}". Message: "{message}"', array('exception' => $exception, 'command' => $this->getCommandAsString($event), 'message' => $exception->getMessage()));
5945
}
6046

61-
/**
62-
* Handles termination of console command.
63-
*
64-
* @param ConsoleTerminateEvent $event Console event
65-
*/
66-
public function onKernelTerminate(ConsoleTerminateEvent $event)
47+
public function onConsoleTerminate(ConsoleTerminateEvent $event)
6748
{
6849
if (null === $this->logger) {
6950
return;
7051
}
7152

7253
$exitCode = $event->getExitCode();
7354

74-
if ($exitCode === 0) {
55+
if (0 === $exitCode) {
7556
return;
7657
}
7758

78-
$input = (string) $event->getInput();
79-
80-
$this->logger->error('Command "{command}" exited with status code "{code}"', array('command' => (string) $input, 'code' => $exitCode));
59+
$this->logger->error('Command "{command}" exited with code "{code}"', array('command' => $this->getCommandAsString($event), 'code' => $exitCode));
8160
}
8261

8362
public static function getSubscribedEvents()
8463
{
8564
return array(
86-
ConsoleEvents::EXCEPTION => array('onKernelException', -128),
87-
ConsoleEvents::TERMINATE => array('onKernelTerminate', -128),
65+
ConsoleEvents::EXCEPTION => array('onConsoleException', -128),
66+
ConsoleEvents::TERMINATE => array('onConsoleTerminate', -128),
8867
);
8968
}
69+
70+
private static function getCommandAsString(ConsoleEvent $event)
71+
{
72+
$commandName = $event->getCommand()->getName();
73+
74+
if (method_exists($event->getInput(), '__toString')) {
75+
return str_replace(array("'$commandName'", "\"$commandName\""), $commandName, (string) $event->getInput());
76+
}
77+
78+
return $commandName;
79+
}
9080
}

src/Symfony/Component/Console/Tests/EventListener/ExceptionListenerTest.php

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,83 +16,110 @@
1616
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
1717
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
1818
use Symfony\Component\Console\EventListener\ExceptionListener;
19+
use Symfony\Component\Console\Input\ArgvInput;
1920
use Symfony\Component\Console\Input\ArrayInput;
20-
use Symfony\Component\Console\Tests\Output\TestOutput;
21+
use Symfony\Component\Console\Input\StringInput;
22+
use Symfony\Component\Console\Input\InputInterface;
23+
use Symfony\Component\Console\Output\OutputInterface;
2124

2225
class ExceptionListenerTest extends \PHPUnit_Framework_TestCase
2326
{
24-
public function testOnKernelException()
27+
public function testOnConsoleException()
2528
{
26-
$logger = $this->getLogger();
27-
$listener = new ExceptionListener($logger);
28-
2929
$exception = new \RuntimeException('An error occurred');
3030

31+
$logger = $this->getLogger();
3132
$logger
3233
->expects($this->once())
3334
->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+
->with('Exception thrown while running command: "{command}". Message: "{message}"', array('exception' => $exception, 'command' => 'test:run --foo=baz buzz', 'message' => 'An error occurred'))
3536
;
3637

37-
$input = array(
38-
'name' => 'test:run',
39-
'--foo' => 'baz',
40-
'bar' => 'buzz'
41-
);
42-
43-
$listener->onKernelException($this->getConsoleExceptionEvent($exception, $input, 1));
38+
$listener = new ExceptionListener($logger);
39+
$listener->onConsoleException($this->getConsoleExceptionEvent($exception, new ArgvInput(array('console.php', 'test:run', '--foo=baz', 'buzz')), 1));
4440
}
4541

46-
public function testOnKernelTerminateForNonZeroExitCodeWritesToLog()
42+
public function testOnConsoleTerminateForNonZeroExitCodeWritesToLog()
4743
{
4844
$logger = $this->getLogger();
49-
$listener = new ExceptionListener($logger);
50-
5145
$logger
5246
->expects($this->once())
5347
->method('error')
54-
->with('Command "{command}" exited with status code "{code}"', array('command' => '\'test:run\'', 'code' => 255))
48+
->with('Command "{command}" exited with code "{code}"', array('command' => 'test:run', 'code' => 255))
5549
;
5650

57-
$listener->onKernelTerminate($this->getConsoleTerminateEvent(array('name' => 'test:run'), 255));
51+
$listener = new ExceptionListener($logger);
52+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArgvInput(array('console.php', 'test:run')), 255));
5853
}
5954

60-
public function testOnKernelTerminateForZeroExitCodeDoesNotWriteToLog()
55+
public function testOnConsoleTerminateForZeroExitCodeDoesNotWriteToLog()
6156
{
6257
$logger = $this->getLogger();
63-
$listener = new ExceptionListener($logger);
64-
6558
$logger
6659
->expects($this->never())
6760
->method('error')
6861
;
6962

70-
$listener->onKernelTerminate($this->getConsoleTerminateEvent(array('name' => 'test:run'), 0));
63+
$listener = new ExceptionListener($logger);
64+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArgvInput(array('console.php', 'test:run')), 0));
7165
}
7266

7367
public function testGetSubscribedEvents()
7468
{
7569
$this->assertEquals(
7670
array(
77-
'console.exception' => array('onKernelException', -128),
78-
'console.terminate' => array('onKernelTerminate', -128),
71+
'console.exception' => array('onConsoleException', -128),
72+
'console.terminate' => array('onConsoleTerminate', -128),
7973
),
8074
ExceptionListener::getSubscribedEvents()
8175
);
8276
}
8377

78+
public function testAllKindsOfInputCanBeLogged()
79+
{
80+
$logger = $this->getLogger();
81+
$logger
82+
->expects($this->exactly(3))
83+
->method('error')
84+
->with('Command "{command}" exited with code "{code}"', array('command' => 'test:run --foo=bar', 'code' => 255))
85+
;
86+
87+
$listener = new ExceptionListener($logger);
88+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArgvInput(array('console.php', 'test:run', '--foo=bar')), 255));
89+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArrayInput(array('name' => 'test:run', '--foo' => 'bar')), 255));
90+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new StringInput('test:run --foo=bar'), 255));
91+
}
92+
93+
public function testCommandNameIsDisplayedForNonStringableInput()
94+
{
95+
$logger = $this->getLogger();
96+
$logger
97+
->expects($this->once())
98+
->method('error')
99+
->with('Command "{command}" exited with code "{code}"', array('command' => 'test:run', 'code' => 255))
100+
;
101+
102+
$listener = new ExceptionListener($logger);
103+
$listener->onConsoleTerminate($this->getConsoleTerminateEvent( $this->getMockBuilder(InputInterface::class)->getMock(), 255));
104+
}
105+
84106
private function getLogger()
85107
{
86108
return $this->getMockForAbstractClass(LoggerInterface::class);
87109
}
88110

89-
private function getConsoleExceptionEvent(\Exception $exception, $input, $exitCode)
111+
private function getConsoleExceptionEvent(\Exception $exception, InputInterface $input, $exitCode)
112+
{
113+
return new ConsoleExceptionEvent(new Command('test:run'), $input, $this->getOutput(), $exception, $exitCode);
114+
}
115+
116+
private function getConsoleTerminateEvent(InputInterface $input, $exitCode)
90117
{
91-
return new ConsoleExceptionEvent(new Command('test:run'), new ArrayInput($input), new TestOutput(), $exception, $exitCode);
118+
return new ConsoleTerminateEvent(new Command('test:run'), $input, $this->getOutput(), $exitCode);
92119
}
93120

94-
private function getConsoleTerminateEvent($input, $exitCode)
121+
private function getOutput()
95122
{
96-
return new ConsoleTerminateEvent(new Command('test:run'), new ArrayInput($input), new TestOutput(), $exitCode);
123+
return $this->getMockBuilder(OutputInterface::class)->getMock();
97124
}
98125
}

src/Symfony/Component/Console/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"psr/log": "~1.0"
2828
},
2929
"suggest": {
30-
"symfony/event-dispatcher": "",
30+
"symfony/event-dispatcher": "For using the console events and exception listener",
3131
"symfony/filesystem": "",
3232
"symfony/process": "",
3333
"psr/log": "For using the console logger"

0 commit comments

Comments
 (0)
0