如何在加载Doctrine灯具时禁用控制台中的查询日志记录?

Rey*_*rPM 3 php doctrine symfony doctrine-orm

我有一个加载大量数据的灯具,并且我遇到这个错误的所有时间:

致命错误:第65行的/var/www/html/platform-cm/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/DebugStack.php中允许的内存大小为2147483648字节(尝试分配16777224字节)

[Symfony\Component\Debug\Exception\OutOfMemoryException]错误:允许的内存大小为2147483648字节耗尽(尝试分配16777224字节)

经过研究后,我发现这篇文章,我读到日志记录可能是问题的原因,因为AppKernel默认情况下将debug设置为true,然后SQL命令在每次迭代时都存储在内存中.

没有禁用调试的第一次尝试AppKernel是运行命令:

doctrine:fixtures:load --no-debug
Run Code Online (Sandbox Code Playgroud)

但是由于同样的错误,我也没有好运.

第二次尝试是禁用调试,config_dev.yml但不建议这样做,因为我正在获取每个日志,但两个都没有工作.

monolog:
    handlers:
        main:
            type:   stream
            path:   "%kernel.logs_dir%/%kernel.environment%.log"
            level:  debug
#        console:
#            type:   console
#            bubble: false
#            verbosity_levels:
#                VERBOSITY_VERBOSE: INFO
#                VERBOSITY_VERY_VERBOSE: DEBUG
#            channels: ["!doctrine"]
#        console_very_verbose:
#            type:   console
#            bubble: false
#            verbosity_levels:
#                VERBOSITY_VERBOSE: NOTICE
#                VERBOSITY_VERY_VERBOSE: NOTICE
#                VERBOSITY_DEBUG: DEBUG
#            channels: ["doctrine"]
Run Code Online (Sandbox Code Playgroud)

所以,这就是我的夹具的样子:

class LoadMsisdn extends AbstractFixture implements OrderedFixtureInterface
{
    public function getOrder()
    {
        return 13;
    }

    public function load(ObjectManager $manager)
    {
        $content = file_get_contents('number.txt');
        $numbers = explode(',', $content);
        shuffle($numbers);

        foreach ($numbers as $key => $number) {
            $msisdn = new Msisdn();
            $msisdn->setMsisdn($number);
            $msisdn->setBlocked((rand(1, 1000) % 10) < 7);
            $msisdn->setOperator($this->getReference('operator-' . rand(45, 47)));

            $this->addReference('msisdn-' . $key, $msisdn);
            $manager->persist($msisdn);
        }

        $manager->flush();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我需要EntityManager在同一帖子的答案中显示,如何禁用记录器?

$em->getConnection()->getConfiguration()->setSQLLogger(null);
Run Code Online (Sandbox Code Playgroud)

qoo*_*mao 8

传递给load方法的对象管理器是实体管理器的实例(Doctrine\Common\Persistence\ObjectManager只是实体/文档/等管理器实现的接口).

这意味着您可以使用与问题中相同的命令来使SQL记录器无效.

$manager->getConnection()->getConfiguration()->setSQLLogger(null);
Run Code Online (Sandbox Code Playgroud)

需要注意的一点是,DBAL连接的默认日志记录设置%kernel.debug%意味着,除非您在配置中覆盖它,否则日志记录应仅在dev环境中进行.我可以看到你已经尝试使用该--no-debug选项,但我只能假设,因为在容器编译期间设置了记录器,它不会将其取消设置为未重建的容器.


Kam*_*her 8

我不确定它是否有助于解决内存限制问题,但您也可以尝试通过 YAML 配置更改日志记录(更舒适):


禁用 Doctrine 日志通道

(如您评论的代码中所示)

monolog:
    handlers:
        main:
            type:   stream
            path:   "%kernel.logs_dir%/%kernel.environment%.log"
            level:  debug
            channels: ["!doctrine"]    # "!event", "!php"
Run Code Online (Sandbox Code Playgroud)

设置自定义虚拟记录器

设置services.yaml默认 Doctrine 记录器的类:

doctrine.dbal.logger:
        class: App\ORM\Doctrine\DBAL\Logging\DummySQLLogger
Run Code Online (Sandbox Code Playgroud)

并在以下位置启用它doctrine.yaml

doctrine:
    dbal:
        driver: 'pdo_mysql'
        logging: true
Run Code Online (Sandbox Code Playgroud)

自定义记录器必须实现该接口Doctrine\DBAL\Logging\SQLLogger。具体方法startQuery可以stopQuery留空,跳过日志记录;或者只是使用error_log(就像我的例子)。


我不确定这是否可以防止内存超出问题。最终增加PHP_MEMORY_LIMIT(如果您的环境支持,则通过 env 变量,或通过ini_set())。并注意使用正确的单位符号(M兆字节、G千兆字节),我经常把它写错为MB