支付宝扫一扫付款
微信扫一扫付款
(微信为保护隐私,不显示你的昵称)
Console组件并不提供任何日志能力。一般来说,你要手动执行命令并观察输出,这就是为什么不提供日志了。然而,仍然会有一些场景你可能需要日志。例如,当你运行无人值守的命令行时,像是cron jobs或部署过的脚本,可能很自然地会使用Symfony自带的logging而不是配置其他工具来收集命令行的输出然后再处理它。如果你已经有一些“用于收集和分析Symfony日志”的现成的设置,(面对这种需求时)将会格外棘手。
基本上你需要两个日志场景:
这十分简单。当你使用的是完整版框架并按照 "Console Commands" 一文所描述的来创建命令时,这个command继承的是 ContainerAwareCommand
。这意味着你可以通过容器直接访问到标准的logger服务并用于做记录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | // src/AppBundle/Command/GreetCommand.php
namespace AppBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Psr\Log\LoggerInterface;
class GreetCommand extends ContainerAwareCommand
{
// ...
protected function execute(InputInterface $input, OutputInterface $output)
{
/** @var $logger LoggerInterface */
$logger = $this->getContainer()->get('logger');
$name = $input->getArgument('name');
if ($name) {
$text = 'Hello '.$name;
} else {
$text = 'Hello';
}
if ($input->getOption('yell')) {
$text = strtoupper($text);
$logger->warning('Yelled: '.$text);
} else {
$logger->info('Greeted: '.$text);
}
$output->writeln($text);
}
} |
根据你执行命令时所处的环境之不同 (也包括你的logging设置),你会在 var/logs/dev.log
或 var/logs/prod.log
文件中看到所记录的信息。
要让控制台程序为所有命令自动地记录下未捕获异常,你可以使用 console events。
首先在服务容器中,针对console exception事件配置一个监听:
1 2 3 4 5 6 7 | # app/config/services.yml
services:
app.listener.command_exception:
class: AppBundle\EventListener\ConsoleExceptionListener
arguments: ['@logger']
tags:
- { name: kernel.event_listener, event: console.exception } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | <!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="app.listener.command_exception" class="AppBundle\EventListener\ConsoleExceptionListener">
<argument type="service" id="logger"/>
<tag name="kernel.event_listener" event="console.exception" />
</service>
</services>
</container> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // app/config/services.php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
$definitionConsoleExceptionListener = new Definition(
'AppBundle\EventListener\ConsoleExceptionListener',
array(new Reference('logger'))
);
$definitionConsoleExceptionListener->addTag(
'kernel.event_listener',
array('event' => 'console.exception')
);
$container->setDefinition(
'app.listener.command_exception',
$definitionConsoleExceptionListener
); |
然后去实现真正的监听类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | // src/AppBundle/EventListener/ConsoleExceptionListener.php
namespace AppBundle\EventListener;
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
use Psr\Log\LoggerInterface;
class ConsoleExceptionListener
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function onConsoleException(ConsoleExceptionEvent $event)
{
$command = $event->getCommand();
$exception = $event->getException();
$message = sprintf(
'%s: %s (uncaught exception) at %s line %s while running console command `%s`',
get_class($exception),
$exception->getMessage(),
$exception->getFile(),
$exception->getLine(),
$command->getName()
);
$this->logger->error($message, array('exception' => $exception));
}
} |
在上述代码中,当任何一个命令抛出异常时,监听都会收到一个事件。通过从服务配置中传进来的logger服务,你可以把它直接记录下来。你的方法接收一个 ConsoleExceptionEvent
对象,里面有可以获取到事件和异常等相关信息的方法。
通过记录non-0 exit status,可以进一步扩展命令行的日志能力。当一个命令出现错误时,哪怕没有异常抛出,你就要用到此种方式。
先在服务容器中,为console terminate事件配置一个监听:
1 2 3 4 5 6 7 | # app/config/services.yml
services:
app.listener.command_error:
class: AppBundle\EventListener\ErrorLoggerListener
arguments: ['@logger']
tags:
- { name: kernel.event_listener, event: console.terminate } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | <!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="app.listener.command_error" class="AppBundle\EventListener\ErrorLoggerListener">
<argument type="service" id="logger"/>
<tag name="kernel.event_listener" event="console.terminate" />
</service>
</services>
</container> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // app/config/services.php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
$definitionErrorLoggerListener = new Definition(
'AppBundle\EventListener\ErrorLoggerListener',
array(new Reference('logger'))
);
$definitionErrorLoggerListener->addTag(
'kernel.event_listener',
array('event' => 'console.terminate')
);
$container->setDefinition(
'app.listener.command_error',
$definitionErrorLoggerListener
); |
然后去实现真正的监听类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | // src/AppBundle/EventListener/ErrorLoggerListener.php
namespace AppBundle\EventListener;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Psr\Log\LoggerInterface;
class ErrorLoggerListener
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function onConsoleTerminate(ConsoleTerminateEvent $event)
{
$statusCode = $event->getExitCode();
$command = $event->getCommand();
if ($statusCode === 0) {
return;
}
if ($statusCode > 255) {
$statusCode = 255;
$event->setExitCode($statusCode);
}
$this->logger->warning(sprintf(
'Command `%s` exited with status code %d',
$command->getName(),
$statusCode
));
}
} |
本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。