Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commit1e84cb0

Browse files
tvlooyweaverryan
authored andcommitted
Rewrite docs
1 parent34eceb1 commit1e84cb0

File tree

1 file changed

+180
-155
lines changed

1 file changed

+180
-155
lines changed

‎cookbook/console/logging.rst

Lines changed: 180 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ container and use it to do the logging::
3434
use Symfony\Component\Console\Input\InputInterface;
3535
use Symfony\Component\Console\Input\InputOption;
3636
use Symfony\Component\Console\Output\OutputInterface;
37-
useSymfony\Component\HttpKernel\Log\LoggerInterface;
37+
use\Psr\Log\LoggerInterface;
3838

3939
class GreetCommand extends ContainerAwareCommand
4040
{
@@ -54,7 +54,7 @@ container and use it to do the logging::
5454

5555
if ($input->getOption('yell')) {
5656
$text = strtoupper($text);
57-
$logger->warn('Yelled: '.$text);
57+
$logger->warning('Yelled: '.$text);
5858
} else {
5959
$logger->info('Greeted: '.$text);
6060
}
@@ -69,146 +69,108 @@ setup), you should see the logged entries in ``app/logs/dev.log`` or ``app/logs/
6969
Enabling automatic Exceptions logging
7070
-------------------------------------
7171

72-
To get your console application to automatically log uncaught exceptions
73-
for all of your commands, you'll need to do a little bit more work.
74-
75-
First, create a new sub-class of:class:`Symfony\\Bundle\\FrameworkBundle\\Console\\Application`
76-
and override its:method:`Symfony\\Bundle\\FrameworkBundle\\Console\\Application::run`
77-
method, where exception handling should happen:
78-
79-
..caution::
80-
81-
Due to the nature of the core:class:`Symfony\\Component\\Console\\Application`
82-
class, much of the:method:`run <Symfony\\Bundle\\FrameworkBundle\\Console\\Application::run>`
83-
method has to be duplicated and even a private property ``originalAutoExit``
84-
re-implemented. This serves as an example of what you *could* do in your
85-
code, though there is a high risk that something may break when upgrading
86-
to future versions of Symfony.
87-
88-
..code-block::php
89-
90-
// src/Acme/DemoBundle/Console/Application.php
91-
namespace Acme\DemoBundle\Console;
92-
93-
use Symfony\Bundle\FrameworkBundle\Console\Application as BaseApplication;
94-
use Symfony\Component\Console\Input\InputInterface;
95-
use Symfony\Component\Console\Output\OutputInterface;
96-
use Symfony\Component\Console\Output\ConsoleOutputInterface;
97-
use Symfony\Component\HttpKernel\Log\LoggerInterface;
98-
use Symfony\Component\HttpKernel\KernelInterface;
99-
use Symfony\Component\Console\Output\ConsoleOutput;
100-
use Symfony\Component\Console\Input\ArgvInput;
101-
102-
class Application extends BaseApplication
72+
To get your console application to automatically log uncaught exceptions for
73+
all of your commands, you can use:doc:`console events</components/console/events>`.
74+
75+
..versionadded::2.3
76+
Console events were added in Symfony 2.3.
77+
78+
First configure a listener for console exception events in the service container:
79+
80+
..configuration-block::
81+
82+
..code-block::yaml
83+
84+
# app/config/services.yml
85+
services:
86+
kernel.listener.command_dispatch:
87+
class:Acme\DemoBundle\EventListener\ConsoleExceptionListener
88+
arguments:
89+
logger:"@logger"
90+
tags:
91+
-{ name: kernel.event_listener, event: console.exception }
92+
93+
..code-block::xml
94+
95+
<!-- app/config/services.xml-->
96+
<?xml version="1.0" encoding="UTF-8" ?>
97+
<containerxmlns="http://symfony.com/schema/dic/services"
98+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
99+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
100+
101+
<parameters>
102+
<parameterkey="console_exception_listener.class">Acme\DemoBundle\EventListener\ConsoleExceptionListener</parameter>
103+
</parameters>
104+
105+
<services>
106+
<serviceid="kernel.listener.command_dispatch"class="%console_exception_listener.class%">
107+
<argumenttype="service"id="logger"/>
108+
<tagname="kernel.event_listener"event="console.exception" />
109+
</service>
110+
</services>
111+
</container>
112+
113+
..code-block::php
114+
115+
// app/config/services.php
116+
use Symfony\Component\DependencyInjection\Definition;
117+
use Symfony\Component\DependencyInjection\Reference;
118+
119+
$container->setParameter(
120+
'console_exception_listener.class',
121+
'Acme\DemoBundle\EventListener\ConsoleExceptionListener'
122+
);
123+
$definitionConsoleExceptionListener = new Definition(
124+
'%console_exception_listener.class%',
125+
array(new Reference('logger'))
126+
);
127+
$definitionConsoleExceptionListener->addTag(
128+
'kernel.event_listener',
129+
array('event' => 'console.exception')
130+
);
131+
$container->setDefinition(
132+
'kernel.listener.command_dispatch',
133+
$definitionConsoleExceptionListener
134+
);
135+
136+
Then implement the actual listener::
137+
138+
// src/Acme/DemoBundle/EventListener/ConsoleExceptionListener.php
139+
namespace Acme\DemoBundle\EventListener;
140+
141+
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
142+
use \Psr\Log\LoggerInterface;
143+
144+
class ConsoleExceptionListener
103145
{
104-
private $originalAutoExit;
146+
/** @var $logger LoggerInterface */
147+
private $logger;
105148

106-
public function __construct(KernelInterface $kernel)
149+
public function __construct(LoggerInterface $logger)
107150
{
108-
parent::__construct($kernel);
109-
$this->originalAutoExit = true;
151+
$this->logger = $logger;
110152
}
111153

112-
/**
113-
* Runs the current application.
114-
*
115-
* @param InputInterface $input An Input instance
116-
* @param OutputInterface $output An Output instance
117-
*
118-
* @return integer 0 if everything went fine, or an error code
119-
*
120-
* @throws \Exception When doRun returns Exception
121-
*
122-
* @api
123-
*/
124-
public function run(InputInterface $input = null, OutputInterface $output = null)
125-
{
126-
// make the parent method throw exceptions, so you can log it
127-
$this->setCatchExceptions(false);
128-
129-
if (null === $input) {
130-
$input = new ArgvInput();
131-
}
132-
133-
if (null === $output) {
134-
$output = new ConsoleOutput();
135-
}
136-
137-
try {
138-
$statusCode = parent::run($input, $output);
139-
} catch (\Exception $e) {
140-
141-
/** @var $logger LoggerInterface */
142-
$logger = $this->getKernel()->getContainer()->get('logger');
143-
144-
$message = sprintf(
145-
'%s: %s (uncaught exception) at %s line %s while running console command `%s`',
146-
get_class($e),
147-
$e->getMessage(),
148-
$e->getFile(),
149-
$e->getLine(),
150-
$this->getCommandName($input)
151-
);
152-
$logger->crit($message);
153-
154-
if ($output instanceof ConsoleOutputInterface) {
155-
$this->renderException($e, $output->getErrorOutput());
156-
} else {
157-
$this->renderException($e, $output);
158-
}
159-
$statusCode = $e->getCode();
160-
161-
$statusCode = is_numeric($statusCode) && $statusCode ? $statusCode : 1;
162-
}
163-
164-
if ($this->originalAutoExit) {
165-
if ($statusCode > 255) {
166-
$statusCode = 255;
167-
}
168-
// @codeCoverageIgnoreStart
169-
exit($statusCode);
170-
// @codeCoverageIgnoreEnd
171-
}
154+
public function onConsoleException(ConsoleExceptionEvent $event) {
155+
$command = $event->getCommand();
156+
$exception = $event->getException();
172157

173-
return $statusCode;
174-
}
158+
$message = sprintf(
159+
'%s: %s (uncaught exception) at %s line %s while running console command `%s`',
160+
get_class($exception),
161+
$exception->getMessage(),
162+
$exception->getFile(),
163+
$exception->getLine(),
164+
$command->getName()
165+
);
175166

176-
public function setAutoExit($bool)
177-
{
178-
// parent property is private, so we need to intercept it in a setter
179-
$this->originalAutoExit = (Boolean) $bool;
180-
parent::setAutoExit($bool);
167+
$this->logger->error($message);
181168
}
182-
183169
}
184170

185-
In the code above, you disable exception catching so the parent ``run`` method
186-
will throw all exceptions. When an exception is caught, you simply log it by
187-
accessing the ``logger`` service from the service container and then handle
188-
the rest of the logic in the same way that the parent ``run`` method does
189-
(specifically, since the parent:method:`run <Symfony\\Bundle\\FrameworkBundle\\Console\\Application::run>`
190-
method will not handle exceptions rendering and status code handling when
191-
``catchExceptions`` is set to false, it has to be done in the overridden
192-
method).
193-
194-
For the extended ``Application`` class to work properly with in console shell mode,
195-
you have to do a small trick to intercept the ``autoExit`` setter and store the
196-
setting in a different property, since the parent property is private.
197-
198-
Now to be able to use your extended ``Application`` class you need to adjust
199-
the ``app/console`` script to use the new class instead of the default::
200-
201-
// app/console
202-
203-
// ...
204-
// replace the following line:
205-
// use Symfony\Bundle\FrameworkBundle\Console\Application;
206-
use Acme\DemoBundle\Console\Application;
207-
208-
// ...
209-
210-
That's it! Thanks to autoloader, your class will now be used instead of original
211-
one.
171+
In the code above, when a command throws an exception, the listener will
172+
receive an event. You can simply log it by passing the logger service via the
173+
service configuration.
212174

213175
Logging non-0 exit statuses
214176
---------------------------
@@ -217,36 +179,99 @@ The logging capabilities of the console can be further extended by logging
217179
non-0 exit statuses. This way you will know if a command had any errors, even
218180
if no exceptions were thrown.
219181

220-
In order to do that, you'd have to modify the ``run()`` method of your extended
221-
``Application`` class in the following way::
222-
223-
public function run(InputInterface $input = null, OutputInterface $output = null)
182+
First configure a listener for console terminate events in the service container:
183+
184+
..configuration-block::
185+
186+
..code-block::yaml
187+
188+
# app/config/services.yml
189+
services:
190+
kernel.listener.command_dispatch:
191+
class:Acme\DemoBundle\EventListener\ConsoleTerminateListener
192+
arguments:
193+
logger:"@logger"
194+
tags:
195+
-{ name: kernel.event_listener, event: console.terminate }
196+
197+
..code-block::xml
198+
199+
<!-- app/config/services.xml-->
200+
<?xml version="1.0" encoding="UTF-8" ?>
201+
<containerxmlns="http://symfony.com/schema/dic/services"
202+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
203+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
204+
205+
<parameters>
206+
<parameterkey="console_terminate_listener.class">Acme\DemoBundle\EventListener\ConsoleExceptionListener</parameter>
207+
</parameters>
208+
209+
<services>
210+
<serviceid="kernel.listener.command_dispatch"class="%console_terminate_listener.class%">
211+
<argumenttype="service"id="logger"/>
212+
<tagname="kernel.event_listener"event="console.terminate" />
213+
</service>
214+
</services>
215+
</container>
216+
217+
..code-block::php
218+
219+
// app/config/services.php
220+
use Symfony\Component\DependencyInjection\Definition;
221+
use Symfony\Component\DependencyInjection\Reference;
222+
223+
$container->setParameter(
224+
'console_terminate_listener.class',
225+
'Acme\DemoBundle\EventListener\ConsoleExceptionListener'
226+
);
227+
$definitionConsoleExceptionListener = new Definition(
228+
'%console_terminate_listener.class%',
229+
array(new Reference('logger'))
230+
);
231+
$definitionConsoleExceptionListener->addTag(
232+
'kernel.event_listener',
233+
array('event' => 'console.terminate')
234+
);
235+
$container->setDefinition(
236+
'kernel.listener.command_dispatch',
237+
$definitionConsoleExceptionListener
238+
);
239+
240+
Then implement the actual listener::
241+
242+
// src/Acme/DemoBundle/EventListener/ConsoleExceptionListener.php
243+
namespace Acme/DemoBundle\EventListener;
244+
245+
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
246+
use \Psr\Log\LoggerInterface;
247+
248+
class ConsoleTerminateListener
224249
{
225-
// make the parent method throw exceptions, so you can log it
226-
$this->setCatchExceptions(false);
250+
/** @var $logger LoggerInterface */
251+
private $logger;
227252

228-
// store the autoExit value before resetting it - you'll need it later
229-
$autoExit = $this->originalAutoExit;
230-
$this->setAutoExit(false);
253+
public function __construct(LoggerInterface $logger)
254+
{
255+
$this->logger = $logger;
256+
}
231257

232-
// ...
258+
public function onConsoleTerminate(ConsoleTerminateEvent $event) {
259+
$statusCode = $event->getExitCode();
260+
$command = $event->getCommand();
233261

234-
if ($autoExit) {
235-
if ($statusCode > 255) {
236-
$statusCode = 255;
262+
if ($statusCode === 0) {
263+
return;
237264
}
238265

239-
// log non-0 exit codes along with command name
240-
if ($statusCode !== 0) {
241-
/** @var $logger LoggerInterface */
242-
$logger = $this->getKernel()->getContainer()->get('logger');
243-
$logger->warn(sprintf('Command `%s` exited with status code %d', $this->getCommandName($input), $statusCode));
266+
if ($statusCode > 255) {
267+
$statusCode = 255;
268+
$event->setExitCode($statusCode);
244269
}
245270

246-
// @codeCoverageIgnoreStart
247-
exit($statusCode);
248-
// @codeCoverageIgnoreEnd
271+
$this->logger->warning(sprintf(
272+
'Command `%s` exited with status code %d',
273+
$command->getName(),
274+
$statusCode
275+
));
249276
}
250-
251-
return $statusCode;
252277
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp