Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
logger.dblog
is backend overrideable but it's pointless to override it because the module is littered with database queries.
Proposed resolution
- Create a storage backend for the dblog module.
- Create a new LogEntry class to avoid the need of interact directly with database records.
- Put all the queries of the dblog.module in this storage.
- Make this storage backend available as a service.
- Refactor the dblog module to interact with this new service
- Delete the use of
$SESSION
from the controller. This feature is covered by: #2015149: Replace dblog recent log entries with a view
Remaining tasks
- Update this patch removing the views integration changes already introduced here: #2851293: dblog is using the wrong views field, filter and relationships definitions Done
- Refactor
DbLogController::buildFilterQuery()
to return a[field, [values, ...], operator]
array. That the storage backend can use to build the filter. - Add test coverage for the refactor of
buildFilterQuery
- Refactor
DbLogStorage::loadMultiple
to use the new filter notation described above. - Add unit tests for the LogEntry class
User interface changes
None.
API changes
- A new
DbLogStorage
service (storage.dblog). - A new
LogEntry
class. _dblog_get_message_types
deprecated. CR: https://www.drupal.org/node/2857426
Comment | File | Size | Author |
---|---|---|---|
#90 | dblog-sql-2458191-89.patch | 45.43 KB | dagmar |
#87 | dblog-sql-2458191-87.patch | 45.88 KB | dagmar |
#83 | dblog-sql-2458191-83.patch | 46.67 KB | dagmar |
#83 | interdiff-2458191-75-83.txt | 18.29 KB | dagmar |
#75 | fqdn-2458191-74.patch | 36.54 KB | martin107 |
Comments
Comment #2
dagmar@chx Do you mean this type of sql bound?
Comment #3
dagmarI'm working on this. Just want to understand if this is the right approach for this issue.
Comment #6
daffie CreditAttribution: daffie commentedNeeds test for the new method.
Comment #7
deepakaryan1988Comment #8
yogeshmpawarI have rerolled the patch for version 8.2.x
Comment #9
daffie CreditAttribution: daffie commentedQuick review:
You are removing a truncate action and adding a delete action.
Comment #10
dagmarThanks everyone for working on this. But before trying to make this work, I think we should have an answer for my question on #3.
Also, I we are going to wrap all the SQL sentences of the dblog module to be able to swap them later, we should define a plan to do this. Where to store them, is the
core/modules/dblog/src/Logger/DbLog.php
the right place?Comment #11
daffie CreditAttribution: daffie commented@dagmar: I think that you are on the right way with your approach in comment #3. Especially literal SQL string should move to "logger.dblog" service.
That service is the right location to store them because it is a backend overridable service. If you like to store the dblogs on something other then the 3 by drupal core supported databases you can override the "logger.dblog" service and it will works for your other database. Even for a NOSQL database like MongoDB.
Some examples are:
$this->database->query('SELECT w.*, u.uid FROM {watchdog} w LEFT JOIN {users} u ON u.uid = w.uid WHERE w.wid = :id', array(':id' => $event_id))->fetchObject())
db_query('SELECT DISTINCT(type) FROM {watchdog} ORDER BY type')->fetchAllKeyed(0, 0);
For the patch in comment #8:
I think that removing the database connection is a good idea. Instead we should add the "logger.dblog" service in the same way.
Comment #12
dagmarI'm going to work on this. Stills needs work but I would like to see how the tests are failing.
Comment #14
dagmarComment #15
dagmarOk, this is now ready for a deeper review.
I think I should create a new interface to document all this new methods. Any suggestion for its name?
Comment #16
daffie CreditAttribution: daffie commentedPatch look good. I do have some remarks:
Can you add the logger.dblog service with the __construct method.
Should this piece of code not be removed? We are adding:
The parameters and the return value of these methods are not documented.
I think that it is better to rename this method to getTypes(). And it will be a "public" method.
Nitpick: This line can be removed.
Nitpick: This line can be removed.
Comment #18
dagmarThanks @daffie.
Items 1, 2, 3, 4 and 7 should be fixed now. 5 and 6 probably you made some mistake with dreditor.
Comment #19
martin107 CreditAttribution: martin107 as a volunteer commentedLooking at the new interface definition
I think we should lock down some of the input parameters to be arrays.
Plus I ran the new interface through phpcs and picked out minor nits.
Comment #21
martin107 CreditAttribution: martin107 as a volunteer commented@dagmar, sorry
I take the line .... if I broke it, I fix it..
If you don't mind I want to take ownership for a short time until tests pass.
I am working on this now...I hope that is OK
Comment #22
martin107 CreditAttribution: martin107 as a volunteer commentedComment #24
martin107 CreditAttribution: martin107 as a volunteer commentedDbLogController::buildFilterQuery was returning NULL early when the session was not primed
I think it makes more sense to return an empty array -- so we have a consistent array type when it feeds it output into DbLog::getCollection()
Comment #25
dagmarThanks @martin107 I'm going to start writing some Kernel tests this week.
Comment #26
dagmarThis patch removes the last occurrence of $connection from outside of the service.
Comment #27
dagmarHere are the initial kernel tests.
Comment #29
dagmarRenamed
core/modules/dblog/tests/src/Kernel/DbLog.php
tocore/modules/dblog/tests/src/Kernel/DbLogTest.php
Comment #30
daffie CreditAttribution: daffie commentedSorry for my late review. The patch looks great, some minor points left:
These lines are not necessary. The @coversDefaultClass tells you what this class will test.
Can we improve this. Key and the value are the log message.
Can you improve this description. Key is the message and the value is the number of appearances.
Why do we do this twice?
Not completely happy about this description, but I do not know how to improve it.
Nitpick: Double empty line.
Comment #31
dagmarThanks!
This is the only missing point of this patch.
Comment #32
dagmarI spent some time reviewing my own patch. I added more tests to cover some edge cases.
Also I worked a bit on the docs. All the references to watchdog in the interface were removed.
I think this is quite complete to be merged. What do you think @daffie?
Comment #33
daffie CreditAttribution: daffie commentedThe patch is almost RTBC for me.
I have thought about how to document the return object in DbLogInterface::get() any better and I have no idea. It is just a standard php class.
I have just 1 remark left after your last patch:
The filter parameter is an array with two key values. Can you document them.
Comment #34
himanshu-dixit CreditAttribution: himanshu-dixit as a volunteer commentedHere is the patch, not sure about the description though. Please Suggest me the right description, if there is a problem with this.
Comment #35
daffie CreditAttribution: daffie commentedThe patch looks now good enough for me.
I have 1 remark left and that can be fixed on commit:
Can we change it to "An array with the filter data to filter the collection. The following array keys can be set:"
Thank you @dagmar, @martin107, @Yogesh_Pawar and @himanshu-dixit for all your work.
Comment #36
himanshu-dixit CreditAttribution: himanshu-dixit as a volunteer commentedHere is the new patch, I am not sure weather i should split the suggested description in two line to avoid 80 cols violations on it. @daffie Please review this patch.
UPDATE: Oops, i add '.patch' extension to interdiff and now that would fail. :(
Comment #37
daffie CreditAttribution: daffie commentedThe patch looks now good enough for me.
Comment #39
himanshu-dixit CreditAttribution: himanshu-dixit as a volunteer commentedAs expected, interdiff.patch wouldn't be able to apply (Sorry i shouldn't have saved it as patch). Returning RTBC Status
Comment #40
alexpottWhy this change? It looks unnecessary. And could cause additional queries for no reason.
Comment #41
himanshu-dixit CreditAttribution: himanshu-dixit as a volunteer commentedHere is the new patch. @alexpott Please review this patch.
Comment #42
himanshu-dixit CreditAttribution: himanshu-dixit as a volunteer commentedOops, the interdiff was big because i
pull origin 8.4.x
for one of the new branch. Here is the correct interdiffComment #43
xjmNR for #41.
Comment #44
alexpottLet's deprecate this. Ideally the replacement would protected and this just not exposed. Hmmm... although:
From dblog_views_data() - so the underscore is misleading.
Also I think we should consider moving dblog_filters() to the expanded service and deprecate it. This is because it is involved in the SQL syntax for building the query.
The other thing I wonder if should we decouple storage completely from logging - ie. inject a DbLogStorage service into the logger.dblog service. This is for two reasons, one we'd have less API change and more API addition and secondly, it'd be possible to make the watchdog table create lazy so sites which swap out service don't end up with a watchdog table and can call it what they like and structure it right. Lastly,
If we really want this to be swappable just returning \stdClass with public properties doesn't offer much of an interface. We could implement a value object with getters and a magic method to get the protected properties when someone does
$result->wid
for BC.Comment #45
dagmarThanks alexpott for the review. I agree with everything you said. This is the reason #2847428: [Meta] Modernize dblog module was created.
I would like to know what is the minimal tasks we should include on this issue to commit it and iterate over the other issues.
My concern is if we try to change everything you mentioned into a single patch we will end with a entirely new dblog module in a single file to review.
Back to NR to get an answer on that. Also credited daffie he reviewed all my patches.
Comment #46
alexpott@dagmar I think this issue should be concerned with inject a storage service into the logger. And doing the minimal to make that work. It should also deprecate anything that should be deprecated as a result of this. It does not have to deal with auto schema generation. But on commit all the SQL concerns should be part of this service. The current state of the issue is not a good halfway house as it introduces a big API change when what we really want is #44.
Comment #47
dagmarThanks @alexpott.
I'll be working on this during next week.
Comment #48
dagmarHere is the first try of the new approach proposed by @alexpott.
Overall I think the proposed solution makes much more sense since there is no big changes to the Logger class but an addition.
I have some questions to discuss here:
There is some pending work to do regarding views integration. I'm posting this to see what the testbot thinks.
Comment #50
dagmarFixed all coding standards highlighted by the testbot in#48. This parch introduces a custom views filter for dblog types and therefore
_dblog_get_message_types
can be deprecated.Also I'm providing a possible (but dirty) approach for BC regarding rest integration.
Comment #51
alexpott@dagmar - this change should try to limit its scope as much as possible and just be about the storage.
Why is this required to do that? Also calling the new class DbLog is unfortunate because it clashes with Logger\DbLog just to make things more confusing.
And yep #48.3 feels an unnecessary db break.
Re #48.1 I don't think setters are appropriate - log messages are immutable!
Comment #52
daffie CreditAttribution: daffie commented@alexpott: Thank you for your help!
Comment #53
dagmarThis patch includes the minimal changes (most of them additions to the existent API) to be able to swap the storage.
Good news, there are is no BC break in this patch.
Agree. Sorry about that. I reverted all the unnecessary changes and the new interface was removed.
Fixed.
Fixed.
Makes sense :)
Thanks for all your help @alexpott
Comment #54
daffie CreditAttribution: daffie commentedA quick first review. Maybe there are some stupid questions. Hope you do not mind.
I think this is a BC break.
You cannot remove a constant. This will result in a BC break.
The API documentation and comment standards states that there must have a blank line between "Unique log event ID." and "@var int". The same for the rest of this class.
Not sure if this is a BC break.
Should this method not be the first method in this class?
Shouldn't these two constants be added to the interface?
This empty line is not needed.
Comment #55
tameeshb CreditAttribution: tameeshb at Google Summer of Code commentedNot sure on how to address backward compatibility on #54.1 , .4 and .6
Comment #56
dagmarThanks @daffie and @tameeshb.
The BC compatibility is still being discussed here: #2116841: [policy] Decide what the Drupal Public API should be and how to manage it.
From what I understand (please correct me if I'm wrong), changes in services and constructors are transparent for developers that load them using
\Drupal:: service()
.This is the relevant part from the mentioned issue.
Ok, nice catch. But we should include a @deprecate mention and point devs to use the defined in LogStorage.
Comment #57
daffie CreditAttribution: daffie commented@dagmar: For #54.1 and #54.4, I agree with you that those are not BC breaks.
Two nitpicks:
There needs to be a blank line inserted between these lines.
These spaces are not needed.
Comment #58
gaurav.kapoor CreditAttribution: gaurav.kapoor at OpenSense Labs commentedComment #60
dagmar@gaurav.kapoor thanks, but it seems you missed some files on your patch.
In my opinion, no. If you use a NoSql database system to replace the storage, you could not need a dedicated connection. Also the concept of 'table' could be different in another system.
Added the
@deprecated
comment theDEDICATED_DBLOG_CONNECTION_TARGET
constant.@daffie fixed your comments from #57. Thanks.
Comment #61
gaurav.kapoor CreditAttribution: gaurav.kapoor at OpenSense Labs commentedMinor Fixes.
Comment #62
gaurav.kapoor CreditAttribution: gaurav.kapoor at OpenSense Labs commentedI had fixed that and was uploading new patch , got an error that someone else changed Show/Hide files. Anyway it looks good now. We should add more tests to it.
Comment #63
dagmarI appreciate the help @gaurav.kapoor. But please make sure you include an interdiff https://www.drupal.org/documentation/git/interdiff when posting new patches.
Thanks!
Comment #64
alexpottNeeds to use the new deprecation policy see https://www.drupal.org/node/2856615
Needs a class docblock and this thing should probably be called something like LogEntry or LogMessage.
Comment #65
dagmarThanks @alexpott!. Added a change record here: https://www.drupal.org/node/2857426
Also updated the issue summary to reflect the API additions.
Comment #66
dagmarSorry but we need an upgrade path :(
The change of the type filter will break all the views that use this filter. And the upgrade path for the view integration is out of the scope of this issue.
I'm already working on an issue to upgrade all the dblog views handlers so the plan is:
_dblog_get_message_types
function.Comment #67
dagmarWhile working on #2852990: Deprecate dblog_filters I was thinking in this comment from #33.
I think we have the opportunity to change that. The storage service should receive the items the keys and values to filter and build the query inside. Currently this is being done by a controller. See: DbLogController::buildFilterQuery().
So probably the
$filter
passed intoloadMultiple
could look like this:And then the storage service can defined the best query to achieve that.
@daffie what do you think?
Comment #68
dagmarGood news. #2851293: dblog is using the wrong views field, filter and relationships definitions is ready for review.
Comment #69
jibranComment #70
dagmarI updated the issue summary to reflect what is missing here. I will try to review this patch and provide feedback as dblog maintainer. Contributors are welcome.
Comment #71
dagmarComment #72
martin107 CreditAttribution: martin107 as a volunteer commentedComment #73
jofitz CreditAttribution: jofitz at ComputerMinds commentedRe-rolled.
Comment #74
dagmarThanks!
Ideally we should have some Unit tests for this class.
This needs to be refactored. Something like
$query->condition(field, value, operator);
There is an array() here.
Needs to be refactored. See issue summary.
change array() to []
This needs to be refactored.
Comment #75
martin107 CreditAttribution: martin107 as a volunteer commentedTwo types of changes nothing major
1) where we have string such as
'Drupal\Core\Database\Query\PagerSelectExtender'
PagerSelectExtender::class is the same FQDN string BUT it is more semantically meaningful.
If the next commit changes the class name to say PageModifierExtender then PHP will automatically flag these strings up, if the change is not made consistently throughout the project.
2) I passed the new files through phpcs and fixed trivial nits.
PS sorry comment clash with #74
Accidently I have fixed
6,5,3more tomorrow night.
Comment #76
martin107 CreditAttribution: martin107 as a volunteer commentedComment #78
dagmarAmazing thanks @martin107.
So to recap there are 3 things missing here.
First:
This logic has to be abstracted from the controller. No SQL queries should be returned here. Instead we could just use something like the parameters accepted by QueryInterface::condition:
[$field, $value, $operator]
Example:
Secondly, we need refactor DblogStorage::loadMultiple() to accept that change and write the test coverage.
And third. We need unit test for the new LogEntry class.
Comment #79
martin107 CreditAttribution: martin107 as a volunteer commentedI will do the refactoring needed here (#78)
but first I want to remove a side issue.
$_SESSION['dblog_overview_filter'] is a global variable and that really sticks in my craw.
So do you mind if I engage in some grumpy driven development and take it out before proceeding.
Comment #80
martin107 CreditAttribution: martin107 as a volunteer commenteddagmar has convinced me not to worry about the global variable.
https://www.drupal.org/node/2877985#comment-12083604
Comment #81
dagmarComment #82
dagmar@martin107 if unasigning this ticket to allow others to contribute. The issue summary describes in the Remaining Tasks section what is missing here.
Comment #83
dagmarThis patch includes the following changes:
By making the interface less strict now it wont be possible to swap the backend and get the UI working. But I think this is a good thing, because forcing the storage to implement every single method required by the controller makes the storage really complex.
Comment #85
fgmFor the record, this issue is part of the set of abstraction changes we (mostly chx TBH) uncovered while working on the 8.x-1.x branch of the MongoDB module, which was a SQL-less distribution of Drupal. Having to support actually switching the database for something entirely different uncovered a number of cases like this one.
In relation with #1506262: Change dblog_watchdog to use Drupal Queue instead of DB insert., this makes me remember an important assumption currently done by dblog: the notion that queries are synchronous. When going with an asynchronous storage (say a queue), some integration tests will necessarily fail if they check that the data arrived "at the other end".
Comment #87
dagmarRe-rolled. Didn't apply due #2901739: Fix 'Squiz.Arrays.ArrayDeclaration' coding standard
Comment #88
fgmIt would be interesting to see if you can map this abstraction to the existing MongoDB watchdog (i.e. logger) in the 8.x-2.x branch of the MongoDB module and/or the Redis watchdog in the Redis module, or if the abstraction is not sufficient to support this overriding.
Way back in 2014, the ability to actually support a NoSQL implementation was why so many storage patches of this type were created while @chx was still working on the 8.x-1.x version of the MongoDB, showing to what extent our existing DB abstractions were still leaking.
Comment #89
dagmarRerolled after
Comment #90
dagmarRerolled after
Comment #91
fgmI've been readying the mongodb 8.2 branch for a release. Can we make sure the changes here and there will be compatible so mongodb_watchdog can still work cleanly when this issue is eventually merged.
In the meantime, AIUI the "backend_overridable" tag remaining on the
logger.dblog
service definition is not correct: this is a tag meant to be used by services injecting the database, and with this patch, that service no longer injects the database, so it no longer needs this tag.Comment #92
fgmFor referench about backend_overridable : https://www.drupal.org/node/2306083
Comment #93
fgmAfter reading part of the code, this is definitely interesting, but the use of a concrete LogEntry class is an issue, as it will be difficult to reconcile the DbLog usage with other logging mechanisms. It would probably be better to depend on factories and interfaces instead of that single concrete class. Specifically, having DbLog and DbLogStorage both instantiate the hard-coded LogEntry instead of relying on a factory service makes them harder to reuse and interface with.
Here is a comparison of the classes involved for the actual message in DbLog (LogEntry) vs MongoDB (Event/EventTemplate). The main difference is how MongoDB splits the constant part (EventTemplate) from the variant part (Event) to provide user-level aggregation instead of a plain sequential list.
Comment #100
dagmarA new attempt to address this issue is now here: #2401463: Make dblog entities
Comment #101
dagmarA full DblogStorage implementation with tests is now available here #2401463: Make dblog entities