Problem/Motivation
Dblog module hasn't really changed since Drupal 6. The upgrade to Drupal 8 left the dblog Controller with a lot of SQL queries inside. People looking for inspiration in Drupal core, should not use dblog as an example of how to organize the code of a Drupal 9+ project.
There is no way to access dblog entries without directly querying the database, and dblog is usually found in tests where modules want to ensure a given log is present after a certain action. There is no Dblog Entry API either, so everything dblog related is coupled to the table structure. Ideally this problem should be fixed by #2903456: Allow kernel tests to fail or expect logged errors
Proposed resolution
- Keep using original watchdog table schema, this guarantees sames indexes are created, no performance is list in terms of writing logs into the database.
- Keep using the Dblog Logger service to insert logs, so no performance is lost when creating logs. Also make the DblogEntry class final, so no contrib module can extend it. This will reduce the need of potential breaking changes.
- Convert Dblog Entries into content entities. But make these entities read only in the sense they cannot be updated after being created. This is what someone would expects from immutable log entries.
- Drupal core assumes all content entities can be saved, and jsonapi module has tests for this. This is incompatible with the point mentioned before, so we make the entity type internal to make it invisible to jsonapi. This also means unfortunatelly no jsonapi integration out of the box.
- Provide an EntityListBuilder to reduce the code of the DblogController. Will also simplify the views integration. and potentially expose the entity via jsonapi or rest modules. Provide a ViewBuilder to render the log details.
- When uninstalling dblog, dblog entities will be automatically deleted. This is required to be somehow compatible with how dblog worked before the entities conversion, but also to allow uninstall dblog in a production site where logs are created automatically. As this entities are content,
DbLogEntryStorage::hasData()returns FALSE when invoked from theContentUninstallValidatorthis is a tradeoff to avoid modifying ContentUninstallValidator only for logs.
Regarding BC compatibility:
- Leave DblogController untouched. Only change references in the the
dblog.routing.ymlto load the entity collection. By providing a ListBuilder and a ViewBuilder we should be able to replicate the same functionality as currently provided by the dblog module. The current set of automated tests should pass for the new implementation using ListBuilder and ViewBuilder. - Direct queries to the watchdog table are still valid, but not recommended anymore.
Remaining tasks
Reviewers needed! All code is done and test are in place.
- Add the new DblogEntry class [✅ Done]
- Add the new DblogEntryStorage class [✅Done]
- Add the View Builder [✅ Done]
- Add the List Entity Builder. [✅ Done]
- Add the remaining methods the DblogEntryStorageInterface. [✅ Done]
- Add new tests (without deleting the existing ones). [✅ Done]
- Add Upgrade path for watchdog view [✅ Done]
- Get some in depth code reviews. [❌ in progress]
User interface changes
- Some internal classes will change, instead of having
dblog-errorto render the icons, we will rely on numeric values provided by RfcLogLevel. For exampleseverity-4. - The backtrace introduced as part of #3175449: Display backtrace for logged throwables on log message details page is displayed under the error message instead to the end of the table
API changes
- New DblogEntry class. and DblogEntryInterface interface.
- New DblogEntryStorage class and DblogEntryStorageInteface interface.
- New DblogEntryAccessControllerHandler class.
- New DblogViewsData class.
- New DblogEntryListBuilder class.
- New FormatMessage service.
Data model changes
None. The watchdog table will remain intact. Column indexes are preserved.
Original report
By @chx: We could make dblog entities with a separate service writing the base data tables for fast writing.
| Comment | File | Size | Author |
|---|---|---|---|
| #97 | 2401463-nr-bot.txt | 90 bytes | needs-review-queue-bot |
| #84 | 2401463-nr-bot.txt | 90 bytes | needs-review-queue-bot |
| #79 | 2401463-nr-bot.txt | 90 bytes | needs-review-queue-bot |
Issue fork drupal-2401463
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 #7
candelas commentedThis is needed to be able to integrate with Views Bulk Operations and other modules. I hope someone with knowledge get the time to give us this present :)
At the moment no modules help admin Watchdog entries...
Comment #15
dagmarI'm working on this.
Comment #16
daffie commentedA couple remarks on the MR and the testbot is not happy.
Comment #17
candelas commentedThanks @dagmar :)
Comment #18
dagmarThanks for the initial review @daffie I will move this back to Needs Review when I consider is worth a review. The DblogStorage is incomplete and will have some methods to justify the existence of the class.
Comment #19
dagmarUpdated issue summary
Comment #20
dagmarComment #21
volegerReview comments need to be addressed.
Comment #22
dagmarComment #24
gauravvvv commentedComment #25
dagmar@voleger Thanks for your help. I'm still working on this, will you let me know when you finish with your modifications?
Comment #26
volegerSorry, no changes planned.
Comment #27
volegerset proper status
Comment #28
fgmDid you have a look at the way other db loggers like mongodb_watchdog and redis_watchdog do it ? It could be good to have a shared common mechanism for that feature, so that these alternate modules can be smaller and implement only a storage layer.
Comment #29
dagmar@fgm not yet. This is mostly exploratory work at this moment since we do not have any 'non content' and 'non config' entity storage in core right now.
I'm trying to make the tests pass using the current D9 API. But I will take a look later for sure.
Comment #30
dagmarSomething we will need fixed before implement this. #3233143: DefaultTableMapping expects ContentEntityTypeInterface to work, but this may not be necesary ready for a review.
Comment #31
dagmarMost of the failing tests are due #3042467: Support entities that are neither content nor config entities for now I patched jsonapi to skip unsupported entities.
Comment #32
dagmarThere are a few pending things that I want to address as part of this patch:
But for now I think this is ready for a review @daffie @fgm
Comment #33
dagmarComment #34
dagmar@fgm I checked the code of
redis_watchdog. With the last set of commits I pushed, this module will have automatic UI if they provide a custom implementation ofDblogEntryStorageInterface.Comment #35
dagmarLinked issues resolved by this issue.
Comment #36
dagmarComment #37
dagmarComment #38
dagmarComment #39
dagmarComment #40
dagmarComment #41
dagmarComment #42
dagmarComment #43
dagmarComment #44
dagmarI think it is ready for some reviews.
Comment #45
dagmarComment #46
dagmarComment #47
dagmarComment #49
smustgrave commentedTested this out on 9.5 and it still applies cleanly
Ran drush updb and the hooks worked created
Code looked clean to me
Only question on the db log page there is an operations column but it's empty.
Not sure how to get a framework manager to review and can't speak on it well enough for a change record.
Don't mind retesting it as this seems like a great feature so will be keeping an eye out! Thanks
Comment #50
dagmarThanks @smustgrave
Please consider the operations column for logs only are available for a very specific set of logs entries, like when creating roles.
Comment #51
smustgrave commentedwhat's your thoughts on a default value like "NA"
Comment #52
dagmarFor other listings core does not use NA when no operations are there. I think it should remain empty.
Comment #53
dagmar@smustgrave a review on #3233143: DefaultTableMapping expects ContentEntityTypeInterface to work, but this may not be necesary would be useful to unblock some of the dependencies of this issue.
Comment #54
smustgrave commentedTaking a look now. I can mark this RTBC or should I wait for the change record?
Comment #55
dagmarI just updated the change record. I cannot say if you can mark this as RTBC I coded the feature and I'm the dblog subsystem maintainer. I think we need an in depth code review, this is a pretty big change.
Comment #56
smustgrave commentedMakes sense I took a look and tested locally and nothing seemed to break so I will least give it a vote of RTBC+1
Will post in slack and see if anyone else is interested
Comment #57
berdirI didn't have a very close look, but my gut reaction is that I'm pretty conflicted on this.
The diff here is +2378 -284, its _a lot_ of new code to maintain (and initially review), there's performance to consider, some sites write _a lot_ of log entries (mostly not for good reasons, but it happens, like tons of php notices or so), making it an entity requires a ton of code (as it's a fieldable entity not a content entity, so it gets to reuse very little code but almost all the new code is custom for dblog).
The problem/motivation doesn't seem convincing enough for me to maintain that amount of code. Abstracting the storage could be also done with a regular service, similar to how things like key value store work.
Comment #58
dagmarThe diff here is +2378 -284, its _a lot_ of new code to maintain (and initially review), there's performance to consider, some sites write _a lot_ of log entries (mostly not for good reasons, but it happens, like tons of php notices or so), making it an entity requires a ton of code (as it's a fieldable entity not a content entity, so it gets to reuse very little code but almost all the new code is custom for dblog).Glad to see you here @berdir, I was expecting a review from you.
I agree it is a lot of code to review.
Please note the logger system is still just an
INSERT INTO, see item one of proposed resolution.Keep using the Dblog Logger service to insert logs, so no performance is lost when creating logsCould you elaborate this a bit more?
Comment #59
smustgrave commentedJust following up on this one.
Comment #60
dagmarI did some profiling. Test scenarios:
1. Install the site using drush.
2. Load a page not found as soon the site is installed.
3. Load a second page different page not found.
So I think we need to dig a bit deeper on this massive performance on uncached pages.
I will keep the needs profiling tag to see if I can fix this issue and provide new data.
Comment #61
dagmarI ran the profiling tests again with more detail this time. It seems I was comparing incorrect data. Here are my findings. In all cases Left is drupal 9.4 using regular watchdog entries. Right dblog entities. All test were made using the Standard profile.
Visit homepage after clearing the cache with drush cr
A page not found after visiting the homepage (cache warm scenario)
Another page not found just after cleaning cache
Visit the logs overview page - (cache warm scenario)
Visit the logs overview page just after cleaning cache
Display an individual log event - (cache warm scenario)
Comment #62
dagmarComment #63
smustgrave commentedThat is very neat! If I'm understanding the numbers correctly it's slightly better in a lot of scenarios.
May be out of my league to fully mark it but +1 for RTBC
Comment #64
gauravvvv commentedComment #65
tstoecklerI really like the idea of this issue but was surprised to see that dblog entries are not content entities here. Did not really find an explanation for that here, is
from the issue summary it?
If so, I'm not sure I'm conviced to be honest. I would agree that it does not make sense for dblog entries to follow the lead of nodes, terms, etc. by extending
EditorialContentEntityBasebut in my opinion it would still make sense for it to be a content entity. It's perfectly fine to not opt-in to revisions or translations and by not declaring afield_ui_base_route, you are really disabling dynamic fields for all intents and purposes. That would achieve the "simplified" part as far as I can tell but allow a much greater amount of code re-use.Or are there other reasons that aren't explained here (or that are and I have overlooked, in which case: sorry!).
Comment #66
dagmar@tstoeckler thanks for your feedback (and @berdir too). I had to do some tests to remember why I took the decision of not going with regular content entities.
It seems all boils down to the plan to make the new entity type compatible with the legacy approach of using
$log->severityas a StdClass object.Today I reflected about this architecture decision and I think it was incorrect. This is a new API, we have the chance to define the interface and let others use it properly.
I will take some days to refactor the codebase. I did some quick tests today and indeed it is possible to extend ContentEntityBase. Initial refactor work attached.
Comment #67
dagmarComment #68
dagmarComment #70
dagmarAlright, commit 12a875fb has a working patch for making dblog content entities, against Drupal 9.4.x. I have to say I'm much more comfortable with the shape of the code right now. Much less code duplication. And half of the lines of this patch are tests. Thanks @Berdir and @tstoeckler for pushing in that direction.
Some pending follow ups:
I won't be able to work on any Drupal issues anymore for the next 4~6 months (new baby incoming) so I'm leaving this for someone else to continue and do the follow ups. 👋
Comment #71
smustgrave commentedStill very interested in this.
Wonder if you could provide a good way for one to test this?
Comment #72
volegerAdded review comments
Comment #74
jungleComment #75
mmbkThe failing test with postgres is not generated by this patch, it already fails with the 10.1.x-dex branch https://www.drupal.org/node/3060/qa
Comment #76
jungleNW for #75
No opinion.
Any reason for this? -1.
Make sense.
Comment #77
gauravvvv commentedComment #78
junglePer the test result of DbLogEntryTest::testSerialization() #75 may not be an issue anymore. Probably, it's not an issue in newer versions of PostgreSQL.
Comment #79
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #80
catchLeft some comments on the MR. More than profiling I am wondering if the indexes are correct (i.e. an EXPLAIN on some common queries would be useful) and whether the schema matches between existing sites and a new install.
Comment #81
dagmarI'm back to work on this.
Comment #82
dagmarI updated the issue summary to answer @catch concerns regarding indexes. I ran a `DESCRIBE watchdog;` command before and after installing the site using this patch, and the table structure remains the same.
I guess this also is valid for the issue #3081144: Database primary keys can exceed maximum integer storeable (has actually occurred, in watchdog), if we fix this in the dblog.install module, the changes will also apply to dblog as entities.
I also addressed the comments about dblog exception in ContentUninstallValidator. Based on my current understanding of the module_installer logic, there is no way for dblog to by pass this content validator exception, so I had to modify it any way. I tried to make it as simple and clear possible, and not only for dblog.
Comment #83
dagmarComment #84
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #85
dagmarComment #86
dagmarI updated the issue summary based on the latest reviews assuming the proposed method names are ok. Removing needs profiling as I did the profiling tests in #61.
Comment #88
dagmarI went over all the pending open threads of the merge request and closed most of them. I left a few open to make sure the provided answer is enough for the original reviewers.
I also checked some concerns I had related caching. It seems entities are not cached but routes are (example
route:[language]=en:/admin/reports/dblog/event/10) in cache_data table. This is also happening for the current non entity implementation so I will not attempt to fix this as part of this issue. Maybe is not even an issue.Most of the concerns regarding performance, indexing and future compatibility with #3081144: Database primary keys can exceed maximum integer storeable (has actually occurred, in watchdog) are addressed as the underlying system still uses the same database scheme and insert queries.
My general feeling about the code (as the current dblog maintainer) is: this is pretty much ready to be in. There is some room of improvement in the
DblogEntryViewBuilder, but probably qualifies for a follow up. And comparing this with the current code of the dblog module I would say this is a big improvement in code quality and alignment with Drupal standards. And will also allow to close several postponed issues for more than a few years now.The remaining steps in my opinion are:
as this is calling a new API method:
ContentEntityTypeInterface;:requireDeleteContentBeforeUninstallwhich needs some grammar and common sense checking.Comment #89
dagmarI had more time to think about item 1. I think we should not make an exception for dblog entries. After researching a bit why the content validator was created it seems a bit dangerous to bypass the checks.
Concerns about disabling the dblog module in a production environment are still valid though. I created this to take care of this functionality: #3354081: Provide a way to disable creation of database log entries
Comment #91
solideogloria commentedComment no longer applies
Comment #93
dagmarI found a way to not have to pause the creation of logs and remove the dblog module transparently as usual.
The approach is not elegant, but it works. When dblog module is asked if has data from the ContentUninstallValidator it replies no... And the module can be uninstalled. Logs are deleted anyways by the
dblog_module_preuninstallhook. There is no other way to implement that I'm aware of as theModuleInstaller::uninstallmethod does not offer any other opportunity to modify the validations.This means this issue is not longer postponed on #3354081: Provide a way to disable creation of database log entries
Comment #96
dagmarAdded #2903456: Allow kernel tests to fail or expect logged errors to the issue summary to, to proper fix the problem with tests. Thanks @joachim
Comment #97
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #98
dagmarComment #99
smustgrave commentedAdded some comments to the MR. Majority small stuff.
Comment #100
ressaThanks @smustgrave, @dagmar, and everyone else for working on this.
I was looking at the "Top 'page not found' errors" (
/admin/reports/page-not-found) and "Top 'access denied' errors" (/admin/reports/access-denied) report pages today, and needed to see recent entries, for the last week.This was not possible, since currently it seems to simply list all entries directly from the database log table. I wondered if I could somehow reset them, but that would probably mean emptying the db log, which I also don't want ...
So I hope this issue can get revived and pushed over the finishing line, since it seems close, and would be a great improvement in Drupal, and give much more flexibility all round. Thanks!
PS. Perhaps adding a feature like a time-range for "Top 'page not found' errors" (
/admin/reports/page-not-found) and "Top 'access denied' errors" (/admin/reports/access-denied) report pages should be handled in a follow up issue?Comment #102
donquixote commentedI think this branch would benefit from a rebase on origin/main to get a linear history..
For the general idea:
I guess the main motivation is that a system like views can support it, and we can have references from other entities.
Seems more like a limitation of views...
Comment #103
dries commentedI tend to agree with @donquixote in #102. The number of "workarounds" needed (raw SQL writes, internal entity hidden from JSON:API, hasData() returning FALSE to bypass uninstall validation, etc) suggests that the entity system is not a natural fit for log entries.
Log entries are append-only, high-volume, ephemeral, and written at a low level where the entity system may not be fully bootstrapped. They're fundamentally different from the content and config data that entities were designed for.
The main motivation seems to be Views integration. But similar to @donquixote, I'd argue that is a Views limitation. If Views could work better with non-entity data sources, we wouldn't need to force log entries into the entity mold and we'd use Views even more.
I think improving the dblog API (a proper query service, value objects) without using entities would be a cleaner path.
Comment #104
donquixote commentedWe should explore this direction in a new issue.
This one has far too many comments that are all focused on dblog records as entities.
Comment #105
donquixote commentedTo be fair, the way I understand this proposal, the idea is to treat dblog records as entities on read, but use raw database queries for writing.
This way, the logging itself does not require the entity system.
(Which we really want to avoid, because how would we log that entity definitions are broken?)
Also, I have not fully studied the current MR.
It probably would give us some things for free, but also require some workarounds.
Comment #106
donquixote commentedI created #3582890: Add value object and query service for dblog entries..