4

当控制台命令出现问题时,如何发送带有日志的电子邮件?目前我已经将我的应用程序配置为从 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哪个抛出异常时,没有电子邮件发送。

4

3 回答 3

1

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

# 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
于 2013-11-27T16:44:22.247 回答
1

它应该在您的 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

于 2014-06-27T17:45:26.813 回答
0

对于 Symfony < 2.3

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

//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 cache:clear 还不够

于 2014-06-02T09:01:43.170 回答