From 3b1df888c963d906005ff139892df06a0d1ae2b4 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 28 Jan 2019 13:48:35 +0100 Subject: [statistics] Track and display memory/tmp usage of clients --- modules-available/statistics/api.inc.php | 13 ++++++-- modules-available/statistics/hooks/cron.inc.php | 9 ++++-- modules-available/statistics/install.inc.php | 17 ++++++++++ .../statistics/lang/de/template-tags.json | 4 +++ .../statistics/lang/en/template-tags.json | 4 +++ modules-available/statistics/page.inc.php | 37 ++++++++++++++++------ modules-available/statistics/style.css | 32 +++++++++++++++++++ .../statistics/templates/filterbox.html | 5 ++- .../statistics/templates/machine-main.html | 33 ++++++++++++++++--- 9 files changed, 135 insertions(+), 19 deletions(-) diff --git a/modules-available/statistics/api.inc.php b/modules-available/statistics/api.inc.php index 813e7d54..57c4cee2 100644 --- a/modules-available/statistics/api.inc.php +++ b/modules-available/statistics/api.inc.php @@ -34,7 +34,8 @@ if ($type{0} === '~') { // External mode of operation? $mode = Request::post('mode', false, 'string'); $NOW = time(); - $old = Database::queryFirst('SELECT clientip, logintime, lastseen, lastboot, state, mbram, cpumodel FROM machine WHERE machineuuid = :uuid', array('uuid' => $uuid)); + $old = Database::queryFirst('SELECT clientip, logintime, lastseen, lastboot, state, mbram, cpumodel, live_memfree, live_swapfree, live_tmpfree + FROM machine WHERE machineuuid = :uuid', array('uuid' => $uuid)); if ($old !== false) { settype($old['logintime'], 'integer'); settype($old['lastseen'], 'integer'); @@ -114,6 +115,7 @@ if ($type{0} === '~') { . ' cpumodel = :cpumodel,' . ' systemmodel = :systemmodel,' . ' id44mb = :id44mb,' + . ' live_tmpsize = 0, live_swapsize = 0, live_memsize = 0,' . ' badsectors = :badsectors,' . ' data = :data,' . ' state = :state ' @@ -152,7 +154,10 @@ if ($type{0} === '~') { // Log potential crash if ($old['state'] === 'IDLE' || $old['state'] === 'OCCUPIED') { - writeClientLog('machine-mismatch-poweron', 'Client sent poweron event, but previous known state is ' . $old['state']); + writeClientLog('machine-mismatch-poweron', 'Poweron event, but previous known state is ' . $old['state'] + . '. RAM: ' . Util::readableFileSize($old['live_memfree'], -1, 2) + . ', Swap: ' . Util::readableFileSize($old['live_swapfree'], -1, 2) + . ', ID44: ' . Util::readableFileSize($old['live_memfree'], -1, 2)); } } @@ -190,6 +195,10 @@ if ($type{0} === '~') { } } } + foreach (['memsize', 'tmpsize', 'swapsize', 'memfree', 'tmpfree', 'swapfree'] as $item) { + $strUpdateBoottime .= ' live_' . $item . ' = :_' . $item . ', '; + $params['_' . $item] = ceil(Request::post($item, 0, 'int') / 1024); + } // Figure out what's happening - state changes if ($used === 0 && $old['state'] !== 'IDLE') { if ($old['state'] === 'OCCUPIED' && $sessionLength === 0) { diff --git a/modules-available/statistics/hooks/cron.inc.php b/modules-available/statistics/hooks/cron.inc.php index 0b8e740e..f22d0475 100644 --- a/modules-available/statistics/hooks/cron.inc.php +++ b/modules-available/statistics/hooks/cron.inc.php @@ -24,14 +24,17 @@ function state_cleanup() $standby = time() - 86400 * 4; // Reset standby machines after four days $on = time() - 610; // Reset others after ~10 minutes // Query for logging - $res = Database::simpleQuery("SELECT machineuuid, clientip, state, logintime, lastseen FROM machine - WHERE lastseen < If(state = 'STANDBY', $standby, $on) AND state <> 'OFFLINE'"); + $res = Database::simpleQuery("SELECT machineuuid, clientip, state, logintime, lastseen, live_memfree, live_swapfree, live_tmpfree + FROM machine WHERE lastseen < If(state = 'STANDBY', $standby, $on) AND state <> 'OFFLINE'"); while ($row = $res->fetch(PDO::FETCH_ASSOC)) { Database::exec('INSERT INTO clientlog (dateline, logtypeid, clientip, machineuuid, description, extra) VALUES (UNIX_TIMESTAMP(), :type, :client, :uuid, :description, :longdesc)', array( 'type' => 'machine-mismatch-cron', 'client' => $row['clientip'], - 'description' => 'Client timed out, last known state is ' . $row['state'], + 'description' => 'Client timed out, last known state is ' . $row['state'] + . '. RAM: ' . Util::readableFileSize($row['live_memfree'], -1, 2) + . ', Swap: ' . Util::readableFileSize($row['live_swapfree'], -1, 2) + . ', ID44: ' . Util::readableFileSize($row['live_memfree'], -1, 2), 'longdesc' => '', 'uuid' => $row['machineuuid'], )); diff --git a/modules-available/statistics/install.inc.php b/modules-available/statistics/install.inc.php index 4e2dfcca..84e038a4 100644 --- a/modules-available/statistics/install.inc.php +++ b/modules-available/statistics/install.inc.php @@ -234,5 +234,22 @@ if (!tableHasColumn('machine', 'state')) { $res[] = UPDATE_DONE; } +// 2019-01-25: Add memory/temp stats column +if (!tableHasColumn('machine', 'live_tmpsize')) { + $ret = Database::exec("ALTER TABLE `machine` + ADD COLUMN `live_tmpsize` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `id44mb`, + ADD COLUMN `live_tmpfree` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `live_tmpsize`, + ADD COLUMN `live_swapsize` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `live_tmpfree`, + ADD COLUMN `live_swapfree` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `live_swapsize`, + ADD COLUMN `live_memsize` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `live_swapfree`, + ADD COLUMN `live_memfree` int(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `live_memsize`, + ADD INDEX `live_tmpfree` (`live_tmpfree`), + ADD INDEX `live_memfree` (`live_memfree`)"); + if ($ret === false) { + finalResponse(UPDATE_FAILED, 'Adding state column to machine table failed: ' . Database::lastError()); + } + $res[] = UPDATE_DONE; +} + // Create response responseFromArray($res); diff --git a/modules-available/statistics/lang/de/template-tags.json b/modules-available/statistics/lang/de/template-tags.json index 84c4690c..2567eea1 100644 --- a/modules-available/statistics/lang/de/template-tags.json +++ b/modules-available/statistics/lang/de/template-tags.json @@ -14,6 +14,7 @@ "lang_event": "Ereignis", "lang_eventType": "Typ", "lang_firstSeen": "Erste Aktivit\u00e4t", + "lang_free": "frei", "lang_gbRam": "RAM", "lang_hardwareSummary": "Hardware", "lang_hdds": "Festplatten", @@ -40,6 +41,7 @@ "lang_machineStandby": "Im Standby", "lang_machineSummary": "Zusammenfassung", "lang_maximumAbbrev": "Max.", + "lang_memFree": "RAM frei (MB)", "lang_memoryStats": "Arbeitsspeicher", "lang_model": "Modell", "lang_modelCount": "Anzahl", @@ -82,10 +84,12 @@ "lang_subnet": "Subnetz", "lang_sureDeletePermanent": "M\u00f6chten Sie diese(n) Rechner wirklich unwiderruflich aus der Datenbank entfernen?\r\n\r\nWichtig: L\u00f6schen verhindert nicht, dass ein Rechner nach erneutem Starten von bwLehrpool wieder in die Datenbank aufgenommen wird.", "lang_sureReplaceNoUndo": "Wollen Sie die Daten ausgew\u00e4hlten Rechner \u00fcbertragen? Diese Aktion kann nicht r\u00fcckg\u00e4ngig gemacht werden.", + "lang_swapFree": "swap frei (MB)", "lang_tempPart": "Temp. Partition", "lang_tempPartStats": "Tempor\u00e4re Partition", "lang_thoseAreProjectors": "Diese Modellnamen werden als Beamer behandelt, auch wenn die EDID-Informationen des Ger\u00e4tes anderes berichten.", "lang_timebarDesc": "Visuelle Darstellung der letzten Tage. Rote Abschnitte zeigen, wann der Rechner belegt war, gr\u00fcne, wann er nicht verwendet wurde, aber eingeschaltet war. Die leicht abgedunkelten Abschnitte markieren N\u00e4chte (22 bis 8 Uhr).", + "lang_tmpFree": "ID44 frei (MB)", "lang_tmpGb": "Temp-HDD", "lang_total": "Gesamt", "lang_usageDetails": "Nutzungsdetails", diff --git a/modules-available/statistics/lang/en/template-tags.json b/modules-available/statistics/lang/en/template-tags.json index b064ee50..1d9cd4da 100644 --- a/modules-available/statistics/lang/en/template-tags.json +++ b/modules-available/statistics/lang/en/template-tags.json @@ -14,6 +14,7 @@ "lang_event": "Event", "lang_eventType": "Type", "lang_firstSeen": "First seen", + "lang_free": "free", "lang_gbRam": "RAM", "lang_hardwareSummary": "Hardware", "lang_hdds": "Hard disk drives", @@ -40,6 +41,7 @@ "lang_machineStandby": "In standby mode", "lang_machineSummary": "Summary", "lang_maximumAbbrev": "max.", + "lang_memFree": "RAM free (MB)", "lang_memoryStats": "Memory", "lang_model": "Model", "lang_modelCount": "Count", @@ -82,10 +84,12 @@ "lang_subnet": "Subnet", "lang_sureDeletePermanent": "Are your sure you want to delete the selected machine(s) from the database? This cannot be undone.\r\n\r\nNote: Deleting machines from the database does not prevent booting up bwLehrpool again, which would recreate their respective database entries.", "lang_sureReplaceNoUndo": "Are you sure you want to replace the selected machine pairs? This action cannot be undone.", + "lang_swapFree": "swap free (MB)", "lang_tempPart": "Temp. partition", "lang_tempPartStats": "Temporary partition", "lang_thoseAreProjectors": "These model names will always be treated as beamers, even if the device's EDID data says otherwise.", "lang_timebarDesc": "Visual representation of the last few days. Red parts mark periods where the client was occupied, green parts where the client was idle. Dimmed parts mark nights (10pm to 8am).", + "lang_tmpFree": "ID44 free (MB)", "lang_tmpGb": "Temp HDD", "lang_total": "Total", "lang_usageDetails": "Detailed usage", diff --git a/modules-available/statistics/page.inc.php b/modules-available/statistics/page.inc.php index c9a0cac5..a9cde6fb 100644 --- a/modules-available/statistics/page.inc.php +++ b/modules-available/statistics/page.inc.php @@ -122,8 +122,18 @@ class Page_Statistics extends Page 'column' => true, 'values' => ['occupied', 'on', 'off', 'idle', 'standby'] ], - 'runtime' => [ - 'op' => Page_Statistics::OP_NOMINAL, + 'live_swapfree' => [ + 'op' => Page_Statistics::OP_ORDINAL, + 'type' => 'int', + 'column' => true + ], + 'live_memfree' => [ + 'op' => Page_Statistics::OP_ORDINAL, + 'type' => 'int', + 'column' => true + ], + 'live_tmpfree' => [ + 'op' => Page_Statistics::OP_ORDINAL, 'type' => 'int', 'column' => true ], @@ -764,9 +774,9 @@ class Page_Statistics extends Page $row['currentsession'] = $lecture['displayname']; $row['lectureid'] = $lecture['lectureid']; } + $row['session'] = $row['currentsession']; + return; } - $row['session'] = $row['currentsession']; - return; } $res = Database::simpleQuery('SELECT dateline, username, data FROM statistic' . " WHERE clientip = :ip AND typeid = '.vmchooser-session-name'" @@ -783,14 +793,17 @@ class Page_Statistics extends Page } if ($session !== false) { $row['session'] = $session['data']; - $row['username'] = $session['username']; + if (empty($row['currentuser'])) { + $row['username'] = $session['username']; + } } } private function showMachine($uuid) { - $client = Database::queryFirst('SELECT machineuuid, locationid, macaddr, clientip, firstseen, lastseen, logintime, lastboot, state,' - . ' mbram, kvmstate, cpumodel, id44mb, data, hostname, currentuser, currentsession, notes FROM machine WHERE machineuuid = :uuid', + $client = Database::queryFirst('SELECT machineuuid, locationid, macaddr, clientip, firstseen, lastseen, logintime, lastboot, state, + mbram, live_tmpsize, live_tmpfree, live_swapsize, live_swapfree, live_memsize, live_memfree, + kvmstate, cpumodel, id44mb, data, hostname, currentuser, currentsession, notes FROM machine WHERE machineuuid = :uuid', array('uuid' => $uuid)); if ($client === false) { Message::addError('unknown-machine', $uuid); @@ -826,6 +839,7 @@ class Page_Statistics extends Page $client['state_' . $client['state']] = true; $client['firstseen_s'] = date('d.m.Y H:i', $client['firstseen']); $client['lastseen_s'] = date('d.m.Y H:i', $client['lastseen']); + $client['logintime_s'] = date('d.m.Y H:i', $client['logintime']); if ($client['lastboot'] == 0) { $client['lastboot_s'] = '-'; } else { @@ -835,9 +849,14 @@ class Page_Statistics extends Page $client['lastboot_s'] .= ' (Up ' . floor($uptime / 86400) . 'd ' . gmdate('H:i', $uptime) . ')'; } } - $client['logintime_s'] = date('d.m.Y H:i', $client['logintime']); - $client['gbram'] = round(round($client['mbram'] / 500) / 2, 1); + $client['gbram'] = round(ceil($client['mbram'] / 512) / 2, 1); $client['gbtmp'] = round($client['id44mb'] / 1024); + foreach (['tmp', 'swap', 'mem'] as $item) { + if ($client['live_' . $item . 'size'] == 0) + continue; + $client['live_' . $item . 'percent'] = round(($client['live_' . $item . 'free'] / $client['live_' . $item . 'size']) * 100, 2); + $client['live_' . $item . 'free_s'] = Util::readableFileSize($client['live_' . $item . 'free'], -1, 2); + } $client['ramclass'] = $this->ramColorClass($client['mbram']); $client['kvmclass'] = $this->kvmColorClass($client['kvmstate']); $client['hddclass'] = $this->hddColorClass($client['gbtmp']); diff --git a/modules-available/statistics/style.css b/modules-available/statistics/style.css index 1496ac87..c48275ba 100644 --- a/modules-available/statistics/style.css +++ b/modules-available/statistics/style.css @@ -8,4 +8,36 @@ border-radius: 25px; font-size: 20px; line-height: 40px; +} + +.meter { + position: relative; + border-radius: 5px; + border: 1px solid #999; + background: linear-gradient(to right, #9e6 0%, #fb8 66%, #f32 100%); + height: 1.25em; + padding: 0; + width: 100%; + overflow: hidden; +} + +.meter .bar { + position: absolute; + top: 0; + height: 100%; + right: 0; + background: #efe; + display: inline-block; + padding: 0; + margin: 0 0 0 auto; +} + +.meter .text { + position: absolute; + right: 5px; + overflow: visible; + font-size: 8pt; + white-space: nowrap; + z-index: 1000; + text-shadow: #fff 1px 1px; } \ No newline at end of file diff --git a/modules-available/statistics/templates/filterbox.html b/modules-available/statistics/templates/filterbox.html index cd8ec24d..07aa7320 100644 --- a/modules-available/statistics/templates/filterbox.html +++ b/modules-available/statistics/templates/filterbox.html @@ -101,7 +101,10 @@ var slxFilterNames = { currentuser: '{{lang_currentUser}}', subnet: '{{lang_subnet}}', runtime: '{{lang_runtimeHours}}', - hostname: '{{lang_hostname}}' + hostname: '{{lang_hostname}}', + live_swapfree: '{{lang_swapFree}}', + live_memfree: '{{lang_memFree}}', + live_tmpfree: '{{lang_tmpFree}}' }; slxLocations = {{{locations}}}; diff --git a/modules-available/statistics/templates/machine-main.html b/modules-available/statistics/templates/machine-main.html index f1021482..904c780b 100644 --- a/modules-available/statistics/templates/machine-main.html +++ b/modules-available/statistics/templates/machine-main.html @@ -1,3 +1,4 @@ +{{%FILTERS}}

{{hostname}} {{#hostname}}–{{/hostname}} {{clientip}} {{#notes}}{{/notes}} @@ -117,9 +118,23 @@ {{lang_ram}} - {{gbram}} GiB - {{#maxram}}({{lang_maximumAbbrev}} {{maxram}}){{/maxram}} - {{ramtype}} +
+ {{gbram}} GiB + {{#maxram}}({{lang_maximumAbbrev}} {{maxram}}){{/maxram}} + {{ramtype}} +
+ {{#live_memsize}} +
+
{{live_memfree_s}} {{lang_free}}
+
+
+ {{/live_memsize}} + {{#live_swapsize}} +
+
{{live_swapfree_s}} {{lang_free}}
+
+
+ {{/live_swapsize}} {{#extram}} @@ -135,7 +150,17 @@ {{/extram}} {{lang_tempPart}} - {{gbtmp}} GiB + +
+ {{gbtmp}} GiB +
+ {{#live_tmpsize}} +
+
{{live_tmpfree_s}} {{lang_free}}
+
+
+ {{/live_tmpsize}} + {{lang_64bitSupport}} -- cgit v1.2.3-55-g7522