Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disabling logs when Handling log (infinite loop) #410

Open
c-lambert opened this issue Jun 4, 2021 · 7 comments
Open

Disabling logs when Handling log (infinite loop) #410

c-lambert opened this issue Jun 4, 2021 · 7 comments

Comments

@c-lambert
Copy link

Hello,

i have to handle log and use some tools like messenger system, doctrine, etc.
When i handle log with an handler, it produce log (through messenger, doctrine, etc.), and go in an infinite loop.

Put conditions on channel or other parameters doesn't work because i want to send messenger, doctrine log of my main application to my jobqueue.

I just want to disable all log launch by my Handler, or set a configuration to my logger to know when it comes.

Thank you for your help.

@dbrumann
Copy link
Contributor

dbrumann commented Jun 6, 2021

Sorry, but I don't understand what is causing your problem. Are you using a custom handler? Can you maybe build a small reproducer or maybe show the config that is causing you problems?

@c-lambert
Copy link
Author

c-lambert commented Jun 11, 2021

Hello,
It's more a Monlog usage question.

When you create a custom handler, if you use component from Symfony to handling logs, it generate log inside the Custom Handler.
When you handle log generating by the Custom Handler, it generate another log, witch is handling by Custom Handler...

When you use Symfony component, i'm not able to disable logging from it or force a specific channel, to prevent infinite log loop.

Here is a basic example :

<?php

use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;
use Symfony\Component\Messenger\MessageBusInterface;

class MyCustomLoggerHandler extends AbstractProcessingHandler
{
    private ?MessageBusInterface $messageBus;

    public function __construct(
        $level = Logger::DEBUG,
        bool $bubble = true,
        MessageBusInterface $messageBus = null
    ) {
        parent::__construct($level, $bubble);
        $this->messageBus = $messageBus;
    }

    protected function write(array $record): void
    {
        try {
            $logMessage = new App\Message\($record);
            //....///
            $this->messageBus->dispatch($logMessage); // Generate new logs
        } catch(\Exception $e) {
            
        }
    }

}

@sustmi
Copy link

sustmi commented Mar 31, 2022

I guess I ran into a similar problem but when logging Doctrine queries.

In debug mode, Symfony uses Symfony\Bridge\Doctrine\Logger\DbalLogger->startQuery() to log each SQL query before it is executed.

We have custom Monolog Processor in our application that adds details about current request into each log record (including request attributes). When the request attributes contain an entity that is not loaded from database yet (thanks to lazy loading), Doctrine runs a query to fetch the entity (because the entity is JsonSerializable and \Monolog\Formatter\NormalizerFormatter::normalize() calls jsonSerialize() on the entity). But before the entity is fetched, the SQL query used to fetch the entity gets logged first. And again, request details (containing the still not loaded entity) are added to the log message. And here comes the infinite loop.

The problem is that the logging is done before the entity is fetched to Doctrine's identity map.

I guess that it could be solved if we can somehow disable logging when we are already inside logger. Yes, the SQL queries executed from inside of the logger will not be logged but I guess this is acceptable since we mainly care about SQL queries executed by the production code of the application (and not the logging code).

I already spent many hours debugging this issue so I need some time to process this. I will get back here when I realize how to handle this.

@sustmi
Copy link

sustmi commented Mar 31, 2022

Currently, I have the following workaround that infinite (recursive) loop problem.

I created a custom Logger class:

use Symfony\Bridge\Monolog\Logger;

class LoggerIgnoringNestedLogging extends Logger
{
    private bool $isNested = false;

    public function addRecord(int $level, string $message, array $context = []): bool
    {
        if ($this->isNested) {
            return false; // TODO: Or true? Should the record be considered processed?
        }

        $this->isNested = true;
        $returnValue = parent::addRecord($level, $message, $context);
        $this->isNested = false;

        return $returnValue;
    }
}

and registered it in services.yml like this:

services:
    # Use custom class for Monolog loggers
    monolog.logger_prototype:
        class: FrontBundle\Service\LoggerIgnoringNestedLogging
        arguments:
            - ~ # it is necessary to specify some arguments in this prototype service so that they can be replaced later

@stof
Copy link
Member

stof commented Apr 1, 2022

@sustmi I suggest that you don't register your custom processor in the doctrine channel.

@c-lambert
Copy link
Author

c-lambert commented Apr 1, 2022

@sustmi I suggest that you don't register your custom processor in the doctrine channel.

Doctrine component use doctrine channel. We cannot change that.

@mustanggb
Copy link

Any suggestions on how to do this without extending Logger, since it got marked as final?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants