From 200d92c8491d5060af5dd839aa82d1e51b058dd6 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 2 Dec 2022 15:21:26 +0100 Subject: [statistics] Per-location usage stats; include active lecture count --- modules-available/statistics/pages/summary.inc.php | 102 +++++++++++++++++---- 1 file changed, 83 insertions(+), 19 deletions(-) (limited to 'modules-available/statistics/pages') diff --git a/modules-available/statistics/pages/summary.inc.php b/modules-available/statistics/pages/summary.inc.php index cf3e745d..53b028fc 100644 --- a/modules-available/statistics/pages/summary.inc.php +++ b/modules-available/statistics/pages/summary.inc.php @@ -44,7 +44,7 @@ class SubPage /** * @param \StatisticsFilterSet $filterSet */ - private static function showSummary($filterSet) + private static function showSummary(StatisticsFilterSet $filterSet) { $filterSet->makeFragments($where, $join, $args); $known = Database::queryFirst("SELECT Count(*) AS val FROM machine m $join WHERE $where", $args); @@ -56,36 +56,74 @@ class SubPage } else { $usedpercent = 0; } - $data = array( + $data = [ 'known' => $known['val'], 'online' => $on['val'], 'used' => $used['val'], 'usedpercent' => $usedpercent, 'badhdd' => $hdd['val'], - ); + ]; // Graph + // Get locations + $locFilter = $filterSet->hasFilter('LocationStatisticsFilter'); + if ($locFilter === null || ($locFilter->op === '~' && (int)$locFilter->argument === 0)) { + $locations = null; + $op = null; + } elseif ($locFilter->op === '~') { + $locations = array_keys(Location::getRecursiveFlat($locFilter->argument)); + $op = $locFilter->op; + } else { + $locations = [$locFilter->argument]; + $op = $locFilter->op; + } + //error_log($op . ' ' . print_r($locations, true)); $cutoff = time() - 2 * 86400; - $res = Database::simpleQuery("SELECT dateline, data FROM statistic WHERE typeid = '~stats' AND dateline > $cutoff ORDER BY dateline ASC"); - $labels = array(); - $points1 = array('data' => array(), 'label' => 'Online', 'borderColor' => '#8eb'); - $points2 = array('data' => array(), 'label' => 'In use', 'borderColor' => '#fa9'); + $res = Database::simpleQuery("SELECT dateline, data FROM statistic + WHERE typeid = '~stats' AND dateline > $cutoff ORDER BY dateline DESC"); + $labels = []; + $points1 = []; + $points2 = []; + $lectures = []; + // Get max from 6 consecutive values, which should be 6*5 = 30m $sum = 0; foreach ($res as $row) { - $x = explode('#', $row['data']); - if ($sum === 0) { + if ($row['data'][0] === '{') { + $x = json_decode($row['data'], true); + if (!is_array($x) || !isset($x['usage'])) + continue; + $x = self::mangleStatsJson($x, $locations, $op); + } else if ($locations === null) { + $x = explode('#', $row['data']); + if (count($x) < 3) + continue; + $x[] = 0; + } else { + continue; + } + if ($sum % 4 === 0) { $labels[] = date('H:i', $row['dateline']); } else { - $x[1] = max($x[1], array_pop($points1['data'])); - $x[2] = max($x[2], array_pop($points2['data'])); + $x[1] = max($x[1], array_pop($points1)); + $x[2] = max($x[2], array_pop($points2)); + $x[3] += array_pop($lectures); } - $points1['data'][] = $x[1]; - $points2['data'][] = $x[2]; + $points1[] = $x[1]; + $points2[] = $x[2]; + $lectures[] = $x[3]; ++$sum; - if ($sum === 12) { - $sum = 0; - } } - $data['json'] = json_encode(array('labels' => $labels, 'datasets' => array($points1, $points2))); + if (!empty($points1) && max(...$points1) > 0) { + $labels = array_reverse($labels); + $points1 = array_reverse($points1); + $points2 = array_reverse($points2); + $lectures = array_reverse($lectures); + $data['json'] = json_encode(['labels' => $labels, + 'datasets' => [ + ['data' => $points1, 'label' => 'Online', 'borderColor' => '#8f3'], + ['data' => $points2, 'label' => 'In use', 'borderColor' => '#e76'], + ]]); + $data['markings'] = json_encode($lectures, true); + } if (Module::get('runmode') !== false) { $res = Database::queryFirst('SELECT Count(*) AS cnt FROM machine m INNER JOIN runmode r USING (machineuuid)' . " $join WHERE $where", $args); @@ -238,14 +276,15 @@ class SubPage /** * @param \StatisticsFilterSet $filterSet */ - private static function showLatestMachines($filterSet) + private static function showLatestMachines(StatisticsFilterSet $filterSet) { $filterSet->makeFragments($where, $join, $args); $args['cutoff'] = ceil(time() / 3600) * 3600 - 86400 * 10; $res = Database::simpleQuery("SELECT m.machineuuid, m.clientip, m.hostname, m.firstseen, m.mbram, m.kvmstate, m.id44mb FROM machine m $join - WHERE firstseen > :cutoff AND $where ORDER BY firstseen DESC LIMIT 32", $args); + WHERE firstseen > :cutoff AND $where + ORDER BY firstseen DESC LIMIT 32", $args); $rows = array(); $count = 0; foreach ($res as $row) { @@ -306,4 +345,29 @@ class SubPage } } + /** + * @param array $json decoded json ~stats data + * @param ?int[] $locations + * @param ?string $op + */ + private static function mangleStatsJson(array $json, $locations, $op): array + { + // Total, On, InUse, Lectures + $retval = [0, 0, 0, 0]; + foreach ($json['usage'] as $lid => $data) { + $lid = (int)$lid; + if ($locations === null + || ($op === '!=' && !in_array($lid, $locations)) + || ($op !== '!=' && in_array($lid, $locations))) { + $retval[0] += $data['t']; + $retval[1] += $data['o'] ?? 0; + $retval[2] += $data['u'] ?? 0; + if (isset($data['event'])) { + $retval[3] += 1; + } + } + } + return $retval; + } + } -- cgit v1.2.3-55-g7522