Skip to content

Commit

Permalink
MDL-49399 task: Add task logging API
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewnicols committed Jan 16, 2019
1 parent af540d4 commit 4b71596
Show file tree
Hide file tree
Showing 17 changed files with 1,761 additions and 3 deletions.
40 changes: 39 additions & 1 deletion admin/settings/server.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page


// "systempaths" settingpage
$temp = new admin_settingpage('systempaths', new lang_string('systempaths','admin'));
$temp->add(new admin_setting_configexecutable('pathtophp', new lang_string('pathtophp', 'admin'),
Expand Down Expand Up @@ -212,6 +211,45 @@
$ADMIN->add('server', $temp);


$ADMIN->add('server', new admin_category('taskconfig', new lang_string('taskadmintitle', 'admin')));
$temp = new admin_settingpage('tasklogging', new lang_string('tasklogging','admin'));
$temp->add(
new admin_setting_configselect(
'task_logmode',
new lang_string('task_logmode', 'admin'),
new lang_string('task_logmode_desc', 'admin'),
\core\task\logmanager::MODE_ALL,
[
\core\task\logmanager::MODE_ALL => new lang_string('task_logmode_all', 'admin'),
\core\task\logmanager::MODE_FAILONLY => new lang_string('task_logmode_failonly', 'admin'),
\core\task\logmanager::MODE_NONE => new lang_string('task_logmode_none', 'admin'),
]
)
);

if (\core\task\logmanager::uses_standard_settings()) {
$temp->add(
new admin_setting_configduration(
'task_logretention',
new \lang_string('task_logretention', 'admin'),
new \lang_string('task_logretention_desc', 'admin'),
28 * DAYSECS
)
);

$temp->add(
new admin_setting_configtext(
'task_logretainruns',
new \lang_string('task_logretainruns', 'admin'),
new \lang_string('task_logretainruns_desc', 'admin'),
20,
PARAM_INT
)
);

}
$ADMIN->add('taskconfig', $temp);

// E-mail settings.
$ADMIN->add('server', new admin_category('email', new lang_string('categoryemail', 'admin')));

Expand Down
1 change: 1 addition & 0 deletions admin/tool/task/cli/schedule_task.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
$predbqueries = $DB->perf_get_queries();
$pretime = microtime(true);

\core\task\logmanager::start_logging($task);
$fullname = $task->get_name() . ' (' . get_class($task) . ')';
mtrace('Execute scheduled task: ' . $fullname);
// NOTE: it would be tricky to move this code to \core\task\manager class,
Expand Down
9 changes: 9 additions & 0 deletions config-dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,15 @@
// on a shared file system that supports locking.
// $CFG->lock_file_root = $CFG->dataroot . '/lock';
//
//
// Alternative task logging.
// Since Moodle 3.7 the output of al scheduled and adhoc tasks is stored in the database and it is possible to use an
// alternative task logging mechanism.
// To set the alternative task logging mechanism in config.php you can use the following settings, providing the
// alternative class name that will be auto-loaded.
//
// $CFG->task_log_class = '\\local_mytasklogger\\logger';
//
// Moodle 2.9 allows administrators to customise the list of supported file types.
// To add a new filetype or override the definition of an existing one, set the
// customfiletypes variable like this:
Expand Down
13 changes: 13 additions & 0 deletions lang/en/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,16 @@
$string['tabselectedtofront'] = 'On tables with tabs, should the row with the currently selected tab be placed at the front';
$string['tabselectedtofronttext'] = 'Bring selected tab row to front';
$string['testsiteupgradewarning'] = 'You are currently using the {$a} test site, to upgrade it properly use the command line interface tool';
$string['task_logmode'] = 'When to log';
$string['task_logmode_desc'] = 'You can choose when you wish task logging to take place. By default logs are always captured. You can disable logging entirely, or change to only log tasks which fail.';
$string['task_logmode_none'] = 'Do not log anything';
$string['task_logmode_all'] = 'Store the log output of all jobs';
$string['task_logmode_failonly'] = 'Only store logs for jobs which fail';
$string['task_logretention'] = 'Retention period';
$string['task_logretention_desc'] = 'The maximum period that logs should be kept for. This setting interacts with the \'Retain runs\' setting: whichever is reached first will apply';
$string['task_logretainruns'] = 'Retain runs';
$string['task_logretainruns_desc'] = 'The number of runs of each task to retain. This setting interacts with the \'Retention period\' setting: whichever is reached first will apply.';
$string['taskadmintitle'] = 'Tasks';
$string['taskanalyticscleanup'] = 'Analytics cleanup';
$string['taskautomatedbackup'] = 'Automated backups';
$string['taskbackupcleanup'] = 'Clean backup tables and logs';
Expand All @@ -1176,6 +1186,7 @@
$string['taskcompletionregular'] = 'Calculate regular completion data';
$string['taskcompletiondaily'] = 'Completion mark as started';
$string['taskcontextcleanup'] = 'Cleanup contexts';
$string['tasklogging'] = 'Task log configuration';
$string['taskcreatecontexts'] = 'Create missing contexts';
$string['taskdeletecachetext'] = 'Delete old text cache records';
$string['taskdeleteincompleteusers'] = 'Delete incomplete users';
Expand All @@ -1186,6 +1197,8 @@
$string['taskglobalsearchoptimize'] = 'Global search index optimization';
$string['taskgradecron'] = 'Background processing for gradebook';
$string['tasklegacycron'] = 'Legacy cron processing for plugins';
$string['tasklogcleanup'] = 'Cleanup of task logs';
$string['tasklogs'] = 'Task logs';
$string['taskmessagingcleanup'] = 'Background processing for messaging';
$string['taskpasswordresetcleanup'] = 'Cleanup password reset attempts';
$string['taskplagiarismcron'] = 'Background processing for legacy cron in plagiarism plugins';
Expand Down
144 changes: 144 additions & 0 deletions lib/classes/task/database_logger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?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/>.

/**
* Database logger for task logging.
*
* @package core
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\task;

defined('MOODLE_INTERNAL') || die();

/**
* Database logger for task logging.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class database_logger implements task_logger {

/** @var int Type constant for a scheduled task */
const TYPE_SCHEDULED = 0;

/** @var int Type constant for an adhoc task */
const TYPE_ADHOC = 1;

/**
* Whether the task is configured and ready to log.
*
* @return bool
*/
public static function is_configured() : bool {
return true;
}

/**
* Store the log for the specified task.
*
* @param task_base $task The task that the log belongs to.
* @param string $logpath The path to the log on disk
* @param bool $failed Whether the task failed
* @param int $dbreads The number of DB reads
* @param int $dbwrites The number of DB writes
* @param float $timestart The start time of the task
* @param float $timeend The end time of the task
*/
public static function store_log_for_task(task_base $task, string $logpath, bool $failed,
int $dbreads, int $dbwrites, float $timestart, float $timeend) {
global $DB;

// Write this log to the database.
$logdata = (object) [
'type' => is_a($task, scheduled_task::class) ? self::TYPE_SCHEDULED : self::TYPE_ADHOC,
'component' => $task->get_component(),
'classname' => get_class($task),
'userid' => 0,
'timestart' => $timestart,
'timeend' => $timeend,
'dbreads' => $dbreads,
'dbwrites' => $dbwrites,
'result' => (int) $failed,
'output' => file_get_contents($logpath),
];

if (is_a($task, adhoc_task::class) && $userid = $task->get_userid()) {
$logdata->userid = $userid;
}

$logdata->id = $DB->insert_record('task_log', $logdata);
}

/**
* Cleanup old task logs.
*/
public static function cleanup() {
global $CFG, $DB;

// Delete logs older than the retention period.
$params = [
'retentionperiod' => time() - $CFG->task_logretention,
];
$logids = $DB->get_fieldset_select('task_log', 'id', 'timestart < :retentionperiod', $params);
self::delete_task_logs($logids);

// Delete logs to retain a minimum number of logs.
$sql = "SELECT classname FROM {task_log} GROUP BY classname HAVING COUNT(classname) > :retaincount";
$params = [
'retaincount' => $CFG->task_logretainruns,
];
$classes = $DB->get_fieldset_sql($sql, $params);

foreach ($classes as $classname) {
$params = [
'classname' => $classname,
];

$retaincount = (int) $CFG->task_logretainruns;
$keeplogs = $DB->get_fieldset_sql(
"SELECT id FROM {task_log} WHERE classname = :classname ORDER BY timestart DESC LIMIT {$retaincount}",
$params
);

$notinsql = "";
if ($keeplogs) {
list($notinsql, $params) = $DB->get_in_or_equal($keeplogs, SQL_PARAMS_NAMED, 'p', false);
$params['classname'] = $classname;
$notinsql = " AND id {$notinsql}";
}

$logids = $DB->get_fieldset_select('task_log', 'id', "classname = :classname {$notinsql}", $params);
self::delete_task_logs($logids);
}
}

/**
* Delete task logs for the specified logs.
*
* @param array $logids
*/
public static function delete_task_logs(array $logids) {
global $DB;

if (empty($logids)) {
return;
}

$DB->delete_records_list('task_log', 'id', $logids);
}
}
Loading

0 comments on commit 4b71596

Please sign in to comment.