Migrating log access in reports

Jump to: navigation, search

This document is aimed to assist developers in replacing SQL queries that access the log table (now referred to as the "legacy log" for reports or other plugins.

A new logging system is being introduced in Moodle 2.7. Writing to the legacy logging table may still be supported on some systems, however it is intended that administrators will make use of other logging plugins that can write to DB tables in the same DB as Moodle, to external DBs (SQL or non-SQL), to files, and so on. By default, a logstore_standard plugin is enabled that writes the data in the internal DB table. This table should not be queried directly. The new logging plugins define interfaces for reading data from the log stores.

Reports also have the choice of accessing the active log stores via logging plugin reader interfaces or registering their own observers and storing necessary data themselves.

Using log readers

First, reports need to find available log readers.

There are three interfaces defined in core that log storage plugins may implement.

  • \core\log\reader - parent for all reader interfaces;
  • \core\log\sql_reader (\core\log\sql_select_reader in Moodle 2.7 and Moodle 2.8) - has methods to create simple SQL queries to the log store. The table (or equivalent storage collection) used is expected to have columns that correspond to properties of class \core\base\event and
  • \core\log\sql_internal_table_reader (\core\log\sql_internal_reader in Moodle 2.7 and Moodle 2.8) - additionally has a method to return the table name which can be used to JOIN queries.

The report decides which type of readers it can work with. Assuming we need a select reader, the following example will access available interfaces of this type.

$manager = get_log_manager();
// Remember to use '\core\log\sql_select_reader' instead of '\core\log\sql_reader' in Moodle 2.7 and Moodle 2.8.
$selectreaders = $manager->get_readers('\core\log\sql_reader');
if ($selectreaders) {
    $reader = reset($selectreaders);
} else {
    // No available log reader found.

The method \core\log\manager::get_readers() returns an associative array of singleton instances of enabled log store plugins implementing the reader interface. When a plugin finds the necessary log reader it can query the data from it. Refer to the interfaces for the list of methods they implement.

For a transition period, a site may support both legacy logging and the new standard logging plugin. A report might need to access both log storages especially if it needs information that covers a long period of time that includes the transition from the legacy log to the new standard log. Please note that columns and event names are different in the new logging system and the legacy log, so separate queries will be needed.

Here is an example of how to use the legacy log reader (which may be present but not enabled for writing).

$manager = get_log_manager();
$allreaders = $manager->get_readers();
if (isset($allreaders['logstore_legacy'])) {
    $legacyreader = $allreaders['logstore_legacy'];
    if ($legacyreader->is_logging()) {
        // All events continue to be recorded in {log} table.
    } else {
        // The {log} table is kept for storing the old logs only. New events are not written to it and must be taken from another log storage.
} else {
    // You are probably developing for 2.10 and table {log} does not exist any more. Or administrator uninstalled the plugin.

Registering an observer

Accessing logs on large Moodle instances will be slow and will cause load on the entire system. Some reports may wish to create their own mini log storages, storing only relevant events and perhaps only for a limited time. If you anticipate that such tables will be small, this can be an alternative solution to reading from logs.

In order to implement an observer in a plugin you must:

  • define a database table in PLUGINDIR/db/install.xml and create it in PLUGINDIR/db/upgrade.php;
  • define event observers in PLUGINDIR/db/events.php with handler functions (see Events 2);
  • define a cron task that truncates the old entries from the table when they are no longer needed (define $plugin->cron in your version.php);
  • possibly create an upgrade script (in PLUGINDIR/db/upgrade.php) that migrates any relevant events from the legacy log table into the new observer table and
  • re-write the SQL queries inside the plugin to access the new observer table instead of logs.

See also