Add logging of who installs/uninstalls a module

NancyDru - January 16, 2008 - 22:19
Project:Drupal
Version:7.x-dev
Component:base system
Category:feature request
Priority:minor
Assigned:Unassigned
Status:needs work
Description

On sites where there are several admins, problems can arise from enabling or disabling modules. I would love to see a message that gets logged when a module is enabled, disabled, or uninstalled, and I'd like the uid included.

#1

deekayen - May 10, 2009 - 05:34
Status:active» needs review

Adds 3 simple watchdog calls. I didn't put a uid in the string because the user that performed the action is automatically linked with the watchdog entry and displays as a link in the User column of the Recent log entries page.

AttachmentSizeStatusTest resultOperations
210876_module_logging.patch1.37 KBIdleFailed: Failed to apply patch.View details | Re-test

#2

Freso - May 10, 2009 - 08:07
Status:needs review» needs work

Hm. Do we need a test for this?

#3

deekayen - May 11, 2009 - 06:38
Status:needs work» needs review

Same patch with tests.

AttachmentSizeStatusTest resultOperations
210876_module_logging_w_tests.patch3.35 KBIdleFailed: 11229 passes, 0 fails, 5 exceptionsView details | Re-test

#4

deekayen - May 11, 2009 - 06:39

I'm not used to tagging yet.

#5

deekayen - May 11, 2009 - 06:54

...and for some variety, this patch tests to make sure both the t() string are there and the module name in the variables field. This one is more precise; #3 is more flexible.

AttachmentSizeStatusTest resultOperations
210876_module_logging_w_tests_v2.patch3.49 KBIdleFailed: 11229 passes, 0 fails, 5 exceptionsView details | Re-test

#6

Dries - May 11, 2009 - 07:33

I support logging these events -- they are quite important. However, a couple of comments based on the last patch:

1. Assert there was a log entry is generated for module status change. sounds like it is broken English.

2. In assertModuleLogMessage($status, $module) it feels more natural to flip the order of the parameters.

3. I wonder if there needs to be a more generic assertLogMessage() (instead of assertModuleLogMessage()).

Thanks for your work!

#7

System Message - May 11, 2009 - 08:35
Status:needs review» needs work

The last submitted patch failed testing.

#8

deekayen - May 11, 2009 - 14:24
Status:needs work» needs review

This version builds on item 3 in #6 to make the test behave more generically, so it accepts parameters like watchdog()'s.

AttachmentSizeStatusTest resultOperations
210876_module_logging_generic_tests.patch4.38 KBIdleFailed: 11229 passes, 0 fails, 5 exceptionsView details | Re-test

#9

Berdir - May 11, 2009 - 21:44
Status:needs review» needs work

+    $count = db_select('watchdog', 'w')
+      ->condition(db_and()
+        ->condition('type', $type)
+        ->condition('message', $message)
+        ->condition('variables', serialize($variables))
+        ->condition('severity', $severity)
+        ->condition('link', $link)
+      )

A "db_select() object" acts the same way as a "db_and() object", so you don't need that, you can simply call condition multiple times. You only need db_and() if you want to add them to db_or() or another DatabaseCondition object.

#10

deekayen - May 11, 2009 - 22:12
Status:needs work» needs review

I'm glad that's the case. Revised to remove the extra condition junk.

AttachmentSizeStatusTest resultOperations
210876_module_logging_remove_dband.patch4.33 KBIdleFailed: Failed to apply patch.View details | Re-test

#11

Dries - May 12, 2009 - 09:05

This looks like a drastic improvement compared to the initial incarnation of this patch. Two small things though:

1. I noticed that you where missing a trailing point in one of the sentences in the phpdoc.

2. "Keep $message translatable by not concatenating dynamic values into it!" seems a little cryptic. I think it would be good to elaborate a bit on that in the docs.

Almost RTBC, IMO.

#12

deekayen - May 12, 2009 - 14:22

I ripped off the docblock from watchdog(), so I've updated it as well in this revision.

AttachmentSizeStatusTest resultOperations
210876_module_logging_mod_docblock.patch5.78 KBIdleFailed: Failed to apply patch.View details | Re-test

#13

Dries - May 12, 2009 - 18:08
Status:needs review» fixed

Looks great. Committed to CVS HEAD. Thanks deekayen.

#14

Dave Reid - May 13, 2009 - 05:06
Status:fixed» needs work

Why did this not use hook_modules_installed/enabled/disabled/uninstalled? Let's keep this logging out of the api functions.

#15

sun - May 13, 2009 - 10:37

Hm. Not sure. Invoking watchdog() after an action was performed is usually done by the API function itself.

For example: http://api.drupal.org/api/function/node_form_submit/7

#16

Berdir - May 13, 2009 - 10:44

First that and second, who whould do it then? system.module? We don't really gain anything then. I would agree if there would be a watchdog module though, but that would mean that all watchdog calls need to be moved to hooks.

#17

deekayen - May 13, 2009 - 13:46

@Dave Reid: Mostly because I wasn't aware of the new hooks. I could move them to new hook functions in system.module. I'm mostly willing to consider this because I noticed I created the only calls to watchdog in all of install.inc and module.inc. Otherwise, moving them to system.module, which is also required anyway, seems to just spread around the code and seems like more to keep track of and more function overhead.

Being serious though, because I really want to get the whole picture, what is gained by moving them to the new hooks in system.module as opposed to having them called deeper in the .inc?

#18

sun - May 13, 2009 - 14:04
Status:needs work» fixed

Sorry, Dave, I've thought quite a bit about this, but moving those watchdog() invocations elsewhere does not make sense. watchdog() itself is a layer of abstraction (or "hook") already, and currently, all of core invokes it directly to log an event.

It might be different if watchdog was a core-event-logging-API module of its own. But then again, we'd probably have to rewrite quite a bit of core to invoke hooks all over the place and allow that watchdog.module to catch them.

Reverting status.

#19

agentrickard - May 13, 2009 - 17:49

@sun

Respectfully. Dave's point makes great sense from a DX, code readability perspective. Putting _some_ install/uninstall function directly inside the .inc file is an inconsistency that, if allowed once, will continue, leading to difficulties in finding where certain actions take place.

The proper place for this is in system_modules_(un)installed(). That's why the abstraction hooks are there.

Not changing status. This is in. We should open a new issue to fix.

#20

Berdir - May 13, 2009 - 17:54

We are not executing an action, we just log the action we've already done. With your argument, we need to move *every* watchdog call to a hook, I don't think that makes sense, atleast not if we would do it in system.module.

#21

agentrickard - May 13, 2009 - 18:00

No. You totally misunderstand.

We aren't moving the watchdog() part _per se_. We are saying "Hey, when modules are installed/uninstalled, system module wants to act." The fact that all system.module does is call watchdog is not the point. (And, yes, calling watchdog() is an action.)

In effect, we are demonstrating 'best practice' code for use of the new hooks.

Think of it this way -- which is the intended use of the new hooks -- what if, on module uninstall, Drupal core _always_ wanted to execute 4 functions instead of just one. Where should that code go and why?

The answer is system_modules_uninstalled, for easier readability and to leverage the API.

#22

deekayen - May 13, 2009 - 21:19

Dave and Ken are swaying me to their side, so I'll put this back on my todo list (through #461990: use new install/enable/disable/uninstall hooks for logging module changes).

#23

sun - May 14, 2009 - 00:27

@Dries: Your thoughts highly appreciated.

My take still is: As long as watchdog() doesn't belong to a dedicated watchdog.module, the "core" function always invokes watchdog() to log an event. "core" does not mean Drupal core, but refers to the main function that takes some action. Hooks are invoked to execute additional actions, depending on the main action. But logging the event itself is always done by the main function/action.

#24

NancyDru - May 14, 2009 - 14:00

Indeed, I must absolutely agree with Daniel on this one. As a matter of fact, the "watchdog" function may, at least in this case, be poorly named since logging is replaceable. Logging must be contemporaneously done by the function taking the action, whether that is the "core" or a hook function. Anything else runs an increased risk of losing the logged message. While the request that spawned this would 99% of the time not be critical if lost, there is always that one time when a lost message is a back-breaker.

#25

agentrickard - May 14, 2009 - 14:58

@sun

That is a good point about logging within the function. Perhaps that should be a documented Drupal standard, if it isn't already.

@NancyDru

I don't see how moving the watchdog call could cause an error; besides, don't we need to ensure that these new hook work? And therefore a test based on this function makes sense.

#26

webchick - May 14, 2009 - 15:41

My general rule of thumb for issues like this is "What does core do?" And what core does is routinely fire the watchdog message wherever the actions it wishes to log are made. Often, this is in form submit handlers, but it can also be in CRUD API functions when those are present.

But nowhere do we implement hooks in order to log messages. For example, comment watchdogs are comment_save(), not hook_comment_update/insert().

There are definitely legitimate use cases for hook_modules_X(), but this isn't one of them.

#27

Dave Reid - May 14, 2009 - 16:06

Ok thank you webchick, sun, and NancyDru for helping convince me. Just wanted to make sure we weren't adding crud to the module api that the new hooks were trying to prevent.

#28

deekayen - May 14, 2009 - 17:13

Just to document it for later passer-bys, I did work some on logging the install. The problem with logging installs happens especially during the Drupal core installation because not all tables exist yet (like watchdog), so you get ugly looking things like

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'drupal-head.simpletest882494watchdog' doesn't exist in dblog_watchdog() (line 148 of /var/www/drupalhead/modules/dblog/dblog.module).

I'm attaching the method that I tried, but I left it out of the final patch because I don't think it's a simple thing to add, and even if it could be added, I think it would require more code than the log entry would be worth (since we can still easily log the enable event) to check for whether tables exist or not before inserting the log entry.

AttachmentSizeStatusTest resultOperations
210876_log_module_install.patch1.51 KBIdleFailed: Failed to run tests.View details | Re-test

#29

deekayen - May 14, 2009 - 17:21
Status:fixed» needs review

Nevermind, it dawned on me how to log the install.

AttachmentSizeStatusTest resultOperations
210876_log_module_install_v2.patch1.62 KBIdleFailed: Invalid PHP syntax in modules/system/system.test.View details | Re-test

#30

NancyDru - May 14, 2009 - 17:48

@agentrickard: the farther apart the action and the logging are, the greater the chance for a problem (such as a server crash) to cause the logging to not occur.

#31

agentrickard - May 14, 2009 - 18:38

I'm on board, too. Previous objections overruled.

#32

deekayen - June 11, 2009 - 04:18

Just to clarify what's going on here, #12 that was committed, only logs enable, disable, and uninstall events. #29 adds an additional watchdog call to log install as well.

#33

System Message - June 13, 2009 - 20:50
Status:needs review» needs work

The last submitted patch failed testing.

#34

deekayen - June 14, 2009 - 06:32
Status:needs work» needs review

Just freshening it up for the change in line numbers.

AttachmentSizeStatusTest resultOperations
210876_log_module_install_v3.patch1.62 KBIdleFailed: Failed to install HEAD.View details | Re-test

#35

System Message - June 24, 2009 - 01:20
Status:needs review» needs work

The last submitted patch failed testing.

 
 

Drupal is a registered trademark of Dries Buytaert.