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

[Console][ErrorHandler] Add option to disable deprecations in dev console in 4.4 #35575

Open
jkobus opened this issue Feb 3, 2020 · 70 comments

Comments

@jkobus
Copy link

jkobus commented Feb 3, 2020

Description
After running any command in dev (debug=1) I get a lot of messages in stdout like:

2020-02-03T16:37:57+01:00 [info] User Deprecated: The "Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand" class is deprecated since Symfony 4.2, use "Symfony\Component\Console\Command\Command" with dependency injection instead.

Console screen gets a bit messy.

That's very helpful but I don't need it every time I run a console command.
Right now the only workaround is to disable debug, because the error_reporting setting is ignored.

Previously (4.2) I just used an option in framework.yaml:

framework:
    php_errors:
        log: 4096

It was enough to get rid of those deprecations.

@jkobus jkobus changed the title [Console][ErrorHandler] Add option to disable depracations in dev console in 4.4 [Console][ErrorHandler] Add option to disable deprecations in dev console in 4.4 Feb 3, 2020
@pounard
Copy link
Contributor

pounard commented Mar 12, 2020

This burning our prods and sending it into hell, especially with messenger in conjunction with fingers_crossed handler which is broken (but that's another topic, rather difficult to solve topic, and I get that).

I did some forensics and found that in there:

https://github.com/symfony/symfony/blob/master/src/Symfony/Component/ErrorHandler/ErrorHandler.php#L411

i.e.:

        $level = error_reporting();
        $silenced = 0 === ($level & $type);
        // Strong errors are not authorized to be silenced.
        $level |= E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;

Strong errors are not authorized to be silenced

It's a matter of opinion, I don't see a deprecation notice as a strong error.

The error handler component refuses explicitly to honour our error reporting configuration, without any kind of valid argument.

Deprecations should not get into log into production.

@jkobus
Copy link
Author

jkobus commented Mar 12, 2020

@pounard, in production environment this problem should not appear.

This depends on the APP_DEBUG env variable, which should be 0 on production bu default.

bin/console:

if ($_SERVER['APP_DEBUG']) {
    umask(0000);

    if (class_exists(Debug::class)) {
        Debug::enable();
    }
}

In short, the problem appears - in my case, when using console like this:

php bin/console --env=dev // local development
APP_DEBUG=1 php bin/console --env=prod

@pounard
Copy link
Contributor

pounard commented Mar 12, 2020

Nope, because:

/**
 * Bundle.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class FrameworkBundle extends Bundle
{
    public function boot()
    {
        ErrorHandler::register(null, false)->throwAt($this->container->getParameter('debug.error_handler.throw_at'), true);

@pounard
Copy link
Contributor

pounard commented Mar 12, 2020

Or did we do something wrong ? But if I get that right, when the Framework bundle initializes itself, it registers the ErrorHandler::handleError() as a PHP error handler.

@jkobus
Copy link
Author

jkobus commented Mar 12, 2020

I'm on 4.4.4 now and my prod is "clean" from these logs. I'll take a closer look tomorrow, but you can test --no-debug flag - when using console all deprecations should be gone.

@pounard
Copy link
Contributor

pounard commented Mar 12, 2020

I'm using 4.4.1, may be this bug was fixed somehow ?

@pounard
Copy link
Contributor

pounard commented Mar 12, 2020

@jkobus are you logging everything 'till the info level, or using fingers_crossed ?

Because trigger_error('foo', E_USER_DEPRECATED) goes to the php channel, using the INFO level, if you setup your logs to the warning level, you won't get those, otherwise you will.

@pounard
Copy link
Contributor

pounard commented Mar 12, 2020

As a matter of fact I stumbled upon this: https://stackoverflow.com/a/35779541

I know it's for 2.7 (rather old version) but it seems to work here.

Nevertheless, I think the bug is real in Symfony 4.4.1 (at least) and probably until current latest stable.

@xabbuh
Copy link
Member

xabbuh commented Mar 15, 2020

@pounard Could you please create a small example application using the latest 4.4 patch release that allows to reproduce this?

@pounard
Copy link
Contributor

pounard commented Mar 18, 2020

I did a minimal installation that reproduces the bug, see https://github.com/pounard/symfony-issue-35575

  • installed using the symfony binary, standard minimal installation,
  • installed monolog using composer req monolog,
  • set the .env file with APP_ENV=prod,
  • added a custom config/packages/prod/monolog.yaml with a sane, production ready, configuration,
  • wrote a simple controller that always triggers a deprecation, then triggers a warning when a dedicated GET parameter is set.

Monolog config is the following:

monolog:
    handlers:
        main:
            type: fingers_crossed
            action_level: warning
            handler: nested
            buffer_size: 500
        nested:
            type: rotating_file
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            date_format: Y-m-d
            max_files: 30
            level: info

How to test by yourself:

  • git clone https://github.com/pounard/symfony-issue-35575.git,
  • cd symfony-issue-35575
  • (vim|nano|gedit|windows notepad|obscure apple app) .env and set APP_ENV=prod,
  • write your custom HTTPd configuration or install the dev web server,
  • go to http://symfony-issue-35575.local/triggers-deprecation/ by replacing symfony-issue-35575.local with whatever is your host,
  • watch out for logs in var/log.

Expected:

  • no matter if the warning is triggered or not, the deprecation notice should NEVER be caught in production logs.

Actual behaviour:

  • without the warning, nothing goes into the log,
  • with the warning, everything is logged, including the deprecation.

Once again, I repeat, this is because the ErrorHandler::handleError() method ignores the environment set log level, but E_USER_DEPRECATED PHP errors will have the INFO level, which makes them pass into the nested handler from my configuration.

@pounard
Copy link
Contributor

pounard commented Mar 18, 2020

That's with 5.0, I'm writing a 4.4 branch.

@pounard
Copy link
Contributor

pounard commented Mar 18, 2020

Using 4.4.5, use git clone https://github.com/pounard/symfony-issue-35575.git --branch=4.4

Even worse, I had to remove trigger_error('This is a notice', E_USER_NOTICE) because it wrongly woke up the fingers_crossed handler systematically, I think this is an additional bug. Let's ignore it for now.

Behaviour is still reproducible, deprecations goes to log.

@pounard
Copy link
Contributor

pounard commented Mar 18, 2020

I added error_reporting(E_ALL & ~E_USER_DEPRECATED); in public/index.php and the behaviour is still reproducible.

Fun thing, if I disable error_reporting completely, I have no logs at all, since it will not wake up the fingers_crossed handler. Yet while step-debugging, my deprecation notice is logged awaiting for the handler to wake up, but my warning gets ignored and never logged ! This is much worse than the having the deprecation pass. This means that in case of an exception, the exception will be logged, messages logged using the PSR logger will be logged, but PHP own errors and notices will be ignored, yet the deprecation will continue to be logged.

This is what I called a seriously inconsistent, unexpected and awkward behaviour.

@pounard
Copy link
Contributor

pounard commented Mar 18, 2020

To reproduce the very stupid behaviour from my previous comment, use git clone https://github.com/pounard/symfony-issue-35575.git --branch=having-fun-with-error-reporting

@pounard
Copy link
Contributor

pounard commented Mar 18, 2020

I sincerely think that this line:

// Strong errors are not authorized to be silenced.
$level |= E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;

In the ErrrorHandler::handleError() should just be removed. Please let developers and sysadmin configure their own environments, do not attempt to be smarter than them with this.

@nicolas-grekas
Copy link
Member

This line is correct: deprecations are always silenced already, see all the calls, they are like @error_reporting(), on purpose.

You should be able to route the deprecation channel to wherever you want, see e.g. the default config which routes them to a dedicated file:
https://github.com/symfony/recipes/blob/master/symfony/monolog-bundle/3.3/config/packages/prod/monolog.yaml

@pounard
Copy link
Contributor

pounard commented Mar 18, 2020

This line is correct: deprecations are always silenced already, see all the calls, they are like @error_reporting(), on purpose.

@nicolas-grekas then pull my work and test. It's not about being silenced, it's about going down to the log, there is no way to prevent deprecations to be emitted into the log handler if you accept the info level, and this is the bug.

EDIT: I think you misunderstood the topic of this issue.

@pounard
Copy link
Contributor

pounard commented Mar 18, 2020

You should be able to route the deprecation channel to wherever you want

Those deprecations, i.e. those triggered using trigger_error('Foo', E_USER_DEPRECATED) are in the php channel, not the deprecation channel.

@pounard
Copy link
Contributor

pounard commented Mar 18, 2020

OK, I admit, the original issue wasn't really about those, but that I may have hijacked it: the original issue author did point his/her finger on the same piece of code that trigger the actual behaviours I'm fighting against, so I guess that's the right place to discuss.

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Mar 18, 2020

I'm sorry also to highlight this but the tone is so stressful here that it's hard to get into anything constructive. "burning", "broken", "forensic", "refuses explicitly to honour", "without any kind of valid argument", "Once again, I repeat", "Even worse", "Fun thing", "This is much worse", "seriously inconsistent, unexpected and awkward behaviour.", "do not attempt to be smarter".

Please keep a cool head. All those words are needlessly dramatic and emotionally loaded. This is even worse when they claim something that happens to be wrong: the line that is yelled at is likely not related, since the error level is always zero for deprecations.

@pounard I did understand that you'd like to handle deprecations separately from other PHP notices, yet you wonder how to do so since right now the php channel mixes both at the info level. It looks like a feature request, nice one.

@jkobus I'm not sure anymore if @pounard's request would fix your case. Please tell if this is being hijacked or not from your pov :)

@pounard
Copy link
Contributor

pounard commented Mar 18, 2020

Don't take those words seriously, I honestly do not want any harm: I am very much appreciating all the hard work and all the time contributors give to this project.

I took the time to write a complete and concrete example with explanation, because I now that maintaining free (and any other kind of) software is hard and time consuming.

I do apologize if it hurt you, please believe me, I don't want any harm and I sincerely appreciate your work.

Now, let me explain:

  • burning is what happened to our logs, it's not your fault, it's a bad behaviour we stumbled upon because of our custom configuration,
  • broken is what it is: it does hijack our PHP directives and log configuration,
  • forensics is what I did: I opened my step debugger and I did an investigation, there is no criminal other than the code itself, you are not a criminal,
  • refuses explicitly to honour is what the code does,
  • without any kind of valid argument is real: the comment does not explain why,
  • this is much worse : it is, I mean it's a very odd additional behaviour I managed to reproduce involuntarily while investigating another one,
  • seriously inconsistent, unexpected and awkward behaviour: once again, it's what I think, because when you trigger off a warning, and it gets shut off, whereas a non consequential deprecation yells, it's weird, right ?

EDIT: "Fun thing" because it's fun :) I am amused when I debug, it's fun, it's what I do for a living and I love this, my job, it's a passion. Fun is fun, in the sens it is fun, not bad !

You, pretty much like me, are confined at home because of the current pandemic, and we all have our nerves on steel because of all of this. I think it might affect our judgement when we read this kind of issues. Most of my comments were before that, at least before drastic government actions.

Once again, I'm sorry if you took that wrong, I will try to be much more careful with my language. But I did not, ever, insult or point fingers at anyone, just an odd behaviour. I know that sometime, people do stumble upon edge cases (this time it was me) and that's what I discriminate, not you, never ever I will doubt about contributors themselves.

@jkobus
Copy link
Author

jkobus commented Mar 20, 2020

@nicolas-grekas I will take a look at it

@jkobus jkobus closed this as completed Mar 20, 2020
@jkobus jkobus reopened this Mar 20, 2020
@pounard
Copy link
Contributor

pounard commented Mar 20, 2020

@nicolas-grekas @jkobus I honestly think that the line I was pointing at a few comment above should be removed, I don't see any valid reason for the error handler to enforce E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED to be dispatched to loggers if the level was explicitly silenced by PHP configuration.

Was there a reason initially to force those to be verbose ? Maybe for testing environments ?

A compromise could be to just remove E_DEPRECATED | E_USER_DEPRECATED or give them a special treatment and enforce the channel to be "deprecated" ? What do you think ?

@nicolas-grekas
Copy link
Member

@pounard check

$this->thrownErrors = ($levels | E_RECOVERABLE_ERROR | E_USER_ERROR) & ~E_USER_DEPRECATED & ~E_DEPRECATED;
Please note also that: 1. E_RECOVERABLE_ERROR and E_USER_ERROR always stop execution and 2. E_USER_DEPRECATED are always silenced. This means 1. we must replace a silenced execution stop (=BIGWTF) by an exception and 2. we must forward deprecations to the logger (then, it's up to the logger to decide). 1. and 2. are thus both independent of the current error reporting level.

@pounard
Copy link
Contributor

pounard commented Mar 20, 2020

  1. E_USER_DEPRECATED are always silenced

So you mean by "silenced" that the PHP handler will not be run for those, took me a while to figure that one out. OK I get that.

Now, let's consider my use case, I did explicitly told PHP to ignore E_USER_DEPRECATED, why does Symfony still log that ? Would it just be possible to honour the PHP configuration and do nothing when those errors are silenced by error_level() configuration ? Just ignoring them ?

I did some step debugging, even thought they are "silenced" meaning PHP won't scream, they still reach that line of code:

$this->loggers[$type][0]->log($level, $logMessage, $errorAsException ? ['exception' => $errorAsException] : []);

So I attempted to decompose the code:

  • In __construct(), $levels is passed as null, so set to E_ALL,
  • then in configure() $handler->setDefaultLogger($this->logger, $this->levels); is called,
  • in setDefaultLogger() and setLogger() then it does a lot of black magic with levels, anyway I have a logger set for the deprecation levels before and after,
  • then when finally getting to handleError() I have a type, which is 16384 (i.e. E_USER_DEPRECATED),
  • then it checks for the PHP configuration by calling error_level() and decides to silence my error, since I disabled it ($silenced is set to true),
  • I did a slight modification, and rewrote the next line to $level |= E_RECOVERABLE_ERROR | E_USER_ERROR /* | E_DEPRECATED | E_USER_DEPRECATED */; for testing, so that the $level variable does not include the deprecation bitflags,
  • so $log is now $log = $this->loggedErrors & $type; which means E_ALL & E_USER_DEPRECATED which means it's still E_USER_DEPRECATED (all right, everything's fine),
  • so $throw is $this->thrownErrors & $type & $level which means that it's not thrown because E_USER_DEPRECATED bit is not in $this->thrownErrors, so all right,
  • then $type is $type &= $level | $this->screamedErrors;, since default is E_ERROR + E_CORE_ERROR + E_COMPILE_ERROR + E_PARSE for $this->screamedErrors this lead to 0, actually, I guess in that particular line, you keeping the type if an only if one of its bits matches one of the $level bits or one of the $this->screamedErrors bits, ok, seems fine,
  • then if if (!$type || (!$log && !$throw)) { you return, good.

Now, everything in this seems fine. Except that, I did a simple patch here, I just removed the E_DEPRECATED | E_USER_DEPRECATED from the forced levels to be logged. If I restore them, end of the previous scenario will be:

  • then $type is $type &= $level | $this->screamedErrors;, since default is E_ERROR + E_CORE_ERROR + E_COMPILE_ERROR + E_PARSE for $this->screamedErrors it becomes 16384 (i.e. E_USER_DEPRECATED),
  • then if if (!$type || (!$log && !$throw)) { does not return, it executes the rest of the function, and log my error.

In here, I don't really understand why and how logging conditions have been chosen, especially this code is very hard to read because of heavy bitflags usage, and, in my opinion, it lacks comments for the reader to understand it fully without having to debug.

From my point of view, the if (!$type || (!$log && !$throw)) {, if I understand it right, if there's no type, then return (no type means the error was silenced by error_level() configuration), or if there's no log nor exception, then return as well (which means that the error at the same time does not trigger exceptions, AND was not set to be logged).

Right, then I should have no $type there ! I seriously still don't understand why:

        // Strong errors are not authorized to be silenced.
        $level |= E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;

I agree with the original code author "Strong errors are not authorized to be silenced". But where I do not agree, E_DEPRECATED and E_USER_DEPRECATED are not strong errors: they just are a hint that tells that something will be deprecated in the future. As a developer, I do appreciate very much to have those when I work, but as a maintainer of a production application, I'd very much like to just completely drop those from my prods.

To be honest after debugging almost the whole class (and it is very hard, because there's more than one instance, one that restores another from the error handler and changes its internals, very hard runtime to fully understand) there is absolutely no technical reason I could see for E_DEPRECATED and E_USER_DEPRECATED to be forced. You pointed out that they are hardcodedely NOT in thrownErrors, but they also hardcodedely in loggedErrors, so either way, they will ALWAYS be logged some way or another. The only way to really silent them (I mean silent them in the logs, not silent them in the PHP error handler meaning) is to configure via the error_level() function call.

@ro0NL
Copy link
Contributor

ro0NL commented Jan 25, 2022

in 5.4 i decided to not have this prod/dev discrepancy

# packages/monolog.yaml
monolog:
    channels:
        - deprecation

# packages/dev/monolog.yaml
monolog:
    handlers:
        ...
        console:
            type: console
            process_psr_3_messages: false
            channels: ["!event", "!doctrine", "!console", "!deprecation"]

having the deprecation in channel in prod, but the php channel in dev feels weird to me. Now it's always the deprecation channel, thus can be excluded.

@ro0NL
Copy link
Contributor

ro0NL commented Jan 25, 2022

To me this is a recipe error btw.

@pounard
Copy link
Contributor

pounard commented Feb 11, 2022

Since I upgraded a project from 5.3 to 5.4, deprecations are back again in console. I tried many subtile ways of configuring monolog, nothing is working. I hoped I would not need to go into step debug again, but I'll do.

@pounard
Copy link
Contributor

pounard commented Feb 11, 2022

OK here is where I got so far:

  • When the debug component is enabled, during bootstrap, an instance of BufferingLogger is set as default logger, in Debug::enable(), before the kernel is created by calling ErrorHandler::setDefaultLogger().
  • Then ErrorHandler::register() is called right after that (OK, it wants to capture errors before monolog is initialized, I guess, seems legit).
  • Then during FrameworkBundle::boot() the error handler is set once again (seems legit at this point).
  • On ConsoleEvents::COMMAND event, DebugHandlersListener::configure() method is called which calls itself DebugHandlersListener::setDefaultLoggers(), which sets a deprecation logger by calling ErrorHandler::setDefaultLogger() once again.
  • On ErrorHandler::setDefaultLogger() calls setLoggers() which itself will call $this->bootstrappingLogger->cleanLogs(), which will fetch all errors that were buffered in the BufferingLogger.
  • This calls Symfony\Bridge\Monolog\Logger::addRecord() for each log entry.
  • At the point, $record array has the right channel and level set, which is good.
  • It iterates over all handlers and call the handle() method, most handlers will only check for the error level, not the channel, which makes all of them log the error.
  • I lost track of were I was debugging, but going back to DebugHandlersListener::setDefaultLoggers() which was not ended yet, it calls ErrorHandler::setDefaultLogger() a second time, at the end of the method.
  • Which calls ErrorHandler::setLogger() a second time, which then decide to $flush because loggers have changed, but this time $this->bootstrappingLogger->cleanLogs() yields no logs.
  • Then going back to DebugHandlersListener::configure(), please note I still do not have anything in console displaying yet (either it's not flushed yet, either logs have not been sent yet).
  • Then it goes out of the event dispatcher, run the command, and logs appears when the command is run.

The debug machinery is terribly complicated (and honestly, code is far from being easily read), I'm stopping here. I suspect that when cleanLogs() is called for the first time, loggers are not fully setup yet (at this very moment, it seems that the ErrorHandler yield only one Logger instance), and this is why all messages end up being flushed in console instead of being rightfully dispatched in the right channel handlers.

At this very moment, $type value is 16384, and only 8192 (E_DEPRECATED) and 16384 (E_USER_DEPRECATED) have a configured logger, all other types have the default BufferingLogger.

This means that something, during initialization, forces all the deprecations to have a configured logger which ignores channels and sends everything to every handler it has at this point. But at this very moment, handlers in memory are not the one configured by the user configuration, because framework is not bootstrapped yet.

I think this is a bug, and the bug lies in DebugHandlersListener::configure(), it should not call setDefaultLoggers() which forces to flush deprecation errors that happened during initialization (before monolog was correctly setup) because at this moment, monolog is not completely initialized yet. There's something wrong happening in there.

But in the end, this is not a critical bug, since it happens only when APP_DEBUG is true.

As a side note, the whole DebugHandlersListener is very confusing, and very hard to understand, I wouldn't be surprised if there is some confusion in logic inside.

@pounard
Copy link
Contributor

pounard commented Feb 11, 2022

I'd add that for people that wanted to shutdown deprecation logging that happens before monolog is fully bootstrapped, I'm sorry, but it seems to be an non-solvable problem considering how is implemented the debug machinery. It'd probably require a full refactor of this component.

Switching to PHP 8.1 with Symfony 6 will convert most of those errors into exceptions, forcing you to fix your deprecations anyway, so my advice is to upgrade ^^

@nocive
Copy link

nocive commented Mar 14, 2022

@pounard that's easier said than done for many of us.
I for one have a project where most of the deprecations do not come from our code directly but rather from upstream dependencies which have yet to adapt their code to be deprecation free. So sadly, unless one is willing to create a bunch of forks with custom patches, there's really not much else that can be done.

@pounard
Copy link
Contributor

pounard commented Mar 14, 2022

that's easier said than done for many of us.

Yes, I definitely agree, I didn't fix anything myself yet on my projects, it's an insane amount of work, almost impossible because of external dependencies. I was being sarcastic.

@gnumoksha
Copy link

I've tested almost all suggestions here, but none worked with Symfony 6.0 and monolog-bundle 3.7.1. It's sad because the deprecations are in third-party libraries which I'm not the owner of, and I really don't care if they use a deprecated class that is inside a famous project. Also, I can't see any reason for Symfony forcing us to deal with deprecations if we don't ask for that.

That being said, my workaround is to redirect the stderr to nowhere:

$ ./bin/console MY_COMMAND 2>/dev/null

@mdeboer
Copy link
Contributor

mdeboer commented Apr 5, 2022

I've tested almost all suggestions here, but none worked with Symfony 6.0 and monolog-bundle 3.7.1. It's sad because the deprecations are in third-party libraries which I'm not the owner of, and I really don't care if they use a deprecated class that is inside a famous project. Also, I can't see any reason for Symfony forcing us to deal with deprecations if we don't ask for that.

That being said, my workaround is to redirect the stderr to nowhere:

$ ./bin/console MY_COMMAND 2>/dev/null

Same, which is a shame as like you say, I fixed all deprecations I could find and all deprecations are from third party packages which are already at their latest versions.

Was hoping the monolog fix would work but no.

@nocive
Copy link

nocive commented May 12, 2022

I'd like to share what we ended up doing, for those out there that might be interested on how to work around your console commands getting polluted with deprecation notices which you have no control over.

We created our own custom debug error handler, which is essentially a copy of the original debug handler with an additional flag to opt-in/out of the console deprecations. We then modified our bin/console file to use our custom debug error handler instead of the default one.

MyApp\DebugErrorHandler

declare(strict_types=1);

use Symfony\Component\ErrorHandler\BufferingLogger;
use Symfony\Component\ErrorHandler\DebugClassLoader;
use Symfony\Component\ErrorHandler\ErrorHandler;

/**
 * This class is a copy of the original Symfony\Component\ErrorHandler\Debug
 * class with the difference that it sets a null logger for deprecations.
 * At the time of writing it's still impossible to silence deprecations in the
 * symfony console which leads to noisy output when running console commands
 * with debug enabled.
 *
 * For more information see https://github.com/symfony/symfony/issues/35575.
 */
class DebugErrorHandler
{
    public static function enable(bool $showDeprecations = true): ErrorHandler
    {
        // (... original code from `Symfony\Component\ErrorHandler\ErrorHandler\Debug` ...)

        $errorHandler = new ErrorHandler(new BufferingLogger(), true);
        if (!$showDeprecations) {
            // silence deprecations in the console
            $errorHandler->setLoggers([
                \E_DEPRECATED => null,
                \E_USER_DEPRECATED => null,
            ]);
        }

        return ErrorHandler::register($errorHandler);
    }
}

bin/console

(...)

if ($_SERVER['APP_DEBUG']) {
    umask(0000);

    if (class_exists(Debug::class)) {
        // use custom debug error handler instead of default one
        // https://github.com/symfony/symfony/issues/35575
        $showDeprecations = $_ENV['APP_CONSOLE_DEPRECATIONS'] ?? $_SERVER['APP_CONSOLE_DEPRECATIONS'] ?? false;
        $showDeprecations = filter_var($showDeprecations, \FILTER_VALIDATE_BOOLEAN);
        DebugErrorHandler::enable($showDeprecations);
    }
}

By default deprecations will not be shown in the console, if one wishes to see them just set the APP_CONSOLE_DEPRECATIONS environment variable to a truthy value.

Hopefully someone else in this thread will also find it useful. Cheers!

@ju1ius
Copy link
Contributor

ju1ius commented May 21, 2022

A workaround without the need to implement an handler class is to just call...

// calls setLoggers on the currently registered handler instance
ErrorHandler::register(null, false)->setLoggers([
    \E_DEPRECATED => [null],
    \E_USER_DEPRECATED => [null],
]);

...at the appropriate place in your application boot sequence.

For example in your AppKernel:

namespace App;

use Symfony\Component\HttpKernel\Kernel as BaseKernel;

class Kernel extends BaseKernel
{
    public function boot()
    {
        parent::boot();
        ErrorHandler::register(null, false)->setLoggers([
            \E_DEPRECATED => [null],
            \E_USER_DEPRECATED => [null],
        ]);
    }
}

@micronax
Copy link

micronax commented Jun 7, 2022

Set the following env variable (eg. in .env.local):

SYMFONY_DEPRECATIONS_HELPER=weak

@melkamar
Copy link

melkamar commented Jun 14, 2022

Isn't SYMFONY_DEPRECATIONS_HELPER just phpunit-specific?

@nocive
Copy link

nocive commented Jun 23, 2022

Correct, SYMFONY_DEPRECATIONS_HELPER will only have any effect when running via the symfony phpunit helper.

A revised version of @ju1ius solution but with an opt in/out flag:

class Kernel extends BaseKernel
{
    use MicroKernelTrait;

    public function boot(): void
    {
        parent::boot();

        // https://github.com/symfony/symfony/issues/35575
        if ($_SERVER['APP_DEBUG']) {
            $showDeprecations = $_ENV['APP_DEPRECATIONS'] ?? $_SERVER['APP_DEPRECATIONS'] ?? false;
            $showDeprecations = filter_var($showDeprecations, FILTER_VALIDATE_BOOLEAN);

            if (!$showDeprecations) {
                ErrorHandler::register(null, false)->setLoggers([
                    \E_DEPRECATED => [null],
                    \E_USER_DEPRECATED => [null],
                ]);
            }
        }
    }
}

@guldil
Copy link

guldil commented Jul 14, 2022

Hello,

i have the same message about "deprecation" in my console for 5.4.10 project even with APP_ENV=prod / APP_DEBUG=0 and a "default" monolog.yaml when clearing cache.

Only way i found is to change this in framework.yaml

framework:
    php_errors:
        log: 4096

@ricbra
Copy link
Contributor

ricbra commented Sep 13, 2022

We have the same thing, none of the above worked. For now fixed locally with this in php.ini:

[PHP]
error_reporting = E_RECOVERABLE_ERROR

Still shows the deprecations in profiler. But no longer annoying messages on your bin/console.

@mdeboer
Copy link
Contributor

mdeboer commented Sep 14, 2022

Correct, SYMFONY_DEPRECATIONS_HELPER will only have any effect when running via the symfony phpunit helper.

A revised version of @ju1ius solution but with an opt in/out flag:

class Kernel extends BaseKernel
{
    use MicroKernelTrait;

    public function boot(): void
    {
        parent::boot();

        // https://github.com/symfony/symfony/issues/35575
        if ($_SERVER['APP_DEBUG']) {
            $showDeprecations = $_ENV['APP_DEPRECATIONS'] ?? $_SERVER['APP_DEPRECATIONS'] ?? false;
            $showDeprecations = filter_var($showDeprecations, FILTER_VALIDATE_BOOLEAN);

            if (!$showDeprecations) {
                ErrorHandler::register(null, false)->setLoggers([
                    \E_DEPRECATED => [null],
                    \E_USER_DEPRECATED => [null],
                ]);
            }
        }
    }
}

It would be great if this was implemented by default, maybe you could open a PR? I would be more than happy to provide a PR if you don't have the time.

This issue is been dragging for well over 2 years now, time for some fixes :)

@nocive
Copy link

nocive commented Sep 23, 2022

@mdeboer I'm happy to provide a PR too, maybe we can collab ;)

The problem here seems more that this issue is not getting attention from the symfony core team.

Seems a bit pointless to be proposing a PR without any feedback from the team on whether they think this is the way to do it and are receptive to such change.

@mdeboer
Copy link
Contributor

mdeboer commented Sep 26, 2022

@nocive Well given it would only be a small PR, it would get their attention probably. And when it does, all they have to do is review it and hit a button instead of giving the OK and waiting for anyone to propose a PR.

I barely have any time this week but if you cook up a PR, add me as a collab or ask me for a review and I'll have a look. Probably 95% of the needed changes have already been written here by people.

@sunnyphp
Copy link

Huge canvases displayed every time the command is called is not the norm, it repels newcomers who start using Symfony.
I have Symfony 6 & PHP 8.1 versions and the same thing happens.
The problem is almost 3 years old and not solved, it says a lot about the core team.

@xabbuh
Copy link
Member

xabbuh commented Dec 13, 2022

The problem is almost 3 years old and not solved, it says a lot about the core team.

I don't see a pull request created by you that would this three year old issue. It says a lot about you.

@pounard
Copy link
Contributor

pounard commented Dec 13, 2022

@xabbuh whereas I understand why you'd defend the core team (as I would I guess because Symfony is huge and great) I do think all the confusion around logging is due to the fact there's probably no-one fully understanding the whole debug, monolog and error handler code at once. I do think, without any disrespect to core team member, it's open source, that many people did work on this, but never one person on the whole chain, which makes it a very hard to understand piece of historical spaghetti code. In my opinion, all code around early logging should be trashed and rewrote from scratch simpler.

That's I guess what one would call "technical debt".

@NeuralClone
Copy link

NeuralClone commented Dec 14, 2022

I completely get the frustration with this issue. Seeing hundreds of lines of deprecation warnings when using the console is obnoxious and doesn't make much sense. Deprecation messages are useful but only in certain contexts. The console definitely isn't one of them (in my view at least). This is worsened significantly by the fact that the bulk of those messages come from third party code that can't be reasonably fixed.

Personally, I'd love to fix this issue on my own but I don't know nearly enough about the complete system to feel confident enough to overhaul or fix it to be more flexible. Given that this issue has been around for as long as it has, I'm clearly not alone in that.

The workaround in the boot() kernel function has mostly eliminated the problem for me. Specifically, the modified version @nocive posted in June. There are still situations when using the console where it just spits out hundreds of deprecation warnings, and that's not particularly fun. But it's mostly been eliminated.

@NikitaObukhov
Copy link

I completely get the frustration with this issue. Seeing hundreds of lines of deprecation warnings when using the console is obnoxious and doesn't make much sense. Deprecation messages are useful but only in certain contexts. The console definitely isn't one of them (in my view at least). This is worsened significantly by the fact that the bulk of those messages come from third party code that can't be reasonably fixed.

Personally, I'd love to fix this issue on my own but I don't know nearly enough about the complete system to feel confident enough to overhaul or fix it to be more flexible. Given that this issue has been around for as long as it has, I'm clearly not alone in that.

The workaround in the boot() kernel function has mostly eliminated the problem for me. Specifically, the modified version @nocive posted in June. There are still situations when using the console where it just spits out hundreds of deprecation warnings, and that's not particularly fun. But it's mostly been eliminated.

Could you please share boot() workaround? I am completely frustrated with this. It is a bad joke that PHP and Symfony does not give a straightforward way to disable such things. Error handling is a mess in PHP. What a pity.

@melkamar
Copy link

Could you please share boot() workaround? I am completely frustrated with this. It is a bad joke that PHP and Symfony does not give a straightforward way to disable such things. Error handling is a mess in PHP. What a pity.

#35575 (comment)

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

No branches or pull requests