【问题标题】:Send email when error occurs in console command of Symfony2 appSymfony2 应用程序的控制台命令发生错误时发送电子邮件
【发布时间】:2013-11-23 13:42:04
【问题描述】:

当控制台命令出现问题时,如何发送带有日志的电子邮件?目前我已经将我的应用程序配置为从 Web 界面发送电子邮件并且它可以正常工作。 Swiftmailer 假脱机已禁用。我的配置是:

monolog:
    handlers:
        main:
            type:         fingers_crossed
            action_level: critical
            handler:      grouped
        grouped:
            type:    group
            members: [streamed, buffered]
        streamed:
            type:  stream
            path:  "%kernel.logs_dir%/%kernel.environment%.log"
            level: debug
        buffered:
            type:    buffer
            handler: swift
        swift:
            type:       swift_mailer
            from_email: info@site.com
            to_email:   username@site.com
            subject:    An Error Occurred!
            level:      debug

当我尝试执行php app/console test:exception-command -e prod 时抛出异常,没有电子邮件发送。

【问题讨论】:

    标签: symfony command-line-interface monolog


    【解决方案1】:

    我遇到了同样的问题,经过几次尝试,我得到了解决方案。 问题是 swiftmailer 中的 spool,它被配置为内存,所以我将其更改为文件

    # app/config/config.yml
    swiftmailer:
        transport: %mailer_transport%
        username:  %mailer_user%
        password:  %mailer_password%
        spool:
            type: file
            path: "%kernel.root_dir%/spool"
    

    然后我在命令中调用了记录器

    $this->logger = $this->getContainer()->get('logger');
    $this->logger->critical('commands');
    

    在命令之后,我调用了 swiftmailer 命令来发送待处理的电子邮件

    app/console swiftmailer:spool:send --env=prod
    

    【讨论】:

      【解决方案2】:

      它应该在您的 swiftmailer 配置中禁用假脱机发送电子邮件,这应该会导致电子邮件立即发送而不是假脱机并且您的命令使用记录器。

      如果您想使用内存假脱机,您可以在命令的执行方法中刷新队列。

      /**
       * force emails to be sent out at the end of execute
       */
      protected function execute(InputInterface $input, OutputInterface $output)
      {
          $container = $this->getContainer();
          $logger = $container->get('logger');
          $logger->critical('My Critical Error Message');
      
          $mailer = $container->get('mailer');
          $spool = $mailer->getTransport()->getSpool();
          $transport = $container->get('swiftmailer.transport.real');
          $spool->flushQueue($transport);
      }
      

      参考:http://symfony.com/doc/current/cookbook/console/sending_emails.html#using-memory-spooling

      如果您想记录未捕获的异常,则必须配置控制台事件以使用记录器。

      http://symfony.com/doc/current/cookbook/console/logging.html#enabling-automatic-exceptions-logging

      【讨论】:

        【解决方案3】:

        对于 Symfony

        还有另一种可能,覆盖应用程序类,下面的类可以帮助, 此应用程序类为控制台激活记录器并记录自动存在

        //Acme/LoggingBundle/Console/Application.php
            <?php
        
            namespace Acme\LoggingBundle\Console;
        
            use Symfony\Bundle\FrameworkBundle\Console\Application as BaseApplication;
            use Symfony\Component\Console\Input\InputInterface;
            use Symfony\Component\Console\Output\OutputInterface;
            use Symfony\Component\Console\Output\ConsoleOutputInterface;
            use Symfony\Component\DependencyInjection\IntrospectableContainerInterface;
            use Symfony\Component\HttpKernel\Log\LoggerInterface;
            use Symfony\Component\HttpKernel\KernelInterface;
            use Symfony\Component\Console\Output\ConsoleOutput;
            use Symfony\Component\Console\Input\ArgvInput;
        
            class Application extends BaseApplication
            {
                private $originalAutoExit;
        
                public function __construct(KernelInterface $kernel)
                {
                    parent::__construct($kernel);
                    $this->originalAutoExit = true;
                }
        
                /**
                * Runs the current application.
                *
                * @param InputInterface  $input  An Input instance
                * @param OutputInterface $output An Output instance
                *
                * @return integer 0 if everything went fine, or an error code
                *
                * @throws \Exception When doRun returns Exception
                *
                * @api
                */
                public function run(InputInterface $input = null, OutputInterface $output = null)
                {
                    // make the parent method throw exceptions, so you can log it
                    $this->setCatchExceptions(false);
        
                    // store the autoExit value before resetting it - you'll need it later
                    $autoExit = $this->originalAutoExit;
                    $this->setAutoExit(false);
        
                    if (null === $input) {
                        $input = new ArgvInput();
                    }
        
                    if (null === $output) {
                        $output = new ConsoleOutput();
                    }
        
                    try {
                        $statusCode = parent::run($input, $output);
                    } catch (\Exception $e) {
        
                        /** @var $logger LoggerInterface */
                        $container = $this->getKernel()->getContainer();
                        $logger = null;
        
                        if($container instanceof IntrospectableContainerInterface){
                            $logger = $container->get('logger');
                        }
        
                        $message = sprintf(
                            '%s: %s (uncaught exception) at %s line %s while running console command `%s`',
                            get_class($e),
                            $e->getMessage(),
                            $e->getFile(),
                            $e->getLine(),
                            $this->getCommandName($input)
                        );
        
                        if($logger){
                            $logger->crit($message);
                        }
        
                        if ($output instanceof ConsoleOutputInterface) {
                            $this->renderException($e, $output->getErrorOutput());
                        } else {
                            $this->renderException($e, $output);
                        }
                        $statusCode = $e->getCode();
        
                        $statusCode = is_numeric($statusCode) && $statusCode ? $statusCode : 1;
                    }
        
                    if ($autoExit) {
                        if ($statusCode > 255) {
                            $statusCode = 255;
                        }
        
                        // log non-0 exit codes along with command name
                        if ($statusCode !== 0) {
        
                            /** @var $logger LoggerInterface */
                            $container = $this->getKernel()->getContainer();
                            $logger = null;
        
                            if($container instanceof IntrospectableContainerInterface){
                                $logger = $container->get('logger');
                            }
        
                            if($logger){
                                $logger->warn(sprintf('Command `%s` exited with status code %d', $this->getCommandName($input), $statusCode));
                            }
                        }
        
                        // @codeCoverageIgnoreStart
                        exit($statusCode);
                        // @codeCoverageIgnoreEnd
                    }
        
                    return $statusCode;
                }
        
                public function setAutoExit($bool)
                {
                    // parent property is private, so we need to intercept it in a setter
                    $this->originalAutoExit = (Boolean) $bool;
                    parent::setAutoExit($bool);
                }
        
            }
        

        然后在app/console中使用

        //use Symfony\Bundle\FrameworkBundle\Console\Application;
        use Acme\UltimateLoggingBundle\Console\Application;
        

        至少删除 app/cache/* 目录 app/console 缓存:清除还不够

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-11-28
          • 2012-09-15
          • 2013-11-24
          • 2013-09-22
          • 1970-01-01
          • 2012-08-14
          • 2015-05-07
          相关资源
          最近更新 更多