Merge branch 'w10_MDL-41266_m27_logging' of https://github.com/skodak/moodle

This commit is contained in:
Damyon Wiese
2014-03-04 13:32:43 +08:00
58 changed files with 3723 additions and 199 deletions
-15
View File
@@ -137,21 +137,6 @@ $temp->add(new admin_setting_configselect('deleteincompleteusers', new lang_stri
48 => new lang_string('numdays', '', 2),
24 => new lang_string('numdays', '', 1))));
$temp->add(new admin_setting_configcheckbox('logguests', new lang_string('logguests', 'admin'),
new lang_string('logguests_help', 'admin'), 1));
$temp->add(new admin_setting_configselect('loglifetime', new lang_string('loglifetime', 'admin'), new lang_string('configloglifetime', 'admin'), 0, array(0 => new lang_string('neverdeletelogs'),
1000 => new lang_string('numdays', '', 1000),
365 => new lang_string('numdays', '', 365),
180 => new lang_string('numdays', '', 180),
150 => new lang_string('numdays', '', 150),
120 => new lang_string('numdays', '', 120),
90 => new lang_string('numdays', '', 90),
60 => new lang_string('numdays', '', 60),
35 => new lang_string('numdays', '', 35),
10 => new lang_string('numdays', '', 10),
5 => new lang_string('numdays', '', 5),
2 => new lang_string('numdays', '', 2))));
$temp->add(new admin_setting_configcheckbox('disablegradehistory', new lang_string('disablegradehistory', 'grades'),
new lang_string('disablegradehistory_help', 'grades'), 0));
@@ -0,0 +1,106 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Helper trait buffered_writer
*
* @package tool_log
* @copyright 2014 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_log\helper;
defined('MOODLE_INTERNAL') || die();
/**
* Helper trait buffered_writer. Adds buffer support for the store.
* \tool_log\helper\store must be included before using this trait.
*
* @package tool_log
* @copyright 2014 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
trait buffered_writer {
/** @var array $buffer buffer of events. */
protected $buffer = array();
/** @var array $buffer buffer size of events. */
protected $buffersize;
/** @var int $count Counter. */
protected $count = 0;
/**
* Write event in the store with buffering. Method insert_events() must be
* defined.
*
* @param \core\event\base $event
*
* @return void
*/
public function write(\core\event\base $event) {
$this->buffer[] = $event;
$this->count++;
if (!isset($this->buffersize)) {
$this->buffersize = $this->get_config('buffersize', 50);
}
if ($this->count >= $this->buffersize) {
$this->flush();
}
}
/**
* Flush event buffer.
*/
public function flush() {
if ($this->count == 0) {
return;
}
$events = $this->buffer;
$this->count = 0;
$this->buffer = array();
$this->insert_events($events);
}
/**
* Bulk write a given array of events to the backend. Stores must implement this.
*
* @param array $events An array of events to write.
*/
abstract protected function insert_events($events);
/**
* Get a config value for the store.
*
* @param string $name Config name
* @param mixed $default default value
*
* @return mixed config value if set, else the default value.
*/
abstract protected function get_config($name, $default = null);
/**
* Push any remaining events to the database. Insert_events() must be
* defined. override in stores if the store doesn't support buffering.
*
*/
public function dispose() {
$this->flush();
}
}
+75
View File
@@ -0,0 +1,75 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Reader helper trait.
*
* @package tool_log
* @copyright 2014 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_log\helper;
defined('MOODLE_INTERNAL') || die();
/**
* Reader helper trait.
* \tool_log\helper\store must be included before using this trait.
*
* @package tool_log
* @copyright 2014 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* @property string $component Frankenstyle plugin name initialised in store trait.
* @property string $store short plugin name initialised in store trait.
*/
trait reader {
/**
* Default get name api.
*
* @return string name of the store.
*/
public function get_name() {
if (get_string_manager()->string_exists('pluginname', $this->component)) {
return get_string('pluginname', $this->component);
}
return $this->store;
}
/**
* Default get description method.
*
* @return string description of the store.
*/
public function get_description() {
if (get_string_manager()->string_exists('pluginname_desc', $this->component)) {
return get_string('pluginname_desc', $this->component);
}
return $this->store;
}
/**
* If the current user can access current store or not.
*
* @param \context $context
*
* @return bool
*/
public function can_access(\context $context) {
return has_capability('logstore/' . $this->store . ':read', $context);
}
}
+79
View File
@@ -0,0 +1,79 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Helper trait store.
*
* @package tool_log
* @copyright 2014 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_log\helper;
defined('MOODLE_INTERNAL') || die();
/**
* Helper trait store. Adds some helper methods for stores.
*
* @package tool_log
* @copyright 2014 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
trait store {
/** @var \tool_log\log\manager $manager manager instance. */
protected $manager;
/** @var string $component Frankenstyle store name. */
protected $component;
/** @var string $store name of the store. */
protected $store;
/**
* Setup store specific variables.
*
* @param \tool_log\log\manager $manager manager instance.
*/
protected function helper_setup(\tool_log\log\manager $manager) {
$this->manager = $manager;
$called = get_called_class();
$parts = explode('\\', $called);
if (!isset($parts[0]) || strpos($parts[0], 'logstore_') !== 0) {
throw new \coding_exception("Store $called doesn't define classes in correct namespaces.");
}
$this->component = $parts[0];
$this->store = str_replace('logstore_', '', $this->store);
}
/**
* Api to get plugin config
*
* @param string $name name of the config.
* @param null|mixed $default default value to return.
*
* @return mixed|null return config value.
*/
protected function get_config($name, $default = null) {
$value = get_config($this->component, $name);
if ($value !== false) {
return $value;
}
return $default;
}
}
+168
View File
@@ -0,0 +1,168 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Log store manager.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_log\log;
defined('MOODLE_INTERNAL') || die();
class manager implements \core\log\manager {
/** @var \core\log\reader[] $readers list of initialised log readers */
protected $readers;
/** @var \tool_log\log\writer[] $writers list of initialised log writers */
protected $writers;
/** @var \tool_log\log\store[] $stores list of all enabled stores */
protected $stores;
/**
* Delayed initialisation of singleton.
*/
protected function init() {
if (isset($this->stores)) {
// Do not bother checking readers and writers here
// because everything is init here.
return;
}
$this->stores = array();
$this->readers = array();
$this->writers = array();
// Register shutdown handler - this may be useful for buffering, file handle closing, etc.
\core_shutdown_manager::register_function(array($this, 'dispose'));
$plugins = get_config('tool_log', 'enabled_stores');
if (empty($plugins)) {
return;
}
$plugins = explode(',', $plugins);
foreach ($plugins as $plugin) {
$classname = "\\$plugin\\log\\store";
if (class_exists($classname)) {
$store = new $classname($this);
$this->stores[$plugin] = $store;
if ($store instanceof \tool_log\log\writer) {
$this->writers[$plugin] = $store;
}
if ($store instanceof \core\log\reader) {
$this->readers[$plugin] = $store;
}
}
}
}
/**
* Called from the observer only.
*
* @param \core\event\base $event
*/
public function process(\core\event\base $event) {
$this->init();
foreach ($this->writers as $plugin => $writer) {
try {
$writer->write($event, $this);
} catch (\Exception $e) {
debugging('Exception detected when logging event ' . $event->eventname . ' in ' . $plugin . ': ' .
$e->getMessage(), DEBUG_NORMAL, $e->getTrace());
}
}
}
/**
* Returns list of available log readers.
*
* This way the reports find out available sources of data.
*
* @param string $interface Returned stores must implement this interface.
*
* @return \core\log\reader[] list of available log data readers
*/
public function get_readers($interface = null) {
$this->init();
$return = array();
foreach ($this->readers as $plugin => $reader) {
if (empty($interface) || ($reader instanceof $interface)) {
$return[$plugin] = $reader;
}
}
return $return;
}
/**
* Intended for store management, do not use from reports.
*
* @return store[] Returns list of available store plugins.
*/
public static function get_store_plugins() {
return \core_component::get_plugin_list_with_class('logstore', 'log\store');
}
/**
* Usually called automatically from shutdown manager,
* this allows us to implement buffering of write operations.
*/
public function dispose() {
if ($this->stores) {
foreach ($this->stores as $store) {
$store->dispose();
}
}
$this->stores = null;
$this->readers = null;
$this->writers = null;
}
/**
* Execute cron actions.
*/
public function cron() {
$this->init();
foreach ($this->stores as $store) {
$store->cron();
}
}
/**
* Legacy add_to_log() redirection.
*
* To be used only from deprecated add_to_log() function and event trigger() method.
*
* NOTE: this is hardcoded to legacy log store plugin, hopefully we can get rid of it soon.
*
* @param int $courseid The course id
* @param string $module The module name e.g. forum, journal, resource, course, user etc
* @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify
* @param string $url The file and parameters used to see the results of the action
* @param string $info Additional description information
* @param int $cm The course_module->id if there is one
* @param int|\stdClass $user If log regards $user other than $USER
*/
public function legacy_add_to_log($courseid, $module, $action, $url = '', $info = '', $cm = 0, $user = 0) {
$this->init();
if (isset($this->stores['logstore_legacy'])) {
$this->stores['logstore_legacy']->legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user);
}
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Event observer.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_log\log;
defined('MOODLE_INTERNAL') || die();
class observer {
/**
* Redirect all events to this log manager, but only if this
* log manager is actually used.
*
* @param \core\event\base $event
*/
public static function store(\core\event\base $event) {
$logmanager = get_log_manager();
if (get_class($logmanager) === 'tool_log\log\manager') {
/** @var \tool_log\log\manager $logmanager */
$logmanager->process($event);
}
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Log store interface.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_log\log;
defined('MOODLE_INTERNAL') || die();
interface store {
/**
* Create new instance of store,
* the calling code must make sure only one instance exists.
*
* @param manager $manager
*/
public function __construct(\tool_log\log\manager $manager);
/**
* Notify store no more events are going to be written/read from it.
* @return void
*/
public function dispose();
/**
* Execute cron actions.
* @return void
*/
public function cron();
}
+37
View File
@@ -0,0 +1,37 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Log store writer interface.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_log\log;
defined('MOODLE_INTERNAL') || die();
interface writer extends store {
/**
* Write one event to the store.
*
* @param \core\event\base $event
* @return void
*/
public function write(\core\event\base $event);
}
@@ -0,0 +1,89 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Subplugin info class.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_log\plugininfo;
use core\plugininfo\base, moodle_url, part_of_admin_tree, admin_settingpage;
defined('MOODLE_INTERNAL') || die();
/**
* Plugin info class for logging store plugins.
*/
class logstore extends base {
public function is_enabled() {
$enabled = get_config('tool_log', 'enabled_stores');
if (!$enabled) {
return false;
}
$enabled = array_flip(explode(',', $enabled));
return isset($enabled['logstore_' . $this->name]);
}
public function get_settings_section_name() {
return 'logsetting' . $this->name;
}
public function load_settings(part_of_admin_tree $adminroot, $parentnodename, $hassiteconfig) {
global $CFG, $USER, $DB, $OUTPUT, $PAGE; // In case settings.php wants to refer to them.
$ADMIN = $adminroot; // May be used in settings.php.
$section = $this->get_settings_section_name();
if (!$this->is_installed_and_upgraded()) {
return;
}
if (!$hassiteconfig or !file_exists($this->full_path('settings.php'))) {
return;
}
$settings = new admin_settingpage($section, $this->displayname, 'moodle/site:config', $this->is_enabled() === false);
include($this->full_path('settings.php'));
if ($settings) {
$ADMIN->add($parentnodename, $settings);
}
}
public static function get_manage_url() {
return new moodle_url('/admin/settings.php', array('section' => 'managelogging'));
}
public function is_uninstall_allowed() {
return true;
}
public function uninstall_cleanup() {
$enabled = get_config('tool_log', 'enabled_stores');
if ($enabled) {
$enabled = array_flip(explode(',', $enabled));
unset($enabled['logstore_' . $this->name]);
$enabled = array_flip($enabled);
set_config('enabled_stores', implode(',', $enabled), 'tool_log');
}
parent::uninstall_cleanup();
}
}
@@ -0,0 +1,233 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Store management setting.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/adminlib.php");
class tool_log_setting_managestores extends admin_setting {
/**
* Calls parent::__construct with specific arguments
*/
public function __construct() {
$this->nosave = true;
parent::__construct('tool_log_manageui', get_string('managelogging', 'tool_log'), '', '');
}
/**
* Always returns true, does nothing.
*
* @return true
*/
public function get_setting() {
return true;
}
/**
* Always returns true, does nothing.
*
* @return true
*/
public function get_defaultsetting() {
return true;
}
/**
* Always returns '', does not write anything.
*
* @param mixed $data ignored
* @return string Always returns ''
*/
public function write_setting($data) {
// Do not write any setting.
return '';
}
/**
* Checks if $query is one of the available log plugins.
*
* @param string $query The string to search for
* @return bool Returns true if found, false if not
*/
public function is_related($query) {
if (parent::is_related($query)) {
return true;
}
$query = core_text::strtolower($query);
$plugins = \tool_log\log\manager::get_store_plugins();
foreach ($plugins as $plugin => $fulldir) {
if (strpos(core_text::strtolower($plugin), $query) !== false) {
return true;
}
$localised = get_string('pluginname', $plugin);
if (strpos(core_text::strtolower($localised), $query) !== false) {
return true;
}
}
return false;
}
/**
* Builds the XHTML to display the control.
*
* @param string $data Unused
* @param string $query
* @return string
*/
public function output_html($data, $query = '') {
global $OUTPUT, $PAGE;
// Display strings.
$strup = get_string('up');
$strdown = get_string('down');
$strsettings = get_string('settings');
$strenable = get_string('enable');
$strdisable = get_string('disable');
$struninstall = get_string('uninstallplugin', 'core_admin');
$strversion = get_string('version');
$pluginmanager = core_plugin_manager::instance();
$available = \tool_log\log\manager::get_store_plugins();
$enabled = get_config('tool_log', 'enabled_stores');
if (!$enabled) {
$enabled = array();
} else {
$enabled = array_flip(explode(',', $enabled));
}
$allstores = array();
foreach ($enabled as $key => $store) {
$allstores[$key] = true;
$enabled[$key] = true;
}
foreach ($available as $key => $store) {
$allstores[$key] = true;
$available[$key] = true;
}
$return = $OUTPUT->heading(get_string('actlogshdr', 'tool_log'), 3, 'main', true);
$return .= $OUTPUT->box_start('generalbox loggingui');
$table = new html_table();
$table->head = array(get_string('name'), $strversion, $strenable, $strup . '/' . $strdown, $strsettings, $struninstall);
$table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
$table->id = 'logstoreplugins';
$table->attributes['class'] = 'admintable generaltable';
$table->data = array();
// Iterate through store plugins and add to the display table.
$updowncount = 1;
$storecount = count($enabled);
$url = new moodle_url('/admin/tool/log/stores.php', array('sesskey' => sesskey()));
$printed = array();
foreach ($allstores as $store => $unused) {
$plugininfo = $pluginmanager->get_plugin_info($store);
$version = get_config($store, 'version');
if ($version === false) {
$version = '';
}
if (get_string_manager()->string_exists('pluginname', $store)) {
$name = get_string('pluginname', $store);
} else {
$name = $store;
}
// Hide/show links.
if (isset($enabled[$store])) {
$aurl = new moodle_url($url, array('action' => 'disable', 'store' => $store));
$hideshow = "<a href=\"$aurl\">";
$hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/hide') . "\" class=\"iconsmall\" alt=\"$strdisable\" /></a>";
$isenabled = true;
$displayname = "<span>$name</span>";
} else {
if (isset($available[$store])) {
$aurl = new moodle_url($url, array('action' => 'enable', 'store' => $store));
$hideshow = "<a href=\"$aurl\">";
$hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/show') . "\" class=\"iconsmall\" alt=\"$strenable\" /></a>";
$isenabled = false;
$displayname = "<span class=\"dimmed_text\">$name</span>";
} else {
$hideshow = '';
$isenabled = false;
$displayname = '<span class="notifyproblem">' . $name . '</span>';
}
}
if ($PAGE->theme->resolve_image_location('icon', $store, false)) {
$icon = $OUTPUT->pix_icon('icon', '', $store, array('class' => 'icon pluginicon'));
} else {
$icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon'));
}
// Up/down link (only if store is enabled).
$updown = '';
if ($isenabled) {
if ($updowncount > 1) {
$aurl = new moodle_url($url, array('action' => 'up', 'store' => $store));
$updown .= "<a href=\"$aurl\">";
$updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"$strup\" class=\"iconsmall\" /></a>&nbsp;";
} else {
$updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />&nbsp;";
}
if ($updowncount < $storecount) {
$aurl = new moodle_url($url, array('action' => 'down', 'store' => $store));
$updown .= "<a href=\"$aurl\">";
$updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"$strdown\" class=\"iconsmall\" /></a>";
} else {
$updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
}
++$updowncount;
}
// Add settings link.
if (!$version) {
$settings = '';
} else {
if ($surl = $plugininfo->get_settings_url()) {
$settings = html_writer::link($surl, $strsettings);
} else {
$settings = '';
}
}
// Add uninstall info.
$uninstall = '';
if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url($store, 'manage')) {
$uninstall = html_writer::link($uninstallurl, $struninstall);
}
// Add a row to the table.
$table->data[] = array($icon . $displayname, $version, $hideshow, $updown, $settings, $uninstall);
$printed[$store] = true;
}
$return .= html_writer::table($table);
$return .= get_string('configlogplugins', 'tool_log') . '<br />' . get_string('tablenosave', 'admin');
$return .= $OUTPUT->box_end();
return highlight($query, $return);
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Event observer.
*
* @package tool_log
* @category event
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$observers = array(
array(
'eventname' => '*',
'callback' => '\tool_log\log\observer::store',
'internal' => false, // This means that we get events only after transaction commit.
'priority' => 1000,
),
);
+38
View File
@@ -0,0 +1,38 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Logging support.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
function xmldb_tool_log_install() {
global $CFG;
$enabled = array();
// For now enable only the legacy logging, this keeps 100% BC.
if (file_exists("$CFG->dirroot/$CFG->admin/tool/log/store/legacy")) {
$enabled[] = 'logstore_legacy';
}
set_config('enabled_stores', implode(',', $enabled), 'tool_log');
}
+25
View File
@@ -0,0 +1,25 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Logging subplugins.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$subplugins = array('logstore' => 'admin/tool/log/store');
+29
View File
@@ -0,0 +1,29 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Store management UI lang strings.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['actlogshdr'] = 'Available log stores';
$string['configlogplugins'] = 'Please enable all required plugins and arrange then in appropriate order.';
$string['logging'] = 'Logging';
$string['managelogging'] = 'Manage log stores';
$string['pluginname'] = 'Log store manager';
+37
View File
@@ -0,0 +1,37 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Log tool API.
*
* @package tool_log
* @copyright 2014 Petr Skoda {@link http://skodak.org/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Execute cron actions.
*/
function tool_log_cron() {
// Execute cron only if this log manager used.
$logmanager = get_log_manager();
if (get_class($logmanager) === 'tool_log\log\manager') {
/** @var \tool_log\log\manager $logmanager */
$logmanager->cron();
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Logging settings.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
if ($hassiteconfig) {
$ADMIN->add('modules', new admin_category('logging', new lang_string('logging', 'tool_log')));
$temp = new admin_settingpage('managelogging', new lang_string('managelogging', 'tool_log'));
$temp->add(new tool_log_setting_managestores());
$ADMIN->add('logging', $temp);
foreach (core_plugin_manager::instance()->get_plugins_of_type('logstore') as $plugin) {
/** @var \tool_log\plugininfo\logstore $plugin */
$plugin->load_settings($ADMIN, 'logging', $hassiteconfig);
}
}
@@ -0,0 +1,77 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Helper class locally used.
*
* @package logstore_database
* @copyright 2014 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_database;
defined('MOODLE_INTERNAL') || die();
/**
* Helper class locally used.
*
* @copyright 2014 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper {
/**
* Returns list of fully working database drivers present in system.
* @return array
*/
public static function get_drivers() {
return array(
'native/mysqli' => \moodle_database::get_driver_instance('mysqli', 'native')->get_name(),
'native/mariadb' => \moodle_database::get_driver_instance('mariadb', 'native')->get_name(),
'native/pgsql' => \moodle_database::get_driver_instance('pgsql', 'native')->get_name(),
'native/oci' => \moodle_database::get_driver_instance('oci', 'native')->get_name(),
'native/sqlsrv' => \moodle_database::get_driver_instance('sqlsrv', 'native')->get_name(),
'native/mssql' => \moodle_database::get_driver_instance('mssql', 'native')->get_name()
);
}
/**
* Get a list of edu levels.
*
* @return array
*/
public static function get_level_options() {
return array(
\core\event\base::LEVEL_TEACHING => get_string('teaching', 'logstore_database'),
\core\event\base::LEVEL_PARTICIPATING => get_string('participating', 'logstore_database'),
\core\event\base::LEVEL_OTHER => get_string('other', 'logstore_database'),
);
}
/**
* Get a list of database actions.
*
* @return array
*/
public static function get_action_options() {
return array(
'c' => get_string('create', 'logstore_database'),
'r' => get_string('read', 'logstore_database'),
'u' => get_string('update', 'logstore_database'),
'd' => get_string('delete')
);
}
}
@@ -0,0 +1,245 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* External database store.
*
* @package logstore_database
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_database\log;
defined('MOODLE_INTERNAL') || die();
class store implements \tool_log\log\writer, \core\log\sql_select_reader {
use \tool_log\helper\store,
\tool_log\helper\reader,
\tool_log\helper\buffered_writer {
dispose as helper_dispose;
}
/** @var \moodle_database $extdb */
protected $extdb;
/** @var bool $logguests true if logging guest access */
protected $logguests;
/** @var array $excludelevels An array of education levels to exclude */
protected $excludelevels = array();
/** @var array $excludeactions An array of actions types to exclude */
protected $excludeactions = array();
/**
* Construct
*
* @param \tool_log\log\manager $manager
*/
public function __construct(\tool_log\log\manager $manager) {
$this->helper_setup($manager);
$this->buffersize = $this->get_config('buffersize', 50);
$this->logguests = $this->get_config('logguests', 1);
$actions = $this->get_config('excludeactions', '');
$levels = $this->get_config('excludelevels', '');
$this->excludeactions = $actions === '' ? array() : explode(',', $actions);
$this->excludelevels = $levels === '' ? array() : explode(',', $levels);
}
/**
* Setup the Database.
*
* @return bool
*/
protected function init() {
if (isset($this->extdb)) {
return !empty($this->extdb);
}
$dbdriver = $this->get_config('dbdriver');
if (!$dbdriver) {
$this->extdb = false;
return false;
}
list($dblibrary, $dbtype) = explode('/', $dbdriver);
if (!$db = \moodle_database::get_driver_instance($dbtype, $dblibrary, true)) {
debugging("Unknown driver $dblibrary/$dbtype", DEBUG_DEVELOPER);
$this->extdb = false;
return false;
}
$dboptions = array();
$dboptions['dbpersist'] = $this->get_config('dbpersist', '0');
$dboptions['dbsocket'] = $this->get_config('dbsocket', '');
$dboptions['dbport'] = $this->get_config('dbport', '');
$dboptions['dbschema'] = $this->get_config('dbschema', '');
$dboptions['dbcollation'] = $this->get_config('dbcollation', '');
try {
$db->connect($this->get_config('dbhost'), $this->get_config('dbuser'), $this->get_config('dbpass'),
$this->get_config('dbname'), false, $dboptions);
$tables = $db->get_tables();
if (!in_array($this->get_config('dbtable'), $tables)) {
debugging('Cannot find the specified table', DEBUG_DEVELOPER);
$this->extdb = false;
return false;
}
} catch (\moodle_exception $e) {
debugging('Cannot connect to external database: ' . $e->getMessage(), DEBUG_DEVELOPER);
$this->extdb = false;
return false;
}
$this->extdb = $db;
return true;
}
/**
* Insert events in bulk to the database.
*
* @param \core\event\base[] $events
*/
protected function insert_events($events) {
if (!$this->init()) {
return;
}
if (!$dbtable = $this->get_config('dbtable')) {
return;
}
$dataobj = array();
// Filter events.
foreach ($events as $event) {
if (in_array($event->crud, $this->excludeactions) ||
in_array($event->edulevel, $this->excludelevels)
) {
// Ignore event if the store settings do not want to store it.
continue;
}
if ((!CLI_SCRIPT or PHPUNIT_TEST) and !$this->logguests) {
// Always log inside CLI scripts because we do not login there.
if (!isloggedin() or isguestuser()) {
continue;
}
}
$data = $event->get_data();
$data['other'] = serialize($data['other']);
if (CLI_SCRIPT) {
$data['origin'] = 'cli';
$data['ip'] = null;
} else {
$data['origin'] = 'web';
$data['ip'] = getremoteaddr();
}
$data['realuserid'] = \core\session\manager::is_loggedinas() ? $_SESSION['USER']->realuser : null;
$dataobj[] = $data;
}
try {
$this->extdb->insert_records($dbtable, $dataobj);
} catch (\moodle_exception $e) {
debugging('Cannot write to external database: ' . $e->getMessage(), DEBUG_DEVELOPER);
}
}
/**
* Get an array of events based on the passed on params.
*
* @param string $selectwhere select conditions.
* @param array $params params.
* @param string $sort sortorder.
* @param int $limitfrom limit constraints.
* @param int $limitnum limit constraints.
*
* @return array|\core\event\base[] array of events.
*/
public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum) {
if (!$this->init()) {
return array();
}
if (!$dbtable = $this->get_config('dbtable')) {
return array();
}
$events = array();
$records = $this->extdb->get_records_select($dbtable, $selectwhere, $params, $sort, '*', $limitfrom, $limitnum);
foreach ($records as $data) {
$extra = array('origin' => $data->origin, 'realuserid' => $data->realuserid, 'ip' => $data->ip);
$data = (array)$data;
$id = $data['id'];
$data['other'] = unserialize($data['other']);
if ($data['other'] === false) {
$data['other'] = array();
}
unset($data['origin']);
unset($data['ip']);
unset($data['realuserid']);
unset($data['id']);
$events[$id] = \core\event\base::restore($data, $extra);
}
return $events;
}
/**
* Get number of events present for the given select clause.
*
* @param string $selectwhere select conditions.
* @param array $params params.
*
* @return int Number of events available for the given conditions
*/
public function get_events_select_count($selectwhere, array $params) {
if (!$this->init()) {
return 0;
}
if (!$dbtable = $this->get_config('dbtable')) {
return 0;
}
return $this->extdb->count_records_select($dbtable, $selectwhere, $params);
}
public function cron() {
}
/**
* Are the new events appearing in the reader?
*
* @return bool true means new log events are being added, false means no new data will be added
*/
public function is_logging() {
if (!$this->init()) {
return false;
}
return true;
}
/**
* Dispose off database connection after pushing any buffered events to the database.
*/
public function dispose() {
$this->helper_dispose();
if ($this->extdb) {
$this->extdb->dispose();
}
$this->extdb = null;
}
}
@@ -0,0 +1,51 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Log store lang strings.
*
* @package logstore_database
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['buffersize'] = 'Buffer size';
$string['buffersize_help'] = 'Number of log entries inserted in one batch database operation, which improves performance.';
$string['conectexception'] = 'Cannot connect to the database.';
$string['create'] = 'Create';
$string['databasesettings'] = 'Database settings';
$string['databasesettings_help'] = 'Connection details for the external log database: {$a}';
$string['databasepersist'] = 'Persistent database connections';
$string['databaseschema'] = 'Database schema';
$string['databasecollation'] = 'Database collation';
$string['databasetable'] = 'Database table';
$string['databasetable_help'] = 'Name of the table where logs will be stored. This table should have a structure identical to the one used by logstore_standard (mdl_logstore_standard_log).';
$string['excludeactions'] = 'Exclude actions of these types';
$string['excludelevels'] = 'Exclude actions with these educational levels';
$string['filters'] = 'Filter logs';
$string['filters_help'] = 'Enable filters that exclude some actions from being logged.';
$string['logguests'] = 'Log guest actions';
$string['other'] = 'Other';
$string['participating'] = 'Participating';
$string['pluginname'] = 'External database log';
$string['pluginname_desc'] = 'A log plugin that stores log entries in an external database table.';
$string['read'] = 'Read';
$string['tablenotfound'] = 'Specified table was not found';
$string['teaching'] = 'Teaching';
$string['testsettings'] = 'Test connection';
$string['testingsettings'] = 'Testing database settings...';
$string['update'] = 'Update';
@@ -0,0 +1,71 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* External database log store settings.
*
* @package logstore_database
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
if ($hassiteconfig) {
$testurl = new moodle_url('/admin/tool/log/store/database/test_settings.php', array('sesskey' => sesskey()));
$test = new admin_externalpage('logstoredbtestsettings', get_string('testsettings', 'logstore_database'),
$testurl, 'moodle/site:config', true);
$ADMIN->add('logging', $test);
$drivers = \logstore_database\helper::get_drivers();
// Database settings.
$link = html_writer::link($testurl, get_string('testsettings', 'logstore_database'), array('target' => '_blank'));
$settings->add(new admin_setting_heading('dbsettings', get_string('databasesettings', 'logstore_database'),
get_string('databasesettings_help', 'logstore_database', $link)));
$settings->add(new admin_setting_configselect('logstore_database/dbdriver', get_string('databasetypehead', 'install'), '',
'', $drivers));
$settings->add(new admin_setting_configtext('logstore_database/dbhost', get_string('databasehost', 'install'), '', ''));
$settings->add(new admin_setting_configtext('logstore_database/dbuser', get_string('databaseuser', 'install'), '', ''));
$settings->add(new admin_setting_configpasswordunmask('logstore_database/dbpass', get_string('databasepass', 'install'), '', ''));
$settings->add(new admin_setting_configtext('logstore_database/dbname', get_string('databasename', 'install'), '', ''));
$settings->add(new admin_setting_configtext('logstore_database/dbtable', get_string('databasetable', 'logstore_database'),
get_string('databasetable_help', 'logstore_database'), ''));
$settings->add(new admin_setting_configcheckbox('logstore_database/dbpersist', get_string('databasepersist',
'logstore_database'), '', '0'));
$settings->add(new admin_setting_configtext('logstore_database/dbsocket', get_string('databasesocket', 'install'), '',
''));
$settings->add(new admin_setting_configtext('logstore_database/dbport', get_string('databaseport', 'install'), '', ''));
$settings->add(new admin_setting_configtext('logstore_database/dbschema', get_string('databaseschema',
'logstore_database'), '', ''));
$settings->add(new admin_setting_configtext('logstore_database/dbcollation', get_string('databasecollation',
'logstore_database'), '', ''));
$settings->add(new admin_setting_configtext('logstore_database/buffersize', get_string('buffersize',
'logstore_database'), get_string('buffersize_help', 'logstore_database'), 50));
// Filters.
$settings->add(new admin_setting_heading('filters', get_string('filters', 'logstore_database'), get_string('filters_help',
'logstore_database')));
$settings->add(new admin_setting_configcheckbox('logstore_database/logguests', get_string('logguests',
'logstore_database'), '', '0'));
$levels = \logstore_database\helper::get_level_options();
$settings->add(new admin_setting_configmulticheckbox('logstore_database/excludelevels', get_string('excludelevels',
'logstore_database'), '', array(), $levels));
$actions = \logstore_database\helper::get_action_options();
$settings->add(new admin_setting_configmulticheckbox('logstore_database/excludeactions', get_string('excludeactions',
'logstore_database'), '', array(), $actions));
}
@@ -0,0 +1,107 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Filter form.
*
* @package logstore_database
* @copyright 2014 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once('../../../../../config.php');
require_once($CFG->dirroot . '/lib/adminlib.php');
require_login();
$context = context_system::instance();
require_capability('moodle/site:config', $context);
require_sesskey();
navigation_node::override_active_url(new moodle_url('/admin/settings.php', array('section' => 'logsettingdatabase')));
admin_externalpage_setup('logstoredbtestsettings');
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('testingsettings', 'logstore_database'));
// NOTE: this is not localised intentionally, admins are supposed to understand English at least a bit...
raise_memory_limit(MEMORY_HUGE);
$dbtable = get_config('logstore_database', 'dbtable');
if (empty($dbtable)) {
echo $OUTPUT->notification('External table not specified.', 'notifyproblem');
die();
}
$dbdriver = get_config('logstore_database', 'dbdriver');
list($dblibrary, $dbtype) = explode('/', $dbdriver);
if (!$db = \moodle_database::get_driver_instance($dbtype, $dblibrary, true)) {
echo $OUTPUT->notification("Unknown driver $dblibrary/$dbtype", "notifyproblem");
die();
}
$olddebug = $CFG->debug;
$olddisplay = ini_get('display_errors');
ini_set('display_errors', '1');
$CFG->debug = DEBUG_DEVELOPER;
error_reporting($CFG->debug);
$dboptions = array();
$dboptions['dbpersist'] = get_config('logstore_database', 'dbpersist');
$dboptions['dbsocket'] = get_config('logstore_database', 'dbsocket');
$dboptions['dbport'] = get_config('logstore_database', 'dbport');
$dboptions['dbschema'] = get_config('logstore_database', 'dbschema');
$dboptions['dbcollation'] = get_config('logstore_database', 'dbcollation');
try {
$db->connect(get_config('logstore_database', 'dbhost'), get_config('logstore_database', 'dbuser'),
get_config('logstore_database', 'dbpass'), get_config('logstore_database', 'dbname'), false, $dboptions);
} catch (\moodle_exception $e) {
echo $OUTPUT->notification('Cannot connect to the database.', 'notifyproblem');
$CFG->debug = $olddebug;
ini_set('display_errors', $olddisplay);
error_reporting($CFG->debug);
ob_end_flush();
echo $OUTPUT->footer();
die();
}
echo $OUTPUT->notification('Connection made.', 'notifysuccess');
$tables = $db->get_tables();
if (!in_array($dbtable, $tables)) {
echo $OUTPUT->notification('Cannot find the specified table ' . $dbtable, 'notifyproblem');
$CFG->debug = $olddebug;
ini_set('display_errors', $olddisplay);
error_reporting($CFG->debug);
ob_end_flush();
echo $OUTPUT->footer();
die();
}
echo $OUTPUT->notification('Table ' . $dbtable . ' found.', 'notifysuccess');
$cols = $db->get_columns($dbtable);
if (empty($cols)) {
echo $OUTPUT->notification('Can not read external table.', 'notifyproblem');
} else {
$columns = array_keys((array)$cols);
echo $OUTPUT->notification('External table contains following columns:<br />' . implode(', ', $columns), 'notifysuccess');
}
$db->dispose();
$CFG->debug = $olddebug;
ini_set('display_errors', $olddisplay);
error_reporting($CFG->debug);
ob_end_flush();
echo $OUTPUT->footer();
+47
View File
@@ -0,0 +1,47 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Fixtures for database log storage testing.
*
* @package logstore_database
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_database\event;
defined('MOODLE_INTERNAL') || die();
class unittest_executed extends \core\event\base {
public static function get_name() {
return 'xxx';
}
public function get_description() {
return 'yyy';
}
protected function init() {
$this->data['crud'] = 'u';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
}
public function get_url() {
return new \moodle_url('/somepath/somefile.php', array('id' => $this->data['other']['sample']));
}
}
@@ -0,0 +1,227 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* External database log store tests.
*
* @package logstore_database
* @copyright 2014 Petr Skoda {@link http://skodak.org/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/fixtures/event.php');
class logstore_database_store_testcase extends advanced_testcase {
public function test_log_writing() {
global $DB, $CFG;
$this->resetAfterTest();
$this->preventResetByRollback(); // Logging waits till the transaction gets committed.
$dbman = $DB->get_manager();
$this->assertTrue($dbman->table_exists('logstore_standard_log'));
$DB->delete_records('logstore_standard_log');
$this->setAdminUser();
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$course1 = $this->getDataGenerator()->create_course();
$module1 = $this->getDataGenerator()->create_module('resource', array('course' => $course1));
$course2 = $this->getDataGenerator()->create_course();
$module2 = $this->getDataGenerator()->create_module('resource', array('course' => $course2));
// Test all plugins are disabled by this command.
set_config('enabled_stores', '', 'tool_log');
$manager = get_log_manager(true);
$stores = $manager->get_readers();
$this->assertCount(0, $stores);
// Fake the settings, we will abuse the standard plugin table here...
$parts = explode('_', get_class($DB));
set_config('dbdriver', $parts[1] . '/' . $parts[0], 'logstore_database');
set_config('dbhost', $CFG->dbhost, 'logstore_database');
set_config('dbuser', $CFG->dbuser, 'logstore_database');
set_config('dbpass', $CFG->dbpass, 'logstore_database');
set_config('dbname', $CFG->dbname, 'logstore_database');
set_config('dbtable', $CFG->prefix . 'logstore_standard_log', 'logstore_database');
if (!empty($CFG->dboptions['dbpersist'])) {
set_config('dbpersist', 1, 'logstore_database');
} else {
set_config('dbpersist', 0, 'logstore_database');
}
if (!empty($CFG->dboptions['dbsocket'])) {
set_config('dbsocket', $CFG->dboptions['dbsocket'], 'logstore_database');
} else {
set_config('dbsocket', '', 'logstore_database');
}
if (!empty($CFG->dboptions['dbport'])) {
set_config('dbport', $CFG->dboptions['dbport'], 'logstore_database');
} else {
set_config('dbport', '', 'logstore_database');
}
if (!empty($CFG->dboptions['dbschema'])) {
set_config('dbschema', $CFG->dboptions['dbschema'], 'logstore_database');
} else {
set_config('dbschema', '', 'logstore_database');
}
if (!empty($CFG->dboptions['dbcollation'])) {
set_config('dbcollation', $CFG->dboptions['dbcollation'], 'logstore_database');
} else {
set_config('dbcollation', '', 'logstore_database');
}
// Enable logging plugin.
set_config('enabled_stores', 'logstore_database', 'tool_log');
set_config('buffersize', 0, 'logstore_database');
set_config('logguests', 1, 'logstore_database');
$manager = get_log_manager(true);
$stores = $manager->get_readers();
$this->assertCount(1, $stores);
$this->assertEquals(array('logstore_database'), array_keys($stores));
$store = $stores['logstore_database'];
$this->assertInstanceOf('logstore_database\log\store', $store);
$this->assertInstanceOf('tool_log\log\writer', $store);
$this->assertTrue($store->is_logging());
$logs = $DB->get_records('logstore_standard_log', array(), 'id ASC');
$this->assertCount(0, $logs);
$this->setCurrentTimeStart();
$this->setUser(0);
$event1 = \logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)));
$event1->trigger();
$logs = $DB->get_records('logstore_standard_log', array(), 'id ASC');
$this->assertCount(1, $logs);
$log1 = reset($logs);
unset($log1->id);
$log1->other = unserialize($log1->other);
$log1 = (array)$log1;
$data = $event1->get_data();
$data['origin'] = 'cli';
$data['ip'] = null;
$data['realuserid'] = null;
$this->assertEquals($data, $log1);
$this->setAdminUser();
\core\session\manager::loginas($user1->id, context_system::instance());
$this->assertEquals(2, $DB->count_records('logstore_standard_log'));
$event2 = \logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module2->cmid), 'other' => array('sample' => 6, 'xx' => 9)));
$event2->trigger();
$_SESSION['SESSION'] = new \stdClass();
$this->setUser(0);
$this->assertFalse(\core\session\manager::is_loggedinas());
$logs = $DB->get_records('logstore_standard_log', array(), 'id ASC');
$this->assertCount(3, $logs);
array_shift($logs);
$log2 = array_shift($logs);
$this->assertSame('\core\event\user_loggedinas', $log2->eventname);
$log3 = array_shift($logs);
unset($log3->id);
$log3->other = unserialize($log3->other);
$log3 = (array)$log3;
$data = $event2->get_data();
$data['origin'] = 'cli';
$data['ip'] = null;
$data['realuserid'] = 2;
$this->assertEquals($data, $log3);
// Test reading.
$this->assertSame(3, $store->get_events_select_count('', array()));
$events = $store->get_events_select('', array(), 'id', 0, 0);
$this->assertCount(3, $events);
$resev1 = array_shift($events);
array_shift($events);
$resev2 = array_shift($events);
$this->assertEquals($event1->get_data(), $resev1->get_data());
$this->assertEquals($event2->get_data(), $resev2->get_data());
// Test buffering.
set_config('buffersize', 3, 'logstore_database');
$manager = get_log_manager(true);
$stores = $manager->get_readers();
/** @var \logstore_database\log\store $store */
$store = $stores['logstore_database'];
$DB->delete_records('logstore_standard_log');
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(0, $DB->count_records('logstore_standard_log'));
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(0, $DB->count_records('logstore_standard_log'));
$store->flush();
$this->assertEquals(2, $DB->count_records('logstore_standard_log'));
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(2, $DB->count_records('logstore_standard_log'));
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(2, $DB->count_records('logstore_standard_log'));
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(5, $DB->count_records('logstore_standard_log'));
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(5, $DB->count_records('logstore_standard_log'));
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(5, $DB->count_records('logstore_standard_log'));
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(8, $DB->count_records('logstore_standard_log'));
// Test guest logging setting.
set_config('logguests', 0, 'logstore_database');
set_config('buffersize', 0, 'logstore_database');
get_log_manager(true);
$DB->delete_records('logstore_standard_log');
get_log_manager(true);
$this->setUser(null);
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(0, $DB->count_records('logstore_standard_log'));
$this->setGuestUser();
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(0, $DB->count_records('logstore_standard_log'));
$this->setUser($user1);
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(1, $DB->count_records('logstore_standard_log'));
$this->setUser($user2);
\logstore_database\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(2, $DB->count_records('logstore_standard_log'));
set_config('enabled_stores', '', 'tool_log');
get_log_manager(true);
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* External database log store.
*
* @package logstore_standard
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2014011900; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2014011000; // Requires this Moodle version.
$plugin->component = 'logstore_database'; // Full name of the plugin (used for diagnostics).
@@ -0,0 +1,52 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace logstore_legacy\event;
defined('MOODLE_INTERNAL') || die();
/**
* Legacy log emulation event class.
*
* @package core
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class legacy_logged extends \core\event\base {
public function init() {
throw new \coding_exception('legacy events cannot be triggered');
}
public static function get_name() {
return get_string('event_legacy_logged', 'logstore_legacy');
}
public function get_description() {
return $this->other['module'] . ' ' . $this->other['action'] . ' ' . $this->other['info'];
}
public function get_url() {
global $CFG;
require_once("$CFG->dirroot/course/lib.php");
$url = \make_log_url($this->other['module'], $this->other['url']);
if (!$url) {
return null;
}
return new \moodle_url($url);
}
}
@@ -0,0 +1,212 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Legacy log reader.
*
* @package logstore_legacy
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_legacy\log;
defined('MOODLE_INTERNAL') || die();
class store implements \tool_log\log\store, \core\log\sql_select_reader {
use \tool_log\helper\store,
\tool_log\helper\reader;
public function __construct(\tool_log\log\manager $manager) {
$this->helper_setup($manager);
}
/** @var array list of db fields which needs to be replaced for legacy log query */
protected $standardtolegacyfields = array(
'timecreated' => 'time',
'courseid' => 'course',
'contextinstanceid' => 'cmid',
'origin' => 'ip'
);
public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum) {
global $DB;
// Replace db field names to make it compatible with legacy log.
foreach ($this->standardtolegacyfields as $from => $to) {
$selectwhere = str_replace($from, $to, $selectwhere);
$sort = str_replace($from, $to, $sort);
if (isset($params[$from])) {
$params[$to] = $params[$from];
unset($params[$from]);
}
}
$events = array();
$records = array();
try {
$records = $DB->get_records_select('log', $selectwhere, $params, $sort, '*', $limitfrom, $limitnum);
} catch (\moodle_exception $ex) {
debugging("error converting legacy event data " . $ex->getMessage() . $ex->debuginfo, DEBUG_DEVELOPER);
}
foreach ($records as $data) {
$events[$data->id] = \logstore_legacy\event\legacy_logged::restore_legacy($data);
}
return $events;
}
public function get_events_select_count($selectwhere, array $params) {
global $DB;
// Replace db field names to make it compatible with legacy log.
foreach ($this->standardtolegacyfields as $from => $to) {
$selectwhere = str_replace($from, $to, $selectwhere);
if (isset($params[$from])) {
$params[$to] = $params[$from];
unset($params[$from]);
}
}
try {
return $DB->count_records_select('log', $selectwhere, $params);
} catch (\moodle_exception $ex) {
debugging("error converting legacy event data " . $ex->getMessage() . $ex->debuginfo, DEBUG_DEVELOPER);
return 0;
}
}
public function cron() {
global $CFG, $DB;
// Delete old logs to save space (this might need a timer to slow it down...).
if (!empty($CFG->loglifetime)) { // Value in days.
$loglifetime = time(0) - ($CFG->loglifetime * 3600 * 24);
$DB->delete_records_select("log", "time < ?", array($loglifetime));
mtrace(" Deleted old log records");
}
}
/**
* Are the new events appearing in the reader?
*
* @return bool true means new log events are being added, false means no new data will be added
*/
public function is_logging() {
return (bool)$this->get_config('loglegacy', true);
}
public function dispose() {
}
/**
* Legacy add_to_log() code.
*
* @param int $courseid The course id
* @param string $module The module name e.g. forum, journal, resource, course, user etc
* @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify.
* @param string $url The file and parameters used to see the results of the action
* @param string $info Additional description information
* @param int $cm The course_module->id if there is one
* @param int|\stdClass $user If log regards $user other than $USER
*/
public function legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user) {
// Note that this function intentionally does not follow the normal Moodle DB access idioms.
// This is for a good reason: it is the most frequently used DB update function,
// so it has been optimised for speed.
global $DB, $CFG, $USER;
if (!$this->is_logging()) {
return;
}
if ($cm === '' || is_null($cm)) { // Postgres won't translate empty string to its default.
$cm = 0;
}
if ($user) {
$userid = $user;
} else {
if (\core\session\manager::is_loggedinas()) { // Don't log.
return;
}
$userid = empty($USER->id) ? '0' : $USER->id;
}
if (isset($CFG->logguests) and !$CFG->logguests) {
if (!$userid or isguestuser($userid)) {
return;
}
}
$remoteaddr = getremoteaddr();
$timenow = time();
if (!empty($url)) { // Could break doing html_entity_decode on an empty var.
$url = html_entity_decode($url, ENT_QUOTES, 'UTF-8');
} else {
$url = '';
}
// Restrict length of log lines to the space actually available in the
// database so that it doesn't cause a DB error. Log a warning so that
// developers can avoid doing things which are likely to cause this on a
// routine basis.
if (!empty($info) && \core_text::strlen($info) > 255) {
$info = \core_text::substr($info, 0, 252) . '...';
debugging('Warning: logged very long info', DEBUG_DEVELOPER);
}
// If the 100 field size is changed, also need to alter print_log in course/lib.php.
if (!empty($url) && \core_text::strlen($url) > 100) {
$url = \core_text::substr($url, 0, 97) . '...';
debugging('Warning: logged very long URL', DEBUG_DEVELOPER);
}
if (defined('MDL_PERFDB')) {
global $PERF;
$PERF->logwrites++;
};
$log = array('time' => $timenow, 'userid' => $userid, 'course' => $courseid, 'ip' => $remoteaddr,
'module' => $module, 'cmid' => $cm, 'action' => $action, 'url' => $url, 'info' => $info);
try {
$DB->insert_record_raw('log', $log, false);
} catch (\dml_exception $e) {
debugging('Error: Could not insert a new entry to the Moodle log. ' . $e->errorcode, DEBUG_ALL);
// MDL-11893, alert $CFG->supportemail if insert into log failed.
if ($CFG->supportemail and empty($CFG->noemailever)) {
// Function email_to_user is not usable because email_to_user tries to write to the logs table,
// and this will get caught in an infinite loop, if disk is full.
$site = get_site();
$subject = 'Insert into log failed at your moodle site ' . $site->fullname;
$message = "Insert into log table failed at " . date('l dS \of F Y h:i:s A') .
".\n It is possible that your disk is full.\n\n";
$message .= "The failed query parameters are:\n\n" . var_export($log, true);
$lasttime = get_config('admin', 'lastloginserterrormail');
if (empty($lasttime) || time() - $lasttime > 60 * 60 * 24) { // Limit to 1 email per day.
// Using email directly rather than messaging as they may not be able to log in to access a message.
mail($CFG->supportemail, $subject, $message);
set_config('lastloginserterrormail', time(), 'admin');
}
}
}
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Defines the capabilities used by standard log store.
*
* @package logstore_legacy
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$capabilities = array(
'logstore/legacy:read' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'manager' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
),
),
);
@@ -0,0 +1,30 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Legacy log reader lang strings.
*
* @package logstore_legacy
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['event_legacy_logged'] = 'Legacy event logged';
$string['legacy:read'] = 'Read logs';
$string['loglegacy'] = 'Log legacy data';
$string['loglegacy_help'] = 'This plugin records log data to the legacy log table (mdl_log). This functionality has been replaced by newer, richer and more efficient logging plugins, so you should only run this plugin if you have old custom reports that directly query the old log table. Writing to the legacy logs will increase load, so it is recommended that you disable this plugin for performance reasons when it is not needed.';
$string['pluginname'] = 'Legacy log';
$string['pluginname_desc'] = 'A log plugin that stores log entries in the legacy log table.';
+52
View File
@@ -0,0 +1,52 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Legacy logging settings.
*
* @package logstore_legacy
* @copyright 2014 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
if ($hassiteconfig) {
$settings->add(new admin_setting_configcheckbox('logstore_legacy/loglegacy',
new lang_string('loglegacy', 'logstore_legacy'),
new lang_string('loglegacy_help', 'logstore_legacy'), 1));
$settings->add(new admin_setting_configcheckbox('logguests',
new lang_string('logguests', 'admin'),
new lang_string('logguests_help', 'admin'), 1));
$options = array(0 => new lang_string('neverdeletelogs'),
1000 => new lang_string('numdays', '', 1000),
365 => new lang_string('numdays', '', 365),
180 => new lang_string('numdays', '', 180),
150 => new lang_string('numdays', '', 150),
120 => new lang_string('numdays', '', 120),
90 => new lang_string('numdays', '', 90),
60 => new lang_string('numdays', '', 60),
35 => new lang_string('numdays', '', 35),
10 => new lang_string('numdays', '', 10),
5 => new lang_string('numdays', '', 5),
2 => new lang_string('numdays', '', 2));
$settings->add(new admin_setting_configselect('loglifetime',
new lang_string('loglifetime', 'admin'),
new lang_string('configloglifetime', 'admin'), 0, $options));
}
+64
View File
@@ -0,0 +1,64 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Fixtures for legacy logging testing.
*
* @package logstore_legacy
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_legacy\event;
defined('MOODLE_INTERNAL') || die();
class unittest_executed extends \core\event\base {
public static function get_name() {
return 'xxx';
}
public function get_description() {
return 'yyy';
}
protected function init() {
$this->data['crud'] = 'u';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
}
public function get_url() {
return new \moodle_url('/somepath/somefile.php', array('id' => $this->data['other']['sample']));
}
public static function get_legacy_eventname() {
return 'test_legacy';
}
protected function get_legacy_eventdata() {
return array($this->data['courseid'], $this->data['other']['sample']);
}
protected function get_legacy_logdata() {
$cmid = 0;
if ($this->contextlevel == CONTEXT_MODULE) {
$cmid = $this->contextinstanceid;
}
return array($this->data['courseid'], 'core_unittest', 'view',
'unittest.php?id=' . $this->data['other']['sample'], 'bbb', $cmid);
}
}
@@ -0,0 +1,163 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Legacy log store tests.
*
* @package logstore_legacy
* @copyright 2014 Petr Skoda {@link http://skodak.org/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/fixtures/event.php');
class logstore_legacy_store_testcase extends advanced_testcase {
public function test_log_writing() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$course1 = $this->getDataGenerator()->create_course();
$module1 = $this->getDataGenerator()->create_module('resource', array('course' => $course1));
$course2 = $this->getDataGenerator()->create_course();
$module2 = $this->getDataGenerator()->create_module('resource', array('course' => $course2));
// Enable legacy logging plugin.
set_config('enabled_stores', 'logstore_legacy', 'tool_log');
set_config('loglegacy', 1, 'logstore_legacy');
$manager = get_log_manager(true);
$stores = $manager->get_readers();
$this->assertCount(1, $stores);
$this->assertEquals(array('logstore_legacy'), array_keys($stores));
$store = $stores['logstore_legacy'];
$this->assertInstanceOf('logstore_legacy\log\store', $store);
$this->assertInstanceOf('core\log\sql_select_reader', $store);
$this->assertTrue($store->is_logging());
$logs = $DB->get_records('log', array(), 'id ASC');
$this->assertCount(0, $logs);
$this->setCurrentTimeStart();
$this->setUser(0);
$event1 = \logstore_legacy\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)));
$event1->trigger();
$this->setUser($user1);
$event2 = \logstore_legacy\event\unittest_executed::create(
array('context' => context_course::instance($course2->id), 'other' => array('sample' => 6, 'xx' => 11)));
$event2->trigger();
$this->setUser($user2);
add_to_log($course1->id, 'xxxx', 'yyyy', '', '7', 0, 0);
//$this->assertDebuggingCalled();
add_to_log($course2->id, 'aaa', 'bbb', 'info.php', '666', $module2->cmid, $user1->id);
//$this->assertDebuggingCalled();
$logs = $DB->get_records('log', array(), 'id ASC');
$this->assertCount(4, $logs);
$log = array_shift($logs);
$this->assertNotEmpty($log->id);
$this->assertTimeCurrent($log->time);
$this->assertEquals(0, $log->userid);
$this->assertSame('0.0.0.0', $log->ip);
$this->assertEquals($course1->id, $log->course);
$this->assertSame('core_unittest', $log->module);
$this->assertEquals($module1->cmid, $log->cmid);
$this->assertSame('view', $log->action);
$this->assertSame('unittest.php?id=5', $log->url);
$this->assertSame('bbb', $log->info);
$oldlogid = $log->id;
$log = array_shift($logs);
$this->assertGreaterThan($oldlogid, $log->id);
$this->assertNotEmpty($log->id);
$this->assertTimeCurrent($log->time);
$this->assertEquals($user1->id, $log->userid);
$this->assertSame('0.0.0.0', $log->ip);
$this->assertEquals($course2->id, $log->course);
$this->assertSame('core_unittest', $log->module);
$this->assertEquals(0, $log->cmid);
$this->assertSame('view', $log->action);
$this->assertSame('unittest.php?id=6', $log->url);
$this->assertSame('bbb', $log->info);
$oldlogid = $log->id;
$log = array_shift($logs);
$this->assertGreaterThan($oldlogid, $log->id);
$this->assertNotEmpty($log->id);
$this->assertTimeCurrent($log->time);
$this->assertEquals($user2->id, $log->userid);
$this->assertSame('0.0.0.0', $log->ip);
$this->assertEquals($course1->id, $log->course);
$this->assertSame('xxxx', $log->module);
$this->assertEquals(0, $log->cmid);
$this->assertSame('yyyy', $log->action);
$this->assertSame('', $log->url);
$this->assertSame('7', $log->info);
$oldlogid = $log->id;
$log = array_shift($logs);
$this->assertGreaterThan($oldlogid, $log->id);
$this->assertNotEmpty($log->id);
$this->assertTimeCurrent($log->time);
$this->assertEquals($user1->id, $log->userid);
$this->assertSame('0.0.0.0', $log->ip);
$this->assertEquals($course2->id, $log->course);
$this->assertSame('aaa', $log->module);
$this->assertEquals($module2->cmid, $log->cmid);
$this->assertSame('bbb', $log->action);
$this->assertSame('info.php', $log->url);
$this->assertSame('666', $log->info);
// Test if disabling works.
set_config('enabled_stores', 'logstore_legacy', 'tool_log');
set_config('loglegacy', 0, 'logstore_legacy');
$manager = get_log_manager(true);
$stores = $manager->get_readers();
$store = $stores['logstore_legacy'];
$this->assertFalse($store->is_logging());
\logstore_legacy\event\unittest_executed::create(
array('context' => \context_system::instance(), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
add_to_log($course1->id, 'xxxx', 'yyyy', '', '7', 0, 0);
//$this->assertDebuggingCalled();
$this->assertEquals(4, $DB->count_records('log'));
// Another way to disable legacy completely.
set_config('enabled_stores', 'logstore_standard', 'tool_log');
set_config('loglegacy', 1, 'logstore_legacy');
get_log_manager(true);
\logstore_legacy\event\unittest_executed::create(
array('context' => \context_system::instance(), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
add_to_log($course1->id, 'xxxx', 'yyyy', '', '7', 0, 0);
//$this->assertDebuggingCalled();
$this->assertEquals(4, $DB->count_records('log'));
// Set everything back.
set_config('enabled_stores', '', 'tool_log');
set_config('loglegacy', 0, 'logstore_legacy');
get_log_manager(true);
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Legacy log reader.
*
* @package logstore_legacy
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2014011300; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2014011000; // Requires this Moodle version.
$plugin->component = 'logstore_legacy'; // Full name of the plugin (used for diagnostics).
@@ -0,0 +1,135 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Standard log reader/writer.
*
* @package logstore_standard
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_standard\log;
defined('MOODLE_INTERNAL') || die();
class store implements \tool_log\log\writer, \core\log\sql_internal_reader {
use \tool_log\helper\store,
\tool_log\helper\buffered_writer,
\tool_log\helper\reader;
/** @var string $logguests true if logging guest access */
protected $logguests;
public function __construct(\tool_log\log\manager $manager) {
$this->helper_setup($manager);
// Log everything before setting is saved for the first time.
$this->logguests = $this->get_config('logguests', 1);
}
/**
* Finally store the events into the database.
*
* @param \core\event\base[] $events
*/
protected function insert_events($events) {
global $DB;
$dataobj = array();
// Filter events.
foreach ($events as $event) {
if ((!CLI_SCRIPT or PHPUNIT_TEST) and !$this->logguests) {
// Always log inside CLI scripts because we do not login there.
if (!isloggedin() or isguestuser()) {
continue;
}
}
$data = $event->get_data();
$data['other'] = serialize($data['other']);
if (CLI_SCRIPT) {
$data['origin'] = 'cli';
$data['ip'] = null;
} else {
$data['origin'] = 'web';
$data['ip'] = getremoteaddr();
}
$data['realuserid'] = \core\session\manager::is_loggedinas() ? $_SESSION['USER']->realuser : null;
$dataobj[] = $data;
}
$DB->insert_records('logstore_standard_log', $dataobj);
}
public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum) {
global $DB;
$events = array();
$records = $DB->get_records_select('logstore_standard_log', $selectwhere, $params, $sort, '*', $limitfrom, $limitnum);
foreach ($records as $data) {
$extra = array('origin' => $data->origin, 'ip' => $data->ip, 'realuserid' => $data->realuserid);
$data = (array)$data;
$id = $data['id'];
$data['other'] = unserialize($data['other']);
if ($data['other'] === false) {
$data['other'] = array();
}
unset($data['origin']);
unset($data['ip']);
unset($data['realuserid']);
unset($data['id']);
$events[$id] = \core\event\base::restore($data, $extra);
}
return $events;
}
public function get_events_select_count($selectwhere, array $params) {
global $DB;
return $DB->count_records_select('logstore_standard_log', $selectwhere, $params);
}
public function get_internal_log_table_name() {
return 'logstore_standard_log';
}
public function cron() {
global $DB;
$loglifetime = $this->get_config('loglifetime', 0);
// NOTE: we should do this only once a day, new cron will deal with this.
if ($loglifetime > 0) {
$loglifetime = time() - ($loglifetime * 3600 * 24); // Value in days.
$DB->delete_records_select("logstore_standard_log", "timecreated < ?", array($loglifetime));
mtrace(" Deleted old log records from standard store.");
}
}
/**
* Are the new events appearing in the reader?
*
* @return bool true means new log events are being added, false means no new data will be added
*/
public function is_logging() {
// Only enabled stpres are queried,
// this means we can return true here unless store has some extra switch.
return true;
}
}
@@ -0,0 +1,38 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Defines the capabilities used by standard log store.
*
* @package logstore_standard
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$capabilities = array(
'logstore/standard:read' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'manager' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
),
),
);
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="admin/tool/log/store/standard/db" VERSION="20140211" COMMENT="XMLDB file for Moodle admin/tool/log/store/standard"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="logstore_standard_log" COMMENT="Standard log table">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="eventname" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="action" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="target" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="objecttable" TYPE="char" LENGTH="50" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="objectid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="crud" TYPE="char" LENGTH="1" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="edulevel" TYPE="int" LENGTH="1" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="contextlevel" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="contextinstanceid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="relateduserid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="other" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="origin" TYPE="char" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="cli, cron, ws, etc."/>
<FIELD NAME="ip" TYPE="char" LENGTH="45" NOTNULL="false" SEQUENCE="false" COMMENT="IP address"/>
<FIELD NAME="realuserid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="real user id when logged-in-as"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="timecreated" UNIQUE="false" FIELDS="timecreated"/>
<INDEX NAME="contextid-component" UNIQUE="false" FIELDS="contextid, component"/>
<INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid"/>
<INDEX NAME="eventname" UNIQUE="false" FIELDS="eventname"/>
<INDEX NAME="crud" UNIQUE="false" FIELDS="crud"/>
<INDEX NAME="edulevel" UNIQUE="false" FIELDS="edulevel"/>
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>
@@ -0,0 +1,28 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Log store lang strings.
*
* @package logstore_standard
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['buffersize'] = 'Write buffer size';
$string['pluginname'] = 'Standard log';
$string['pluginname_desc'] = 'A log plugin stores log entries in a Moodle database table.';
$string['standard:read'] = 'Read logs';
@@ -0,0 +1,53 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Standard log store settings.
*
* @package logstore_standard
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
if ($hassiteconfig) {
$settings->add(new admin_setting_configcheckbox('logstore_standard/logguests',
new lang_string('logguests', 'core_admin'),
new lang_string('logguests_help', 'core_admin'), 1));
$options = array(
0 => new lang_string('neverdeletelogs'),
1000 => new lang_string('numdays', '', 1000),
365 => new lang_string('numdays', '', 365),
180 => new lang_string('numdays', '', 180),
150 => new lang_string('numdays', '', 150),
120 => new lang_string('numdays', '', 120),
90 => new lang_string('numdays', '', 90),
60 => new lang_string('numdays', '', 60),
35 => new lang_string('numdays', '', 35),
10 => new lang_string('numdays', '', 10),
5 => new lang_string('numdays', '', 5),
2 => new lang_string('numdays', '', 2));
$settings->add(new admin_setting_configselect('logstore_standard/loglifetime',
new lang_string('loglifetime', 'core_admin'),
new lang_string('configloglifetime', 'core_admin'), 0, $options));
$settings->add(new admin_setting_configtext('logstore_standard/buffersize',
get_string('buffersize', 'logstore_standard'),
'', '50', PARAM_INT));
}
+47
View File
@@ -0,0 +1,47 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Fixtures for standard log storage testing.
*
* @package logstore_standard
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_standard\event;
defined('MOODLE_INTERNAL') || die();
class unittest_executed extends \core\event\base {
public static function get_name() {
return 'xxx';
}
public function get_description() {
return 'yyy';
}
protected function init() {
$this->data['crud'] = 'u';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
}
public function get_url() {
return new \moodle_url('/somepath/somefile.php', array('id' => $this->data['other']['sample']));
}
}
@@ -0,0 +1,193 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Standard log store tests.
*
* @package logstore_standard
* @copyright 2014 Petr Skoda {@link http://skodak.org/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/fixtures/event.php');
class logstore_standard_store_testcase extends advanced_testcase {
public function test_log_writing() {
global $DB;
$this->resetAfterTest();
$this->preventResetByRollback(); // Logging waits till the transaction gets committed.
$this->setAdminUser();
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$course1 = $this->getDataGenerator()->create_course();
$module1 = $this->getDataGenerator()->create_module('resource', array('course' => $course1));
$course2 = $this->getDataGenerator()->create_course();
$module2 = $this->getDataGenerator()->create_module('resource', array('course' => $course2));
// Test all plugins are disabled by this command.
set_config('enabled_stores', '', 'tool_log');
$manager = get_log_manager(true);
$stores = $manager->get_readers();
$this->assertCount(0, $stores);
// Enable logging plugin.
set_config('enabled_stores', 'logstore_standard', 'tool_log');
set_config('buffersize', 0, 'logstore_standard');
set_config('logguests', 1, 'logstore_standard');
$manager = get_log_manager(true);
$stores = $manager->get_readers();
$this->assertCount(1, $stores);
$this->assertEquals(array('logstore_standard'), array_keys($stores));
$store = $stores['logstore_standard'];
$this->assertInstanceOf('logstore_standard\log\store', $store);
$this->assertInstanceOf('tool_log\log\writer', $store);
$this->assertTrue($store->is_logging());
$logs = $DB->get_records('logstore_standard_log', array(), 'id ASC');
$this->assertCount(0, $logs);
$this->setCurrentTimeStart();
$this->setUser(0);
$event1 = \logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)));
$event1->trigger();
$logs = $DB->get_records('logstore_standard_log', array(), 'id ASC');
$this->assertCount(1, $logs);
$log1 = reset($logs);
unset($log1->id);
$log1->other = unserialize($log1->other);
$log1 = (array)$log1;
$data = $event1->get_data();
$data['origin'] = 'cli';
$data['ip'] = null;
$data['realuserid'] = null;
$this->assertEquals($data, $log1);
$this->setAdminUser();
\core\session\manager::loginas($user1->id, context_system::instance());
$this->assertEquals(2, $DB->count_records('logstore_standard_log'));
$event2 = \logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module2->cmid), 'other' => array('sample' => 6, 'xx' => 9)));
$event2->trigger();
$_SESSION['SESSION'] = new \stdClass();
$this->setUser(0);
$this->assertFalse(\core\session\manager::is_loggedinas());
$logs = $DB->get_records('logstore_standard_log', array(), 'id ASC');
$this->assertCount(3, $logs);
array_shift($logs);
$log2 = array_shift($logs);
$this->assertSame('\core\event\user_loggedinas', $log2->eventname);
$log3 = array_shift($logs);
unset($log3->id);
$log3->other = unserialize($log3->other);
$log3 = (array)$log3;
$data = $event2->get_data();
$data['origin'] = 'cli';
$data['ip'] = null;
$data['realuserid'] = 2;
$this->assertEquals($data, $log3);
// Test table exists.
$tablename = $store->get_internal_log_table_name();
$this->assertTrue($DB->get_manager()->table_exists($tablename));
// Test reading.
$this->assertSame(3, $store->get_events_select_count('', array()));
$events = $store->get_events_select('', array(), 'id', 0, 0);
$this->assertCount(3, $events);
$resev1 = array_shift($events);
array_shift($events);
$resev2 = array_shift($events);
$this->assertEquals($event1->get_data(), $resev1->get_data());
$this->assertEquals($event2->get_data(), $resev2->get_data());
// Test buffering.
set_config('buffersize', 3, 'logstore_standard');
$manager = get_log_manager(true);
$stores = $manager->get_readers();
/** @var \logstore_standard\log\store $store */
$store = $stores['logstore_standard'];
$DB->delete_records('logstore_standard_log');
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(0, $DB->count_records('logstore_standard_log'));
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(0, $DB->count_records('logstore_standard_log'));
$store->flush();
$this->assertEquals(2, $DB->count_records('logstore_standard_log'));
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(2, $DB->count_records('logstore_standard_log'));
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(2, $DB->count_records('logstore_standard_log'));
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(5, $DB->count_records('logstore_standard_log'));
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(5, $DB->count_records('logstore_standard_log'));
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(5, $DB->count_records('logstore_standard_log'));
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(8, $DB->count_records('logstore_standard_log'));
// Test guest logging setting.
set_config('logguests', 0, 'logstore_standard');
set_config('buffersize', 0, 'logstore_standard');
get_log_manager(true);
$DB->delete_records('logstore_standard_log');
get_log_manager(true);
$this->setUser(null);
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(0, $DB->count_records('logstore_standard_log'));
$this->setGuestUser();
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(0, $DB->count_records('logstore_standard_log'));
$this->setUser($user1);
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(1, $DB->count_records('logstore_standard_log'));
$this->setUser($user2);
\logstore_standard\event\unittest_executed::create(
array('context' => context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(2, $DB->count_records('logstore_standard_log'));
set_config('enabled_stores', '', 'tool_log');
get_log_manager(true);
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Standard log store.
*
* @package logstore_standard
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2014021100; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2014012400; // Requires this Moodle version.
$plugin->component = 'logstore_standard'; // Full name of the plugin (used for diagnostics).
+98
View File
@@ -0,0 +1,98 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Logging store management.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once('../../../config.php');
require_once($CFG->libdir . '/adminlib.php');
$action = required_param('action', PARAM_ALPHANUMEXT);
$enrol = required_param('store', PARAM_PLUGIN);
$PAGE->set_url('/admin/tool/log/stores.php');
$PAGE->set_context(context_system::instance());
require_login();
require_capability('moodle/site:config', context_system::instance());
require_sesskey();
$all = \tool_log\log\manager::get_store_plugins();
$enabled = get_config('tool_log', 'enabled_stores');
if (!$enabled) {
$enabled = array();
} else {
$enabled = array_flip(explode(',', $enabled));
}
$return = new moodle_url('/admin/settings.php', array('section' => 'managelogging'));
$syscontext = context_system::instance();
switch ($action) {
case 'disable':
unset($enabled[$enrol]);
set_config('enabled_stores', implode(',', array_keys($enabled)), 'tool_log');
break;
case 'enable':
if (!isset($all[$enrol])) {
break;
}
$enabled = array_keys($enabled);
$enabled[] = $enrol;
set_config('enabled_stores', implode(',', $enabled), 'tool_log');
break;
case 'up':
if (!isset($enabled[$enrol])) {
break;
}
$enabled = array_keys($enabled);
$enabled = array_flip($enabled);
$current = $enabled[$enrol];
if ($current == 0) {
break; // Already at the top.
}
$enabled = array_flip($enabled);
$enabled[$current] = $enabled[$current - 1];
$enabled[$current - 1] = $enrol;
set_config('enabled_stores', implode(',', $enabled), 'tool_log');
break;
case 'down':
if (!isset($enabled[$enrol])) {
break;
}
$enabled = array_keys($enabled);
$enabled = array_flip($enabled);
$current = $enabled[$enrol];
if ($current == count($enabled) - 1) {
break; // Already at the end.
}
$enabled = array_flip($enabled);
$enabled[$current] = $enabled[$current + 1];
$enabled[$current + 1] = $enrol;
set_config('enabled_stores', implode(',', $enabled), 'tool_log');
break;
}
redirect($return);
+71
View File
@@ -0,0 +1,71 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Log manager and log API tests.
*
* @package tool_log
* @copyright 2014 Petr Skoda {@link http://skodak.org/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die;
class tool_log_manager_testcase extends advanced_testcase {
public function test_get_log_manager() {
global $CFG;
$this->resetAfterTest();
$manager = get_log_manager();
$this->assertInstanceOf('core\log\manager', $manager);
$stores = $manager->get_readers();
$this->assertInternalType('array', $stores);
$this->assertCount(0, $stores);
$this->assertFileExists("$CFG->dirroot/$CFG->admin/tool/log/store/standard/version.php");
$this->assertFileExists("$CFG->dirroot/$CFG->admin/tool/log/store/legacy/version.php");
set_config('enabled_stores', 'logstore_standard,logstore_legacy', 'tool_log');
$manager = get_log_manager(true);
$this->assertInstanceOf('core\log\manager', $manager);
$stores = $manager->get_readers();
$this->assertInternalType('array', $stores);
$this->assertCount(2, $stores);
foreach ($stores as $key => $store) {
$this->assertInternalType('string', $key);
$this->assertInstanceOf('core\log\sql_select_reader', $store);
}
$stores = $manager->get_readers('core\log\sql_internal_reader');
$this->assertInternalType('array', $stores);
$this->assertCount(1, $stores);
foreach ($stores as $key => $store) {
$this->assertInternalType('string', $key);
$this->assertSame('logstore_standard', $key);
$this->assertInstanceOf('core\log\sql_internal_reader', $store);
}
$stores = $manager->get_readers('core\log\sql_select_reader');
$this->assertInternalType('array', $stores);
$this->assertCount(2, $stores);
foreach ($stores as $key => $store) {
$this->assertInternalType('string', $key);
$this->assertInstanceOf('core\log\sql_select_reader', $store);
}
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Default log manager.
*
* @package tool_log
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2014011300; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2014011000; // Requires this Moodle version.
$plugin->component = 'tool_log'; // Full name of the plugin (used for diagnostics).
-1
View File
@@ -1007,7 +1007,6 @@ $string['taskcontextcleanup'] = 'Cleanup contexts';
$string['taskcreatecontexts'] = 'Create missing contexts';
$string['taskdeletecachetext'] = 'Delete old text cache records';
$string['taskdeleteincompleteusers'] = 'Delete incomplete users';
$string['taskdeletelogs'] = 'Delete logs';
$string['taskdeleteunconfirmedusers'] = 'Delete unconfirmed users';
$string['taskeventscron'] = 'Background processing for events';
$string['taskfiletrashcleanup'] = 'Cleanup files in trash';
+5
View File
@@ -562,6 +562,10 @@ $string['edittitleinstructions'] = 'Escape to cancel, Enter when finished';
$string['editthisactivity'] = 'Edit this activity';
$string['editthiscategory'] = 'Edit this category';
$string['edituser'] = 'Edit user accounts';
$string['edulevelother'] = 'Other';
$string['edulevelteacher'] = 'Teaching';
$string['edulevelparticipating'] = 'Participating';
$string['edulevel'] = 'Educational level';
$string['email'] = 'Email address';
$string['emailalreadysent'] = 'A password reset email has already been sent. Please check your email.';
$string['emailactive'] = 'Email activated';
@@ -734,6 +738,7 @@ $string['eventcourseupdated'] = 'Course updated';
$string['eventcoursesectionupdated'] = ' Course section updated';
$string['eventcoursemoduleinstancelistviewed'] = 'Course module instance list viewed';
$string['eventemailfailed'] = 'Email failed to send';
$string['eventname'] = 'Event name';
$string['eventusercreated'] = 'User created';
$string['eventuserdeleted'] = 'User deleted';
$string['eventuserlistviewed'] = 'User list viewed';
+90 -1
View File
@@ -347,6 +347,92 @@ abstract class base implements \IteratorAggregate {
return $event;
}
/**
* Create fake event from legacy log data.
*
* @param \stdClass $legacy
* @return base
*/
public static final function restore_legacy($legacy) {
$classname = get_called_class();
/** @var base $event */
$event = new $classname();
$event->restored = true;
$event->triggered = true;
$event->dispatched = true;
$context = false;
$component = 'legacy';
if ($legacy->cmid) {
$context = \context_module::instance($legacy->cmid, IGNORE_MISSING);
$component = 'mod_'.$legacy->module;
} else if ($legacy->course) {
$context = \context_course::instance($legacy->course, IGNORE_MISSING);
}
if (!$context) {
$context = \context_system::instance();
}
$event->data = array();
$event->data['eventname'] = $legacy->module.'_'.$legacy->action;
$event->data['component'] = $component;
$event->data['action'] = $legacy->action;
$event->data['target'] = null;
$event->data['objecttable'] = null;
$event->data['objectid'] = null;
if (strpos($legacy->action, 'view') !== false) {
$event->data['crud'] = 'r';
} else if (strpos($legacy->action, 'print') !== false) {
$event->data['crud'] = 'r';
} else if (strpos($legacy->action, 'update') !== false) {
$event->data['crud'] = 'u';
} else if (strpos($legacy->action, 'hide') !== false) {
$event->data['crud'] = 'u';
} else if (strpos($legacy->action, 'move') !== false) {
$event->data['crud'] = 'u';
} else if (strpos($legacy->action, 'write') !== false) {
$event->data['crud'] = 'u';
} else if (strpos($legacy->action, 'tag') !== false) {
$event->data['crud'] = 'u';
} else if (strpos($legacy->action, 'remove') !== false) {
$event->data['crud'] = 'u';
} else if (strpos($legacy->action, 'delete') !== false) {
$event->data['crud'] = 'p';
} else if (strpos($legacy->action, 'create') !== false) {
$event->data['crud'] = 'c';
} else if (strpos($legacy->action, 'post') !== false) {
$event->data['crud'] = 'c';
} else if (strpos($legacy->action, 'add') !== false) {
$event->data['crud'] = 'c';
} else {
// End of guessing...
$event->data['crud'] = 'r';
}
$event->data['edulevel'] = $event::LEVEL_OTHER;
$event->data['contextid'] = $context->id;
$event->data['contextlevel'] = $context->contextlevel;
$event->data['contextinstanceid'] = $context->instanceid;
$event->data['userid'] = ($legacy->userid ? $legacy->userid : null);
$event->data['courseid'] = ($legacy->course ? $legacy->course : null);
$event->data['relateduserid'] = ($legacy->userid ? $legacy->userid : null);
$event->data['timecreated'] = $legacy->time;
$event->logextra = array();
if ($legacy->ip) {
$event->logextra['origin'] = 'web';
$event->logextra['ip'] = $legacy->ip;
} else {
$event->logextra['origin'] = 'cli';
$event->logextra['ip'] = null;
}
$event->logextra['realuserid'] = null;
$event->data['other'] = (array)$legacy;
return $event;
}
/**
* Returns event context.
* @return \context
@@ -504,7 +590,10 @@ abstract class base implements \IteratorAggregate {
if (isset($CFG->loglifetime) and $CFG->loglifetime != -1) {
if ($data = $this->get_legacy_logdata()) {
call_user_func_array('add_to_log', $data);
$manager = get_log_manager();
if (method_exists($manager, 'legacy_add_to_log')) {
call_user_func_array(array($manager, 'legacy_add_to_log'), $data);
}
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Dummy storage manager, returns nothing.
* used when no other manager available.
*
* @package core
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\log;
defined('MOODLE_INTERNAL') || die();
class dummy_manager implements manager {
public function get_readers($interface = null) {
return array();
}
public function dispose() {
}
}
+52
View File
@@ -0,0 +1,52 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Log storage manager interface.
*
* @package core
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\log;
defined('MOODLE_INTERNAL') || die();
/**
* Interface describing log readers.
*
* This is intended for reports, use get_log_manager() to get
* the configured instance.
*
* @package core\log
*/
interface manager {
/**
* Return list of available log readers.
*
* @param string $interface All returned readers must implement this interface.
*
* @return \core\log\reader[]
*/
public function get_readers($interface = null);
/**
* Dispose all initialised stores.
* @return void
*/
public function dispose();
}
@@ -15,44 +15,44 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* A scheduled task.
* Log storage reader interface.
*
* @package core
* @copyright 2013 onwards Martin Dougiamas http://dougiamas.com
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\task;
/**
* Simple task to delete old log records.
*/
class delete_logs_task extends scheduled_task {
namespace core\log;
defined('MOODLE_INTERNAL') || die();
interface reader {
/**
* Get a descriptive name for this task (shown to admins).
* Localised name of the reader.
*
* To be used in selection for in reports.
*
* @return string
*/
public function get_name() {
return get_string('taskdeletelogs', 'admin');
}
public function get_name();
/**
* Do the job.
* Throw exceptions on errors (the job will be retried).
* Longer description of the log data source.
* @return string
*/
public function execute() {
global $CFG, $DB;
public function get_description();
$timenow = time();
// Delete old logs to save space.
// Value in days.
if (!empty($CFG->loglifetime)) {
$loglifetime = $timenow - ($CFG->loglifetime * 3600 * 24);
$DB->delete_records_select("log", "time < ?", array($loglifetime));
}
}
/**
* Can the current user access this store?
* @param \context $context
* @return bool
*/
public function can_access(\context $context);
/**
* Are the new events appearing in the reader?
*
* @return bool true means new log events are being added, false means no new data will be added
*/
public function is_logging();
}
+41
View File
@@ -0,0 +1,41 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Log storage sql reader interface.
*
* @package core
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\log;
defined('MOODLE_INTERNAL') || die();
interface sql_internal_reader extends sql_select_reader {
/**
* Returns name of the table or database view that
* holds the log data in standardised format.
*
* Note: this table must be used for reading only,
* it is strongly recommended to use this in complex reports only.
*
* @return string
*/
public function get_internal_log_table_name();
}
+50
View File
@@ -0,0 +1,50 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Log storage reader interface.
*
* @package core
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\log;
defined('MOODLE_INTERNAL') || die();
interface sql_select_reader extends reader {
/**
* Fetch records using given criteria.
*
* @param string $selectwhere
* @param array $params
* @param string $sort
* @param int $limitfrom
* @param int $limitnum
* @return \core\event\base[]
*/
public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum);
/**
* Return number of events matching given criteria.
*
* @param string $selectwhere
* @param array $params
* @return int
*/
public function get_events_select_count($selectwhere, array $params);
}
+5 -1
View File
@@ -1028,6 +1028,10 @@ class core_plugin_manager {
'local' => array(
),
'logstore' => array(
'database', 'legacy', 'standard',
),
'message' => array(
'email', 'jabber', 'popup'
),
@@ -1117,7 +1121,7 @@ class core_plugin_manager {
'tool' => array(
'assignmentupgrade', 'behat', 'capability', 'customlang',
'dbtransfer', 'generator', 'health', 'innodb', 'installaddon',
'langimport', 'multilangupgrade', 'phpunit', 'profiling',
'langimport', 'log', 'multilangupgrade', 'phpunit', 'profiling',
'qeupgradehelper', 'replace', 'spamcleaner', 'task', 'timezoneimport',
'unittest', 'uploadcourse', 'uploaduser', 'unsuproles', 'xmldb'
),
+35 -103
View File
@@ -1583,6 +1583,41 @@ function coursemodule_visible_for_user($cm, $userid=0) {
/// LOG FUNCTIONS /////////////////////////////////////////////////////
/**
* Get instance of log manager.
*
* @param bool $forcereload
* @return \core\log\manager
*/
function get_log_manager($forcereload = false) {
/** @var \core\log\manager $singleton */
static $singleton = null;
if ($forcereload and isset($singleton)) {
$singleton->dispose();
$singleton = null;
}
if (isset($singleton)) {
return $singleton;
}
$classname = '\tool_log\log\manager';
if (defined('LOG_MANAGER_CLASS')) {
$classname = LOG_MANAGER_CLASS;
}
if (!class_exists($classname)) {
if (!empty($classname)) {
debugging("Cannot find log manager class '$classname'.", DEBUG_DEVELOPER);
}
$classname = '\core\log\dummy_manager';
}
$singleton = new $classname();
return $singleton;
}
/**
* Add an entry to the config log table.
*
@@ -1613,109 +1648,6 @@ function add_to_config_log($name, $oldvalue, $value, $plugin) {
$DB->insert_record('config_log', $log);
}
/**
* Add an entry to the log table.
*
* Add an entry to the log table. These are "action" focussed rather
* than web server hits, and provide a way to easily reconstruct what
* any particular student has been doing.
*
* @package core
* @category log
* @global moodle_database $DB
* @global stdClass $CFG
* @global stdClass $USER
* @uses SITEID
* @uses DEBUG_DEVELOPER
* @uses DEBUG_ALL
* @param int $courseid The course id
* @param string $module The module name e.g. forum, journal, resource, course, user etc
* @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify.
* @param string $url The file and parameters used to see the results of the action
* @param string $info Additional description information
* @param string $cm The course_module->id if there is one
* @param string $user If log regards $user other than $USER
* @return void
*/
function add_to_log($courseid, $module, $action, $url='', $info='', $cm=0, $user=0) {
// Note that this function intentionally does not follow the normal Moodle DB access idioms.
// This is for a good reason: it is the most frequently used DB update function,
// so it has been optimised for speed.
global $DB, $CFG, $USER;
if ($cm === '' || is_null($cm)) { // postgres won't translate empty string to its default
$cm = 0;
}
if ($user) {
$userid = $user;
} else {
if (\core\session\manager::is_loggedinas()) { // Don't log
return;
}
$userid = empty($USER->id) ? '0' : $USER->id;
}
if (isset($CFG->logguests) and !$CFG->logguests) {
if (!$userid or isguestuser($userid)) {
return;
}
}
$REMOTE_ADDR = getremoteaddr();
$timenow = time();
$info = $info;
if (!empty($url)) { // could break doing html_entity_decode on an empty var.
$url = html_entity_decode($url, ENT_QUOTES, 'UTF-8');
} else {
$url = '';
}
// Restrict length of log lines to the space actually available in the
// database so that it doesn't cause a DB error. Log a warning so that
// developers can avoid doing things which are likely to cause this on a
// routine basis.
if(!empty($info) && core_text::strlen($info)>255) {
$info = core_text::substr($info,0,252).'...';
debugging('Warning: logged very long info',DEBUG_DEVELOPER);
}
// If the 100 field size is changed, also need to alter print_log in course/lib.php
if(!empty($url) && core_text::strlen($url)>100) {
$url = core_text::substr($url,0,97).'...';
debugging('Warning: logged very long URL',DEBUG_DEVELOPER);
}
if (defined('MDL_PERFDB')) { global $PERF ; $PERF->logwrites++;};
$log = array('time'=>$timenow, 'userid'=>$userid, 'course'=>$courseid, 'ip'=>$REMOTE_ADDR, 'module'=>$module,
'cmid'=>$cm, 'action'=>$action, 'url'=>$url, 'info'=>$info);
try {
$DB->insert_record_raw('log', $log, false);
} catch (dml_exception $e) {
debugging('Error: Could not insert a new entry to the Moodle log. '. $e->error, DEBUG_ALL);
// MDL-11893, alert $CFG->supportemail if insert into log failed
if ($CFG->supportemail and empty($CFG->noemailever)) {
// email_to_user is not usable because email_to_user tries to write to the logs table,
// and this will get caught in an infinite loop, if disk is full
$site = get_site();
$subject = 'Insert into log failed at your moodle site '.$site->fullname;
$message = "Insert into log table failed at ". date('l dS \of F Y h:i:s A') .".\n It is possible that your disk is full.\n\n";
$message .= "The failed query parameters are:\n\n" . var_export($log, true);
$lasttime = get_config('admin', 'lastloginserterrormail');
if(empty($lasttime) || time() - $lasttime > 60*60*24) { // limit to 1 email per day
//using email directly rather than messaging as they may not be able to log in to access a message
mail($CFG->supportemail, $subject, $message);
set_config('lastloginserterrormail', time(), 'admin');
}
}
}
}
/**
* Store user last access times - called when use enters a course or site
*
-9
View File
@@ -59,15 +59,6 @@ $tasks = array(
'dayofweek' => '*',
'month' => '*'
),
array(
'classname' => 'core\task\delete_logs_task',
'blocking' => 0,
'minute' => '0',
'hour' => '2',
'day' => '*',
'dayofweek' => '*',
'month' => '*'
),
array(
'classname' => 'core\task\backup_cleanup_task',
'blocking' => 0,
+30 -14
View File
@@ -30,6 +30,36 @@
defined('MOODLE_INTERNAL') || die();
/**
* Add an entry to the log table.
*
* Add an entry to the log table. These are "action" focussed rather
* than web server hits, and provide a way to easily reconstruct what
* any particular student has been doing.
*
* @deprecated since 2.7 use new events instead
*
* @param int $courseid The course id
* @param string $module The module name e.g. forum, journal, resource, course, user etc
* @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify.
* @param string $url The file and parameters used to see the results of the action
* @param string $info Additional description information
* @param int $cm The course_module->id if there is one
* @param int|stdClass $user If log regards $user other than $USER
* @return void
*/
function add_to_log($courseid, $module, $action, $url='', $info='', $cm=0, $user=0) {
// TODO: Uncomment after all add_to_log() are removed from standard distribution - ideally before 2.7 release.
//debugging('ideally all add_to_log() calls should be replaced() with new events', DEBUG_DEVELOPER);
// This is a nasty hack that allows us to put all the legacy stuff into legacy storage,
// this way we may move all the legacy settings there too.
$manager = get_log_manager();
if (method_exists($manager, 'legacy_add_to_log')) {
$manager->legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user);
}
}
/**
* Adds a file upload to the log table so that clam can resolve the filename to the user later if necessary
*
@@ -4318,17 +4348,3 @@ function can_use_html_editor() {
debugging('can_use_html_editor has been deprecated please update your code to assume it returns true.', DEBUG_DEVELOPER);
return true;
}
/**
* Returns whether ajax is enabled/allowed or not.
* This function is deprecated and always returns true.
*
* @param array $unused - not used any more.
* @return bool
* @deprecated since 2.7 MDL-33099 - please do not use this function any more.
* @todo MDL-44088 This will be removed in Moodle 2.9.
*/
function ajaxenabled(array $browsers = null) {
debugging('ajaxenabled() is deprecated - please update your code to assume it returns true.', DEBUG_DEVELOPER);
return true;
}
+3
View File
@@ -384,6 +384,9 @@ class phpunit_util extends testing_util {
install_cli_database($options, false);
// Disable all logging for performance and sanity reasons.
set_config('enabled_stores', '', 'tool_log');
// install timezone info
$timezones = get_records_csv($CFG->libdir.'/timezone.txt', 'timezone');
update_timezone_records($timezones);
+10 -29
View File
@@ -29,17 +29,6 @@ require_once(__DIR__.'/fixtures/event_fixtures.php');
class core_event_testcase extends advanced_testcase {
protected function setUp() {
global $CFG;
// No need to always modify log table here.
$CFG->loglifetime = '-1';
}
protected function tearDown() {
global $CFG;
$CFG->loglifetime = '0';
}
public function test_event_properties() {
global $USER;
@@ -469,7 +458,7 @@ class core_event_testcase extends advanced_testcase {
}
public function test_legacy() {
global $DB;
global $DB, $CFG;
$this->resetAfterTest(true);
@@ -513,22 +502,7 @@ class core_event_testcase extends advanced_testcase {
$this->assertSame(array(1, 5), \core_tests\event\unittest_observer::$event[2]);
$logs = $DB->get_records('log', array(), 'id ASC');
$this->assertCount(3, $logs);
$log = array_shift($logs);
$this->assertEquals(1, $log->course);
$this->assertSame('core_unittest', $log->module);
$this->assertSame('view', $log->action);
$log = array_shift($logs);
$this->assertEquals(2, $log->course);
$this->assertSame('core_unittest', $log->module);
$this->assertSame('view', $log->action);
$log = array_shift($logs);
$this->assertEquals(3, $log->course);
$this->assertSame('core_unittest', $log->module);
$this->assertSame('view', $log->action);
$this->assertCount(0, $logs);
}
public function test_restore_event() {
@@ -566,6 +540,8 @@ class core_event_testcase extends advanced_testcase {
}
public function test_trigger_problems() {
$this->resetAfterTest(true);
$event = \core_tests\event\unittest_executed::create(array('courseid'=>1, 'context'=>\context_system::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
$event->trigger();
try {
@@ -597,6 +573,8 @@ class core_event_testcase extends advanced_testcase {
}
public function test_bad_events() {
$this->resetAfterTest(true);
try {
$event = \core_tests\event\unittest_executed::create(array('courseid'=>1, 'other'=>array('sample'=>5, 'xx'=>10)));
$this->fail('Exception expected when context and contextid missing');
@@ -654,7 +632,8 @@ class core_event_testcase extends advanced_testcase {
}
public function test_problematic_events() {
global $CFG;
$this->resetAfterTest(true);
$event1 = \core_tests\event\problematic_event1::create(array('context'=>\context_system::instance()));
$this->assertDebuggingNotCalled();
$this->assertNull($event1->xxx);
@@ -703,6 +682,8 @@ class core_event_testcase extends advanced_testcase {
public function test_record_snapshots() {
global $DB;
$this->resetAfterTest(true);
$event = \core_tests\event\unittest_executed::create(array('courseid'=>1, 'context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
$course1 = $DB->get_record('course', array('id'=>1));
$this->assertNotEmpty($course1);
+1 -1
View File
@@ -45,7 +45,7 @@ class unittest_executed extends \core\event\base {
}
public function get_url() {
return new moodle_url('/somepath/somefile.php', array('id'=>$this->data['other']['sample']));
return new \moodle_url('/somepath/somefile.php', array('id'=>$this->data['other']['sample']));
}
public static function get_legacy_eventname() {