Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Migrating log access in reports: Difference between revisions

From MoodleDocs
(unit test example)
(10 intermediate revisions by 4 users not shown)
Line 1: Line 1:
This document is aimed to assist developers in replacing SQL queries to '''log''' table in the reports or other plugins.
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.


As new [[Logging 2|logging system]] is being introduced in Moodle 2.7, wrting to the '''log''' table is called "legacy logging" and still may be supported on some systems. Administrator may set up other logging plugins that can write the data to DB table in the same DB as Moodle, in another DB (SQL or non-SQL), to the file, and so on. By default a '''logstore_standard''' plugin is enabled that writes the data in the internal DB table. Moodle core defines several interfaces for reading data from the log storage plugins. Reports have the choice of accessing the active log storage via interface or registering their own observers and storing necessary data themselves.
A new [[Logging 2|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.


== Using log reader ==
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.


First, report need to find available log readers.
== Using log readers ==


There are three interfaces defined in core that log storage plugin may implement.
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\reader''' - parent for all reader interfaces;
* '''\core\log\sql_select_reader''' - has methods to create simple SQL queries to the log table. The table is expected to have columns that correspond to properties of class '''\core\base\event''';
* '''\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_reader''' - additionally has a method to return the table name which can be used for JOIN queries.
* '''\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.


Report decides which type of readers it can work with. Assuming we need a select reader:
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.
 
Example how to get the first available reader that implements \core\log\sql_select_reader:
<pre>
<pre>
$manager = get_log_manager();
$manager = get_log_manager();
$selectreaders = $manager->get_readers(\core\log\sql_select_reader);
// 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) {
if ($selectreaders) {
     $reader = reset($selectreaders);
     $reader = reset($selectreaders);
Line 25: Line 26:
</pre>
</pre>


Example how to get the legacy log reader (it is often present but not necessary enabled for writing):
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).
<pre>
<pre>
$manager = get_log_manager();
$manager = get_log_manager();
Line 41: Line 46:
</pre>
</pre>


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


Accessing log table on big systems may be slow. Some reports may wish to create their own mini log storages only for necessary rare events and store them for limited time. If developer anticipates the small size of such table and is concerned about the performance, this can be an alternative solution to reading the log table.
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 this plugin must:
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 [[Event_2#Event_observers|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.


* define database table in PLUGINDIR/db/install.xml and also create it in PLUGINDIR/db/upgrade.php
== See also ==
* define event observers in PLUGINDIR/db/events.php and the handling functions themselves, see [[Event_2#Event_observers|Events 2]]
* [[Writing PHPUnit tests#Logstores]]
* define cron job that truncates the old entries from the table
* possibly create an upgrade script that migrates the necessary events from the log table into the new plugin table in PLUGINDIR/db/upgrade.php
* re-write the SQL queries inside the plugin to access the new table instead of log

Revision as of 00:46, 2 August 2016

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