加载 Doctrine 固定装置时如何在控制台中禁用查询日志记录?

Posted

技术标签:

【中文标题】加载 Doctrine 固定装置时如何在控制台中禁用查询日志记录?【英文标题】:How to disable query logging in console while load Doctrine fixtures? 【发布时间】:2016-02-04 03:51:50 【问题描述】:

我有一个加载大量数据的固定装置,并且一直遇到这个错误:

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

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

经过一番研究后,我发现this 帖子中我读到日志记录可能是导致问题的原因,因为AppKernel 被实例化,默认情况下调试设置为 true,然后每次迭代的 SQL 命令都存储在内存中.

AppKernel 不禁用调试的第一次尝试是运行以下命令:

doctrine:fixtures:load --no-debug

但我没有运气,因为同样的错误仍然存​​在。

第二次尝试是在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"]

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

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();
    

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

$em->getConnection()->getConfiguration()->setSQLLogger(null);

【问题讨论】:

也许可以创建自己的命令,关闭日志记录,然后运行内置的fixtures 命令。看看 Doctrine/Bundle/FixturesBundle/Command/LoadDataFixturesDoctrineCommand.php。您可能可以对其进行子类化并更改命令名称,并将您的日志记录行添加到 execute()。 实体管理器被传递到加载方法中。你不能用那个吗? how to stop doctrine to log queries 或 Memory leaks Symfony2 Doctrine2 / exceed memory limit 的可能重复 @qooplmao load() 方法中的EntityManager 在哪里? $managerDoctrine\Common\Persistence\ObjectManager 的类型,并且该类无法将 SQLLogger 设置为 null,您能解释一下您的建议吗? ... 用于缩短声明。如您现在所见,经理是Doctrine\ORM\EntityManager,这意味着它是实体经理(您的问题中为$em),因此您可以使用$manager-&gt;getConnection()-&gt;getConfiguration()-&gt;setSQLLogger(null); 【参考方案1】:

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

这意味着您可以使用与您的问题相同的命令来取消 SQL 记录器,例如..

$manager->getConnection()->getConfiguration()->setSQLLogger(null);

需要注意的是,DBAL 连接的默认日志记录设置是%kernel.debug%,这意味着除非您在配置中覆盖它,否则日志记录应该只发生在dev 环境中。我可以看到您已尝试使用 --no-debug 选项,但我只能假设,由于记录器设置为 during the container compilation,它不会将其取消设置为未重建的容器。


测试用例中的 Symfony 3/4/5 方法

final class SomeTestCase extends KernelTestCase

    protected function setUp(): void
    
        $this->bootKernel('...');

        // @see https://***.com/a/35222045/1348344
        // disable Doctrine logs in tests output
        $entityManager = self::$container->get(EntityManagerInterface::class);
        $entityManager->getConfiguration();
        $connection = $entityManager->getConnection();

        /** @var Configuration $configuration */
        $configuration = $connection->getConfiguration();
        $configuration->setSQLLogger(null);
    

【讨论】:

【参考方案2】:

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


禁用 Doctrine 日志通道

(在您的注释代码中)

monolog:
    handlers:
        main:
            type:   stream
            path:   "%kernel.logs_dir%/%kernel.environment%.log"
            level:  debug
            channels: ["!doctrine"]    # "!event", "!php"

设置自定义虚拟记录器

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

doctrine.dbal.logger:
        class: App\ORM\Doctrine\DBAL\Logging\DummysqlLogger

并在doctrine.yaml 中启用它:

doctrine:
    dbal:
        driver: 'pdo_mysql'
        logging: true

自定义记录器必须实现接口Doctrine\DBAL\Logging\SQLLogger。具体方法startQuerystopQuery可以留空,跳过日志;或者只使用error_log 代替(就像我的情况一样)。


我不确定这是否会防止内存溢出问题。最终增加PHP_MEMORY_LIMIT(如果您的环境支持,则通过环境变量,或通过ini_set())。

【讨论】:

以上是关于加载 Doctrine 固定装置时如何在控制台中禁用查询日志记录?的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 3.3 Doctrine Fixtures 加载跳过 SQL 视图

Symfony 4 - 加载动态用户角色的固定装置

如何从 Play 框架中的 YAML 固定装置加载(静态嵌套)枚举值?

Doctrine(Symfony) 加载夹具,参考不存在

Symfony 固定装置和多对多关系(学说)

Symfony 学说数据加载分段错误