Problem/Motivation
Dries had this IMHO great idea in https://twitter.com/Dries/status/1081582626560008192 I'd also love to see a "Log deprecated code" setting in /admin so you can also identify deprecated code without having to run tests. which could be a good way to turn on and let it run for a while to audit for problems. Proper tools to vet the results would still be important (dependencies will throw these errors, some errors should not be fixed too soon without core updates, etc), but we need some way to collect the data first.
User stories from #20:
- As a site owner, I want to see if my site can be upgraded to Drupal 9 (e.g. there should be no deprecations).
- As a developer, I want to see what deprecations I have to remove. Because I have to manage custom code, I'd like to know the module, file name and line number of the deprecated code.
Proposed resolution
Add logic to _drupal_error_handler_real to used the configuration values to determine if a message should be logged.
The configuration allows one to
- Enable/disable the logging of deprecation messages
- Filter messages bases on file path
- Filter messages by the message text
Remaining tasks
Get testing to work and likely add more test cases.
- Discuss log retention around these messages, these may generate a lot of logs fast, but at the same time aggregate results out of it would be *really* useful to prioritise work on a site.
- In separate issue: discuss ways to improve making sense of this data, currently messages logged this way don't really stand out in logs and hard to filter for (they show up alongside other 'php' sourced errors and no further filter to filter to deprecated things or to aggregate them and see volumes):

User interface changes
after

API changes
None.
Data model changes
None.
Release notes snippet
TBD.

| Comment | File | Size | Author |
|---|---|---|---|
| #67 | ogging and errors.png | 34.59 KB | quietone |
Issue fork drupal-3024296
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
gábor hojtsyComment #3
gábor hojtsyComment #5
alexpottThis feature is in-built in the Symfony webprofiler - the devel project exposes this but we need to take the next step and connect up some stuff. See #3005545: Collect log messages generated during a request
Comment #6
gábor hojtsy@alexpott: thanks, that would be per request right? If we also store them then we can aggregate and get more info on requests not performed personally by us, that is most requests on a website usually.
Comment #7
alexpott@Gábor Hojtsy good point. +1 on the idea to allow sites to turn on deprecation logging in some way.
Comment #8
wim leersAnd we could perhaps even report which modules are causing deprecation errors. Which might be another incentive for contrib module maintainers to solve those deprecation errors.
Comment #9
wim leersFrom the D9 chat on Monday:
Comment #10
alexpottOne big problem for d.o telemetry is that I'm not sure how it is going to be possible to correctly attribute who is causing the deprecation. A deprecation triggered from core code doesn't mean that core needs to change (in fact that'd never be the case because we have a zero deprecated code use policy) but I don't see a clear way to attribute the deprecation to the correct module / theme / profile. This is also a general problem for the logging. We need to make sure that if we do log we give the user enough information to file an issue we're we can triage it to go against the correct module. It is highly likely that all issues will be filed against core because that is the likely point where the deprecation has been triggered from.
Comment #11
gábor hojtsyThere is a backtrace included with the error which helps identify where it came from. I do believe that local aggregation by itself will help inform people a lot about their readiness, even if we cannot automate pushing that info to drupal.org or we cannot exactly identify where things came from at the beginning.
Comment #12
alexpott@Gábor Hojtsy I agree - I've always wanted a created ticket on drupal.org button in our log viewer which would ensure that all the information we need is there. I just think #10 is mostly about the idea of automatic telemetry. Another problem that we should think about is noise. At the moment the default configuration is to keep 1000 log messages in db log but this could get extremely noisy if every request that hits the web server generates a message. Maybe we should priorities purging deprecation messages first and then limit to the count because they are the least important.
Comment #13
gábor hojtsyYeah I think this needs to be ultimately in its own storage and aggregated (not stored individually) removed from the logs before they get purged. They could also go into their own logs outright, but I am not sure if that is possible. It depends if loggers can be chained somehow, did not yet look into that.
Comment #14
dawehnerI'm curious why the same information can't be extracted using some level of static code analysis. PHPStorm and phpstan are both able to figure out this information, which would allow us to not worry about runtime issues with deprecation logging.
Comment #15
berdirI think there's a reasonable amount of stuff that static code analysis can't cover, \Drupal::service()-based calls, our "optional" constructor arguments.
I don't think this is something we need *now*, we have plenty of things to work on, seems like something that sites might want to check/enable on 8.9, before making the switch to 9.0.
Comment #16
mile23A log entry that says 'drupal_render() is deprecated...' is kind of meaningless in user-space. There's no error at all here, and really nothing to warn about either. It's OK to use deprecated code, which is why it's still there.
Adding a trail back to a contrib module means that someone sees this error and annoys a contrib maintainer with it. If I were still a contrib maintainer, I'd leave code where it is until the last minor release before D9 and then turn on deprecation fails. I'd do that because deprecation is a moving target, and because it's better to be compatible with old core than not. And I wouldn't want to have to explain my wisdom to people all day long because they saw it in a log.
The main justification for doing this would be if you have a pile of custom modules that don't have tests, and you want to find out if they're D9-happy. In that case, it's fair to say that the design for this issue should not surface this information beyond log entries and I guess a report on the site status page. That way you can find out which of your own custom modules represent technical debt, but you're not directed to tell a contrib maintainer what their deprecation policy should be.
Comment #17
gábor hojtsyre @dawehner
Yeah I don't think this is THE solution to deprecation discovery. I've been looking at three other tracks of improvements in fact:
- Api.d.o improvements: #3024341: Improve deprecation listing with filtering
- Testbot improvements #3024347: Add a mechanism to selectively enable deprecation testing per configuration
- Standard deprecation format #3024461: Adopt consistent deprecation format for core and contrib deprecation messages
I think all of them help in some way. And yes static analysis tools would help as well. The more tooling we have and the easier those tools are to use and act results on, the better it will be to upgrade stuff from Drupal 8 to 9. It may be that only people with enough experience to set up local static analysation tools for their codebases reached Drupal 8 and we don't need drop-in site tools, but as @berdir explained even those people would be helped with another lens to use to verify their readiness.
re @Mile23 The promise of Drupal 8 was that we do continuous innovation and keep deprecating and adding new things so people can divide that work and not need to do everything all at once from 8 to 9 while having the inclination also to rearchitect everything and then you end up with a Rules-like situation when there is no Rules even 3 years after Drupal 8.0.0. While we of course cannot force contrib maintainers to follow that vision, we can still provide tools to help with doing that. Otherwise contrib updates will be tucked into that 6 month timeframe between Drupal 8.8 and Drupal 8.9 when they need to face a Symfony major version update, a Twig major version update, a testing system replacement, a migration system rearchitecture, etc. all at once and then we did not even look at the changes in their other dependencies in contrib and further 3rd parties they may depend on. I think its in the benefit of the contrib module maintainer as well to divide that work, they can get bugs identified sooner and feedback provided by users. I do think this issue is about providing that insight to the site maintainer and I don't think that should be easily pushed to the d.o queue (at first at least), that said it could help if site maintainers see which modules are in need of work and may invest time/money to make them work.
Comment #18
gábor hojtsyHere is a very rough idea of how this could look like:
Notes:
1. As the goal of this UI is to make you improve your compatibility / get rid of messages, you should be able to clear or archive this log when you deploy fixes. I added an archive tab to do the clear/archive from the UI. I think archiving it could be useful to look back at historic improvements but that may be the data nerd in me :D I would show how long was the data collection going prominently so it is evident how representative the data may be. If it was collected for 2 hours on a low traffic site it will not show much. Even after two months there is no guarantee that most code paths were ever run (certain errors mostly never will), but at least it will be a more representative data sample. The methodology and caveats should be explained in the help text.
2. Additionally to archiving, there could be settings as to what is being collected. Most prominently what is the target compatibility for the site. Messages for Drupal 10 or Symfony 6 changes should not be logged if the site does not aim to be compatible.
3. This is where this logging is definitely different from standard error logs. We must aggregate messages to groups because otherwise it will be impossible to manage. Aggregating to groups also helps identify the most widespread issue to fix.
4. It would be important to somehow zoom in on the source of the problem. In the proof of concept above, I was getting backtraces from errors, so I could walk through that and identify if it was invoked from a module, etc. Not 100% sure how to do this in a useful way and if this should factor into the aggregation or not (or to what extent). But we need to help people to track down where the error came from. I made each line clickable, so when people go see more info, it would print the whole deprecation message, logs from multiple occurrences of the issue (including saved backtraces from some as the log storage capacity allows).
+1 The "Since" column we would parse out of the messages hopefully (if we can, otherwise we need to save as "N/A). The "removed in" version is not shown here, but that would be taken into account when logging or not, based on settings. Since that is your target compatibility version, not sure if its valuable to show. It will likely be "boring" like "Drupal 9" and "Symfony 4/5" at all places.
This is *my* thinking about how this could look like. Feedback welcome :D
Comment #19
berdir@Gabor: I actually agree here with @Mile23 (/me marks day on calendar with a red cross :p), waiting for the last (or until that is in alpha, or the one before..) 8.x release seems like a perfectly valid approach to me especially for small to medium sized contrib modules. Getting "into" a module again takes some time, and it definitely has advantages when you can do that in bulk, especially since core is still catching up on the most common deprecated functions.
" promise of Drupal 8 was that we do continuous innovation and keep deprecating and adding new things so people can divide that work and not need to"
I don't think that is the main or even a very important reason for doing continuous innovation now in 8.x, the main reason IMHO is simply that we *can* do that now and at the same time, that we can *not* do that in 9.0 :)
Comment #20
dries commentedThis is a very important feature so thanks for driving this, Gabor.
Overall, I like the mockup.
The two big use cases are:
We should think through the developer workflow a bit more as it likely impacts the mockup:
Comment #21
gábor hojtsy@berdir: from what I see, the continuous innovation approach was supposed to bring gradually upgraded contribs. Otherwise you get years of changes all at once which is not much different from Drupal 6 to 7 let's say.
A key reason we want to make Drupal 8 compatible with Symfony 4 ASAP for example is not just so core does not need to do that work too late, but so we can release a Drupal 8 minor and say: hey contrib module authors, site maintainers, please try using Symfony 4 *now* and attempt to implement optional support for it now, so you don't need to do everything all at once in 6 months. The sooner site maintainers and contrib authors adapt the new ways of doing things the more bugs will be worked out in them. If they do it in the last 6 months, core and contrib will need to work out the bugs in that very tight timeframe while also not having a chance anymore to make API changes with deprecations for Drupal 9 to fix issues.
@dries: that is what the "from the past 37 days" signifies (since you last archived/cleared these logs) and the archive tab is supposed to let you do that. We should figure out if we want to clear or archive stuff. I think archiving is more useful since it keep more historic data, maybe more relevant logs about things your next batch of data collection may not catch so well. So if log storage allows I would opt for archiving rather than clearing logs with some way to access data in the archived entries.
Comment #22
gábor hojtsy@berdir/@Mile23: in other words how do we trust the new stuff replacing deprecated things is good enough if contribs only update to it in the very last minute when we don't have any chance anymore to change their APIs and deprecate any broken/inadequate stuff for Drupal 9? How do we trust our Symfony 4/5 or Twig 2 implementation makes sense if contribs are to update to it in the last minute when they are baked in place for good for Drupal 9 and the next chance we can change something about them without needing to support our mistakes is Drupal 10?
Comment #23
andypost@Gabor nice UI to start with! meanwhile this deprecations should be grouped within each module versions
On other hand infra moving to Gitlab so it makes sense to reconsider idea #2667536: Perform high level static analysis on core code
Comment #24
mile23I still owe you $50. I hope you're coming to DrupalCon in Seattle. :-)
Added user stories to IS.
Mistakes!!?? Unpossible!
Right, so the actual question here is: Why didn't we run more tests? In the case of contrib, we should be showing deprecations during testing without forcing a fail because of them. We currently don't do that. I'm pretty sure @mixologic made an issue for that but I can't find it right now. That way you're a contrib dev and you have a list of things to do, but you don't have to do them right now if you don't want to.
This gets back to why we'd want this logging feature: So you can turn on logging in your old sites and find out which custom code within them needs updating. You don't need it so much in order to figure out which contrib is borked, because contrib maintainers will already be doing that testing.
Re #18: These are all features that should be in dblog. :-)
#18.3 makes me think that we might make the symfony/phpunit-bridge a non-dev requirement of core, because it does all the things you mention. I'm not sure whether that's a good idea overall, but it's already done the heavy lifting.
Comment #25
webchickI agree with @Dries on the two use cases. Since this is a UI, we should assume this screen is for the site owner audience, not (necessarily) the developer audience. (For developers, some kind of command-line tool and/or something that integrates with their IDE might be more useful?)
Given it's for (at least) site owners:
- Ideally, these would be grouped by origin module/theme, not by error message. This is probably hard to do, but pointing it out, as this is the "interface" through which most site owners view their relationship with the underlying code. I did see @Mile23/@Berdir's concerns above that this may result in people annoying contrib maintainers before they're ready to make the changes, but honestly, you also get those same annoyances when you're using PHP 5 stuff that breaks on PHP 7 or what have you, so I don't really see a difference. And ideally, instead of it being annoying, it'll result in people uploading patches, and users helping each other out So You Don't Have To™. And if so, this helps with removing these deprecations gradually vs. another "Hooray! Drupal X is out! And... 13 modules are available!" moment like we're trying very hard to avoid in D9. :P
- "Since" would ideally be since Drupal 8.(minor-version) only; not even module developers will necessarily know in what arbitrary point release we decided to support Symfony 4, let alone site owners, so that seems less helpful. (I realize here you're just printing stuff verbatim from the @since message in the code, but an abstraction could be better from a UX POV.)
In other words, a "counter" UI mockup targeted at site owners could look something like this (mirroring Migrate UI, which is a screen for the same type of problem):
"View log" then takes you to the list of error messages encountered, on what files/line numbers, etc. which could either be handed to a developer, or inspected in the event that you are the developer.
We may wish to just do Gábor's from the standpoint of it being pretty easy to just knock it out, though.
Comment #26
webchickHuh. NO idea why that turned out all fuzzy, but basically, start with https://www.drupal.org/files/d8-upgrade-status-review-2.PNG and work from there. Ta-da.
Comment #27
andypost@webchick it looks & sounds like extension experimental module update_project and there was idea issue to add contrib modules explorer/browser to module listing
Comment #28
andypostComment #29
mile23We should scope contrib D9 compatibility checking to D.O because it can always run a consistent test on commit/release and then put a badge on the project page. That test would just run the module's tests without suppressing deprecations. If the module doesn't have automated testing turned on they can't have a badge.
We'd then figure out a way to put that badge on the status/module update page on the site. The information would travel with the module update data. You'd look at your update page and it tells you which modules are free of deprecation *according to D.O*, and also gives you a way to move forward. For instance, maybe the user has NeetoModule 8.x-1.0 but 8.x-2.0 is D9 ready. The report shows you this, instead of reporting that your current module has deprecations, with no options for moving forward. In fact, your current module might be throwing deprecation errors because you patched it during deploy.
So for the scope of this issue, just adding logging of deprecation errors to dblog would be the way to go. Site owners and/or developers can then look at their current sites and find custom code that needs attention if they plan to migrate to D9. They can do this without running tests (because there probably aren't any), and they get their stacktrace to find out which module is the culprit.
Comment #30
gábor hojtsy@Mile23:
This assumes that (a) most modules have tests (b) their tests are fairly complete to be able to deduct compatibility information from them. I am not sure both are true to the extent that this could be used to derive a badge on the project page. It would be highly misleading at best.
See the UI I proposed does not say anything about Drupal 9 compatibility. @webchick is proposing such a UI display but I don't think local data gathered would be enough to deduct that information either. Neither the tool on the site neither testbot has data on test coverage to be able to deduct the probability of a statement like "Drupal 9 compatible". Also something can only be truly Drupal 9 compatible once all the changes in Drupal 9 are certain which is much later. A lot of the interim changes can be executed on though. Like we do actively in #2976394: Allow Symfony 4.4 to be installed in Drupal 8. We are not going to delay on that until Drupal 8.9-dev opens.
Also we are talking about a site here. A site usually comes with a custom(ized) theme and some custom modules. As a site owner you are interested in your site's status not about module X and Y. Module X and Y are good to know, but that does not help you see your complete picture.
Which log retention setting would allow to keep enough logs to be able to use dblog? The volume of deprecation messages especially on slightly busier sites would quickly flush all the other messages out.
Comment #31
izus commentedhi,
i think we shouldn't rely on logged notices/errors nor on tests to ensure the module is ready for Drupal 9 :
Maybe we should have a sniffer to detect all deprecated usages (a php script/ a batch ui executable script/ external library ?) : a simple way for both contrib and custom projects to collect deprecated usages everywhere
The idea of a UI for reporting what is collected is excellent : i love the #18 suggestion
Comment #32
gábor hojtsy@webchick: so the fact that we did not collect a deprecation notice in a given timeframe does not prove readiness, however finding deprecation errors does prove lack of readiness. So we can identify things that will be broken but things that don't emit deprecation notices may or may not work with Drupal 9 for various reasons:
1. The codepath just did not run in the timeframe it collected notices.
2. Stuff did not use trigger_error() but was still deprecated, so no notice was invoked.
3. You are on Drupal 8.7 and there are still two more releases that will deprecate things, and we don't know what are those yet.
4. You are not running up to date versions of dependencies, eg. Symfony 4 (if core already supports it) or even 5, so you are not getting deprecations in connection with those.
There are probably more reasons :) So all-in-all we can identify issues but we cannot conclude compatibility IMHO.
@izus: certainly if you can run tools like https://github.com/phpstan/phpstan then you will get a lot of info. A module (or this module) can use phpstan (too) to gather information about deprecations. That may or may not collect all the issues that happen in runtime due to how Drupal is using PHP in particular. See https://glamanate.com/blog/writing-better-drupal-code-static-analysis-us...
Comment #33
dawehnerIt feels like there could be one dedicated issue for:
a) How would we expose this to the user?
b) What information do we log?
c) How are we able to log it in a way that the site doesn't fall apart?
For the later block I read something recently which might be an interesting solution. Let's assume we collected all the deprecations in a request and now need to store them in a database. Trigging an update/upsert query on every single request would be really bad for the actual site performance. Bloom filters could be a space and time efficient solution to figure out whether we have logged a particular deprecation already.
Comment #34
joachim commentedThis needs to have some sort of filtering for the source of the error, I think.
Use case: as a site owner, I want to update deprecated usage in my codebase's custom code, but it's hard to do that if the messages about those are drowned out by all the deprecated errors coming from core and contrib!
Comment #35
mile23Re: #30: (Considering how to surface deprecation info to the user on D.O):
Yah, this is the problem, which is why I pointed out that if you don't have testing turned on you shouldn't get a badge.
Also, a compatibility test could be devised for DrupalCI to run on projects which don't have tests: Allow deprecations to fail, enable the module, and visit all the routes in the routing file. This would give you a red-light NOPE if there are deprecations and a yellow-light D9-maybe if it passes.
Adding 'needs followup' because someone should file an ideas issue about surfacing this info to the site owner role in some way other than logs.
That's mainly the same thing I'm reacting to in #29. We can't declare compatibility, though the 'not ready' part does track.
I like the approach of #18 because it doesn't promise anything, but it does tell you that your custom modules need some love before D9 if you can read a stacktrace. Limited scope good, more chance of happening sooner. :-)
Comment #36
chandeepkhosa commentedThis is awesome! Thanks for working on this everyone!
Comment #43
mxr576Having this solved would have been really beneficial before Drupal 9.0.0 but we still have a chance to get this done before Drupal 10.0.0... :)
I firmly believe that depredations should be caught by a static code analyzer like PHPStan. Having them logged in dev environments could be something, but that won't block CR/PR/MR from being merged with deprecated API usage.
Today I have bumped in an entity query in the theme layer (yey!) that does not add explicit access check to the query. Even if we have test coverage for the module and the UI it provides and the theme modifies, this deprecation warning is never triggered in that test because the test uses a different theme - because the module should be theme-independent.
Although, currently this deprecation is not even caught by PHPStan Drupal: https://github.com/mglaman/phpstan-drupal/issues/315
Now that PHPStan is part of Drupal core, when can we make it required to have a PHPStan that covers a deprecation before the deprecation gets introduced? Does it seem a realistic requirement to others?
Comment #46
mxr576Comment #47
heddnSeems like a new title is in order.
Comment #49
plachWhat about using PHP settings to make the behavior configurable? We could make this opt-in by assuming a FALSE default and punt aggregation/filtering to a follow-up issue :)
Comment #50
berdirI closed #3106098: Allow to display/log E_USER_DEPRECATED messages as a duplicate. Note that the other issue also tried to handle skipped deprecations, which is IMHO crucial for this, as some of them have been logged a _lot_ historically and would completely spam that log, making it rather useless.
Comment #51
mxr576Removed redundant tag
Comment #52
plach@Berdir
Fair, what about making those configurable via a PHP setting as well? We could hardcode a default if the setting is NULL.
Comment #54
graber commentedHere's some initial work on this: https://git.drupalcode.org/issue/drupal-3024296/-/compare/11.x...3024296...
Not sure if filename - based deprecation level (all, contrib + custom, custom only) filtering is reliable enough, namespace is not for sure as we cannot distinguish contrib from custom at all there.
Also we could log those as ‘php_deprecation’ to distinguish from other log types.
Let's get this moving in any case :)
Comment #56
graber commentedCreated a MR against 11.x, no tests yet as it'll be nice to receive feedback first and some recommendations what'd be the best way to test (Unit?).
Marking for initial review.
Adding a patch to lock at this state to avoid composer issues if the MR gets updated as well.
Comment #57
smustgrave commentedMR appears to have some failures.
Comment #58
graber commented@smutsgrave, yes, I'm aware of that - typo in a comment. Nevertheless, I asked for a small review at this stage to ensure the direction is correct before more hours are spent on this. Can we have it?
Comment #59
smustgrave commentedGo for it. Haven't checked the follow up tag need either.
Comment #60
graber commentedThanks, received some internal feedback on this and thought about it a bit in the meantime.
TODO:
- fix typo obviously
- remove deprecation level in favor or a boolean switch and ignored file path patterns (*/core/* and */vendor/* by default)
- we should probably only log deprecations instead of displaying them on pages.
Comment #61
graber commentedRight, now work has to be done to update existing tests and write new ones. Moving this to review again so we can see if this has chances of merging at this state assuming tests are handled.
Comment #62
graber commentedComment #63
smustgrave commentedComment #64
smustgrave commentedSeems @alexpott left some feedback on the MR.
Comment #65
larowlan@alexpott and I have looked at this, removing the tag
Comment #67
quietone commentedStarted a test but in the test there is no logging of the deprecation message. I don't see why that is. Anyone?
Comment #68
andypostit may help to catch deprecations from upcoming PHP release #3427903: [META] Make Drupal 10/11 compatible with PHP 8.4
Comment #69
quietone commentedComment #70
smustgrave commentedResolved the threads but the kernel failure seems related to the change
Comment #71
quietone commentedRebase and fixed the failing kernel test.
Comment #72
quietone commentedComment #73
dwwComment #74
smustgrave commentedBelieve all feedback has been addressed on this one, do we still need a follow up?
Comment #75
alexpottWe need to do some work on the support of regular expression strings.
1. The form help text does not seem right
2. We need to validate the strings
3. The defaults are too greedy
4. The update function does not look right.