MDL-41284 hack stats to use new log readers if available

This commit is contained in:
Petr Škoda 2014-02-12 11:25:18 +08:00
parent e6f0b5f135
commit 92927fba72
3 changed files with 253 additions and 13 deletions

View File

@ -942,9 +942,31 @@ function stats_get_start_from($str) {
// decide what to do based on our config setting (either all or none or a timestamp)
switch ($CFG->statsfirstrun) {
case 'all':
if ($firstlog = $DB->get_field_sql('SELECT MIN(time) FROM {log}')) {
$manager = get_log_manager();
$stores = $manager->get_readers();
$firstlog = false;
foreach ($stores as $store) {
if ($store instanceof \core\log\sql_internal_reader) {
$logtable = $store->get_internal_log_table_name();
if (!$logtable) {
continue;
}
$first = $DB->get_field_sql("SELECT MIN(timecreated) FROM {{$logtable}}");
if ($first and (!$firstlog or $firstlog > $first)) {
$firstlog = $first;
}
}
}
$first = $DB->get_field_sql('SELECT MIN(time) FROM {log}');
if ($first and (!$firstlog or $firstlog > $first)) {
$firstlog = $first;
}
if ($firstlog) {
return $firstlog;
}
default:
if (is_numeric($CFG->statsfirstrun)) {
return time() - $CFG->statsfirstrun;
@ -1698,9 +1720,9 @@ function stats_temp_table_drop() {
*
* This function is meant to be called once at the start of stats generation
*
* @param timestart timestamp of the start time of logs view
* @param timeend timestamp of the end time of logs view
* @return boolen success (true) or failure(false)
* @param int timestart timestamp of the start time of logs view
* @param int timeend timestamp of the end time of logs view
* @return bool success (true) or failure(false)
*/
function stats_temp_table_setup() {
global $DB;
@ -1721,19 +1743,68 @@ function stats_temp_table_setup() {
*
* This function is meant to be called to get a new day of data
*
* @param timestart timestamp of the start time of logs view
* @param timeend timestamp of the end time of logs view
* @return boolen success (true) or failure(false)
* @param int timestamp of the start time of logs view
* @param int timestamp of the end time of logs view
* @return bool success (true) or failure(false)
*/
function stats_temp_table_fill($timestart, $timeend) {
global $DB;
$sql = 'INSERT INTO {temp_log1} (userid, course, action)
// First decide from where we want the data.
SELECT userid, course, action FROM {log}
WHERE time >= ? AND time < ?';
$params = array('timestart' => $timestart, 'timeend' => $timeend, 'loginevent' => '\core\event\user_loggedin');
$DB->execute($sql, array($timestart, $timeend));
$filled = false;
$manager = get_log_manager();
$stores = $manager->get_readers();
foreach ($stores as $store) {
if ($store instanceof \core\log\sql_internal_reader) {
$logtable = $store->get_internal_log_table_name();
if (!$logtable) {
continue;
}
$sql = "SELECT COUNT('x')
FROM {{$logtable}}
WHERE timecreated >= :timestart AND timecreated < :timeend";
if (!$DB->get_field_sql($sql, $params)) {
continue;
}
// Let's fake the old records using new log data.
$sql = "INSERT INTO {temp_log1} (userid, course, action)
SELECT userid,
CASE
WHEN courseid IS NULL THEN ".SITEID."
WHEN courseid = 0 THEN ".SITEID."
ELSE courseid
END,
CASE
WHEN eventname = :loginevent THEN 'login'
WHEN crud = 'r' THEN 'view'
ELSE 'update'
END
FROM {{$logtable}}
WHERE timecreated >= :timestart AND timecreated < :timeend";
$DB->execute($sql, $params);
$filled = true;
}
}
if (!$filled) {
// Fallback to legacy data.
$sql = "INSERT INTO {temp_log1} (userid, course, action)
SELECT userid, course, action
FROM {log}
WHERE time >= :timestart AND time < :timeend";
$DB->execute($sql, $params);
}
$sql = 'INSERT INTO {temp_log2} (userid, course, action)
@ -1751,7 +1822,7 @@ function stats_temp_table_fill($timestart, $timeend) {
/**
* Deletes summary logs table for stats calculation
*
* @return boolen success (true) or failure(false)
* @return bool success (true) or failure(false)
*/
function stats_temp_table_clean() {
global $DB;

57
lib/tests/fixtures/stats_events.php vendored Normal file
View File

@ -0,0 +1,57 @@
<?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 core_tests\event;
/**
* Fixtures for new stats testing.
*
* @package core
* @category phpunit
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
class create_executed extends \core\event\base {
protected function init() {
$this->data['crud'] = 'c';
$this->data['edulevel'] = self::LEVEL_OTHER;
}
}
class read_executed extends \core\event\base {
protected function init() {
$this->data['crud'] = 'r';
$this->data['edulevel'] = self::LEVEL_OTHER;
}
}
class update_executed extends \core\event\base {
protected function init() {
$this->data['crud'] = 'u';
$this->data['edulevel'] = self::LEVEL_OTHER;
}
}
class delete_executed extends \core\event\base {
protected function init() {
$this->data['crud'] = 'd';
$this->data['edulevel'] = self::LEVEL_OTHER;
}
}

View File

@ -29,6 +29,7 @@ global $CFG;
require_once($CFG->libdir . '/adminlib.php');
require_once($CFG->libdir . '/statslib.php');
require_once($CFG->libdir . '/cronlib.php');
require_once(__DIR__ . '/fixtures/stats_events.php');
/**
* Test functions that affect daily stats.
@ -343,6 +344,43 @@ class core_statslib_testcase extends advanced_testcase {
$this->prepare_db($dataset[1], array('stats_daily'));
$this->assertEquals($day + (24 * 3600), stats_get_start_from('daily'), 'Daily stats start time');
// New log stores.
$this->preventResetByRollback();
$this->assertFileExists("$CFG->dirroot/$CFG->admin/tool/log/store/standard/version.php");
set_config('enabled_stores', 'logstore_standard', 'tool_log');
set_config('buffersize', 0, 'logstore_standard');
set_config('logguests', 1, 'logstore_standard');
get_log_manager(true);
$this->assertEquals(0, $DB->count_records('logstore_standard_log'));
$DB->delete_records('stats_daily');
$CFG->statsfirstrun = 'all';
$firstoldtime = $DB->get_field_sql('SELECT MIN(time) FROM {log}');
$this->assertEquals($firstoldtime, stats_get_start_from('daily'));
\core_tests\event\create_executed::create(array('context' => context_system::instance()))->trigger();
\core_tests\event\read_executed::create(array('context' => context_system::instance()))->trigger();
\core_tests\event\update_executed::create(array('context' => context_system::instance()))->trigger();
\core_tests\event\delete_executed::create(array('context' => context_system::instance()))->trigger();
$logs = $DB->get_records('logstore_standard_log');
$this->assertCount(4, $logs);
$firstnew = reset($logs);
$this->assertGreaterThan($firstoldtime, $firstnew->timecreated);
$DB->set_field('logstore_standard_log', 'timecreated', 10, array('id' => $firstnew->id));
$this->assertEquals(10, stats_get_start_from('daily'));
$DB->set_field('logstore_standard_log', 'timecreated', $firstnew->timecreated, array('id' => $firstnew->id));
$DB->delete_records('log');
$this->assertEquals($firstnew->timecreated, stats_get_start_from('daily'));
set_config('enabled_stores', '', 'tool_log');
get_log_manager(true);
}
/**
@ -491,7 +529,7 @@ class core_statslib_testcase extends advanced_testcase {
* @depends test_statslib_temp_table_create_and_drop
*/
public function test_statslib_temp_table_fill() {
global $CFG, $DB;
global $CFG, $DB, $USER;
$dataset = $this->load_xml_data_file(__DIR__."/fixtures/statslib-test09.xml");
@ -507,6 +545,80 @@ class core_statslib_testcase extends advanced_testcase {
$this->assertEquals(1, $DB->count_records('temp_log2'));
stats_temp_table_drop();
// New log stores.
$this->preventResetByRollback();
stats_temp_table_create();
$course = $this->getDataGenerator()->create_course();
$context = context_course::instance($course->id);
$fcontext = context_course::instance(SITEID);
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$this->assertFileExists("$CFG->dirroot/$CFG->admin/tool/log/store/standard/version.php");
set_config('enabled_stores', 'logstore_standard', 'tool_log');
set_config('buffersize', 0, 'logstore_standard');
set_config('logguests', 1, 'logstore_standard');
get_log_manager(true);
$DB->delete_records('logstore_standard_log');
\core_tests\event\create_executed::create(array('context' => $fcontext, 'courseid' => SITEID))->trigger();
\core_tests\event\read_executed::create(array('context' => $context, 'courseid' => $course->id))->trigger();
\core_tests\event\update_executed::create(array('context' => context_system::instance()))->trigger();
\core_tests\event\delete_executed::create(array('context' => context_system::instance()))->trigger();
\core\event\user_loggedin::create(
array(
'userid' => $USER->id,
'objectid' => $USER->id,
'other' => array('username' => $USER->username),
)
)->trigger();
$DB->set_field('logstore_standard_log', 'timecreated', 10);
$this->assertEquals(5, $DB->count_records('logstore_standard_log'));
\core_tests\event\delete_executed::create(array('context' => context_system::instance()))->trigger();
\core_tests\event\delete_executed::create(array('context' => context_system::instance()))->trigger();
$this->assertEquals(7, $DB->count_records('logstore_standard_log'));
stats_temp_table_fill(9, 11);
$logs1 = $DB->get_records('temp_log1');
$logs2 = $DB->get_records('temp_log2');
$this->assertCount(5, $logs1);
$this->assertCount(5, $logs2);
// The order of records in the temp tables is not guaranteed...
$viewcount = 0;
$updatecount = 0;
$logincount = 0;
foreach ($logs1 as $log) {
if ($log->course == $course->id) {
$this->assertEquals('view', $log->action);
$viewcount++;
} else {
$this->assertTrue(in_array($log->action, array('update', 'login')));
if ($log->action === 'update') {
$updatecount++;
} else {
$logincount++;
}
$this->assertEquals(SITEID, $log->course);
}
$this->assertEquals($user->id, $log->userid);
}
$this->assertEquals(1, $viewcount);
$this->assertEquals(3, $updatecount);
$this->assertEquals(1, $logincount);
set_config('enabled_stores', '', 'tool_log');
get_log_manager(true);
stats_temp_table_drop();
}
/**