summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2016-02-15 18:33:37 +0100
committerSimon Rettberg2016-02-15 18:33:37 +0100
commit6821a5f066b8e2a5648c0eabf1322749300d28c3 (patch)
treed61b1fd3e2e91532dceed824ae03513430f037b6
parent[ad/ldap] Fallback to default ports if working on old config (diff)
downloadslx-admin-6821a5f066b8e2a5648c0eabf1322749300d28c3.tar.gz
slx-admin-6821a5f066b8e2a5648c0eabf1322749300d28c3.tar.xz
slx-admin-6821a5f066b8e2a5648c0eabf1322749300d28c3.zip
[statistics] Smart values, show last log lines, location support
-rw-r--r--lang/de/templates/statistics/cpumodels.json8
-rw-r--r--lang/de/templates/statistics/machine-hdds.json6
-rw-r--r--lang/de/templates/statistics/syslog.json7
-rw-r--r--lang/en/templates/statistics/cpumodels.json8
-rw-r--r--lang/en/templates/statistics/machine-hdds.json6
-rw-r--r--lang/en/templates/statistics/syslog.json7
-rw-r--r--lang/pt/templates/statistics/syslog.json3
-rw-r--r--modules/statistics.inc.php203
-rw-r--r--templates/statistics/cpumodels.html16
-rw-r--r--templates/statistics/machine-hdds.html14
-rw-r--r--templates/statistics/summary.html17
-rw-r--r--templates/statistics/syslog.html43
12 files changed, 284 insertions, 54 deletions
diff --git a/lang/de/templates/statistics/cpumodels.json b/lang/de/templates/statistics/cpumodels.json
index fc7cf503..85cf517f 100644
--- a/lang/de/templates/statistics/cpumodels.json
+++ b/lang/de/templates/statistics/cpumodels.json
@@ -1,6 +1,6 @@
{
- "lang_cpuCores": "Kerne",
- "lang_cpuCount": "Anzahl",
- "lang_cpuName": "CPU Typ",
- "lang_cpuStats": "Prozessoren"
+ "lang_cpuCores": "CPU-Kerne",
+ "lang_modelCount": "Anzahl",
+ "lang_modelName": "Modellname",
+ "lang_modelStats": "PC-Modelle"
} \ No newline at end of file
diff --git a/lang/de/templates/statistics/machine-hdds.json b/lang/de/templates/statistics/machine-hdds.json
index 731376e3..f2f26baf 100644
--- a/lang/de/templates/statistics/machine-hdds.json
+++ b/lang/de/templates/statistics/machine-hdds.json
@@ -1,7 +1,13 @@
{
"lang_hdds": "Festplatten",
+ "lang_hours": "Stunden",
+ "lang_modelNo": "Modell",
"lang_partName": "Name",
"lang_partSize": "Gr\u00f6\u00dfe",
"lang_partType": "Typ",
+ "lang_pendingSectors": "Potentiell defekte Sektoren",
+ "lang_powerOnTime": "Betriebszeit",
+ "lang_reallocatedSectors": "Defekte Sektoren",
+ "lang_serialNo": "Serien-Nr",
"lang_total": "Gesamt"
} \ No newline at end of file
diff --git a/lang/de/templates/statistics/syslog.json b/lang/de/templates/statistics/syslog.json
new file mode 100644
index 00000000..960de730
--- /dev/null
+++ b/lang/de/templates/statistics/syslog.json
@@ -0,0 +1,7 @@
+{
+ "lang_details": "Details",
+ "lang_event": "Ereignis",
+ "lang_logHeadline": "Logging",
+ "lang_more": "Mehr",
+ "lang_when": "Wann"
+} \ No newline at end of file
diff --git a/lang/en/templates/statistics/cpumodels.json b/lang/en/templates/statistics/cpumodels.json
index c73cbb22..864933dd 100644
--- a/lang/en/templates/statistics/cpumodels.json
+++ b/lang/en/templates/statistics/cpumodels.json
@@ -1,6 +1,6 @@
{
- "lang_cpuCores": "Cores",
- "lang_cpuCount": "Count",
- "lang_cpuName": "CPU type",
- "lang_cpuStats": "Processors"
+ "lang_cpuCores": "CPU cores",
+ "lang_modelCount": "Count",
+ "lang_modelName": "Model name",
+ "lang_modelStats": "PC models"
} \ No newline at end of file
diff --git a/lang/en/templates/statistics/machine-hdds.json b/lang/en/templates/statistics/machine-hdds.json
index 85afe2e8..8ce6801d 100644
--- a/lang/en/templates/statistics/machine-hdds.json
+++ b/lang/en/templates/statistics/machine-hdds.json
@@ -1,7 +1,13 @@
{
"lang_hdds": "Hard disk drives",
+ "lang_hours": "hours",
+ "lang_modelNo": "Model",
"lang_partName": "Name",
"lang_partSize": "Size",
"lang_partType": "Type",
+ "lang_pendingSectors": "Sectors pending reallocation",
+ "lang_powerOnTime": "Power on time",
+ "lang_reallocatedSectors": "Bad sectors",
+ "lang_serialNo": "Serial no",
"lang_total": "Total"
} \ No newline at end of file
diff --git a/lang/en/templates/statistics/syslog.json b/lang/en/templates/statistics/syslog.json
new file mode 100644
index 00000000..6737ca68
--- /dev/null
+++ b/lang/en/templates/statistics/syslog.json
@@ -0,0 +1,7 @@
+{
+ "lang_details": "Details",
+ "lang_event": "Event",
+ "lang_logHeadline": "Logging",
+ "lang_more": "More",
+ "lang_when": "When"
+} \ No newline at end of file
diff --git a/lang/pt/templates/statistics/syslog.json b/lang/pt/templates/statistics/syslog.json
new file mode 100644
index 00000000..c44dc44f
--- /dev/null
+++ b/lang/pt/templates/statistics/syslog.json
@@ -0,0 +1,3 @@
+[
+
+] \ No newline at end of file
diff --git a/modules/statistics.inc.php b/modules/statistics.inc.php
index 3104496a..dbac4b75 100644
--- a/modules/statistics.inc.php
+++ b/modules/statistics.inc.php
@@ -56,11 +56,11 @@ class Page_Statistics extends Page
$this->showId44();
$this->showKvmState();
$this->showLatestMachines();
- $this->showCpuModels();
+ $this->showSystemModels();
Render::closeTag('div');
}
- private function capChart(&$json, $cutoff)
+ private function capChart(&$json, $cutoff, $minSlice = 0.015)
{
$total = 0;
foreach ($json as $entry) {
@@ -70,10 +70,9 @@ class Page_Statistics extends Page
$accounted = 0;
$id = 0;
foreach ($json as $entry) {
- if ($accounted < $cap || $id < 3) {
- $id++;
- $accounted += $entry['value'];
- }
+ if (($accounted >= $cap || $entry['value'] / $total < $minSlice) && $id >= 3) break;
+ $id++;
+ $accounted += $entry['value'];
}
$json = array_slice($json, 0, $id);
if ($accounted / $total < 0.99) {
@@ -100,24 +99,50 @@ class Page_Statistics extends Page
'usedpercent' => round($used['val'] / $on['val'] * 100),
'badhdd' => $hdd['val']
);
+ // Graph
+ $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', 'fillColor' => '#efe', 'strokeColor' => '#aea', 'pointColor' => '#7e7', 'pointStrokeColor' => '#fff', 'pointHighlightFill' => '#fff', 'pointHighlightStroke' => '#7e7');
+ $points2 = array('data' => array(), 'label' => 'In use', 'fillColor' => '#fee', 'strokeColor' => '#eaa', 'pointColor' => '#e77', 'pointStrokeColor' => '#fff', 'pointHighlightFill' => '#fff', 'pointHighlightStroke' => '#e77');
+ $sum = 0;
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $x = explode('#', $row['data']);
+ if ($sum === 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']));
+ }
+ $points1['data'][] = $x[1];
+ $points2['data'][] = $x[2];
+ $sum++;
+ if ($sum === 12) {
+ $sum = 0;
+ }
+ }
+ $data['json'] = json_encode(array('labels' => $labels, 'datasets' => array($points1, $points2)));
+ // Draw
Render::addTemplate('statistics/summary', $data);
}
- private function showCpuModels()
+ private function showSystemModels()
{
global $STATS_COLORS;
- $res = Database::simpleQuery("SELECT cpumodel, realcores, Count(*) AS `count` FROM machine GROUP BY cpumodel ORDER BY `count` DESC, cpumodel ASC");
+ $res = Database::simpleQuery("SELECT systemmodel, Round(AVG(realcores)) AS cores, Count(*) AS `count` FROM machine"
+ . " GROUP BY systemmodel ORDER BY `count` DESC, systemmodel ASC");
$lines = array();
$json = array();
$id = 0;
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ if (empty($row['systemmodel'])) continue;
settype($row['count'], 'integer');
- $row['id'] = 'cpuid' . $id;
- $row['urlcpumodel'] = urlencode($row['cpumodel']);
+ $row['id'] = 'systemid' . $id;
+ $row['urlsystemmodel'] = urlencode($row['systemmodel']);
$lines[] = $row;
$json[] = array(
'color' => $STATS_COLORS[$id % count($STATS_COLORS)],
- 'label' => 'cpuid' . $id,
+ 'label' => 'systemid' . $id,
'value' => $row['count']
);
++$id;
@@ -205,31 +230,20 @@ class Page_Statistics extends Page
$data = array('rows' => array());
$json = array();
$id = 0;
- $cap = ceil($total * 0.95);
- $accounted = 0;
foreach (array_reverse($lines, true) as $k => $v) {
$data['rows'][] = array('gb' => $k, 'count' => $v, 'class' => $this->hddColorClass($k));
- if ($accounted <= $cap) {
- if ($k === 0) {
- $color = '#e55';
- } else {
- $color = $STATS_COLORS[$id++ % count($STATS_COLORS)];
- }
- $json[] = array(
- 'color' => $color,
- 'label' => (string)$k,
- 'value' => $v
- );
+ if ($k === 0) {
+ $color = '#e55';
+ } else {
+ $color = $STATS_COLORS[$id++ % count($STATS_COLORS)];
}
- $accounted += $v;
- }
- if ($accounted / $total < 0.99) {
$json[] = array(
- 'color' => '#eee',
- 'label' => 'invalid',
- 'value' => ($total - $accounted)
+ 'color' => $color,
+ 'label' => (string)$k,
+ 'value' => $v
);
}
+ $this->capChart($json, 0.95);
$data['json'] = json_encode($json);
Render::addTemplate('statistics/id44', $data);
}
@@ -263,7 +277,8 @@ class Page_Statistics extends Page
private function showMachineList($filter, $argument)
{
global $SIZE_RAM, $SIZE_ID44;
- $filters = array('cpumodel', 'realcores', 'kvmstate', 'clientip', 'macaddr', 'machineuuid');
+ $join = '';
+ $filters = array('cpumodel', 'realcores', 'kvmstate', 'clientip', 'macaddr', 'machineuuid', 'systemmodel');
if (in_array($filter, $filters)) {
// Simple filters mapping into db
$where = " $filter = :argument";
@@ -287,13 +302,30 @@ class Page_Statistics extends Page
} elseif ($filter === 'badsectors') {
$where = " badsectors >= :argument ";
$args = array('argument' => $argument);
+ } elseif ($filter === 'state') {
+ if ( $argument === 'on') {
+ $where = " lastseen + 600 > UNIX_TIMESTAMP() ";
+ } elseif ($argument === 'off') {
+ $where = " lastseen + 600 < UNIX_TIMESTAMP() ";
+ } elseif ($argument === 'idle') {
+ $where = " lastseen + 600 > UNIX_TIMESTAMP() AND logintime = 0 ";
+ } elseif ($argument === 'occupied') {
+ $where = " lastseen + 600 > UNIX_TIMESTAMP() AND logintime <> 0 ";
+ } else {
+ Message::addError('invalid-filter');
+ return;
+ }
+ } elseif ($filter === 'location') {
+ $where = "subnet.locationid = :lid OR machine.locationid = :lid";
+ $join = " INNER JOIN subnet ON (INET_ATON(clientip) BETWEEN startaddr AND endaddr) ";
+ $args = array('lid' => (int)$argument);
} else {
Message::addError('invalid-filter');
return;
}
$res = Database::simpleQuery("SELECT machineuuid, macaddr, clientip, firstseen, lastseen,"
. " logintime, lastboot, realcores, mbram, kvmstate, cpumodel, id44mb, hostname, notes IS NOT NULL AS hasnotes, badsectors FROM machine"
- . " WHERE $where ORDER BY lastseen DESC, clientip ASC", $args);
+ . " $join WHERE $where ORDER BY lastseen DESC, clientip ASC", $args);
$rows = array();
$NOW = time();
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
@@ -408,7 +440,8 @@ class Page_Statistics extends Page
}
$client['firstseen_s'] = date('d.m.Y H:i', $client['firstseen']);
$client['lastseen_s'] = date('d.m.Y H:i', $client['lastseen']);
- $client['lastboot_s'] = date('d.m.Y H:i', $client['lastboot']);
+ $uptime = $NOW - $client['lastboot'];
+ $client['lastboot_s'] = date('d.m.Y H:i', $client['lastboot']) . ' (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['gbtmp'] = round($client['id44mb'] / 1024);
@@ -428,6 +461,10 @@ class Page_Statistics extends Page
if ($section[1] === 'Partition tables') {
$this->parseHdd($hdds, $section[2]);
}
+ if (isset($hdds['hdds']) && $section[1] === 'smartctl') {
+ // This currently required that the partition table section comes first...
+ $this->parseSmartctl($hdds['hdds'], $section[2]);
+ }
}
}
unset($client['data']);
@@ -436,16 +473,23 @@ class Page_Statistics extends Page
// Sessions
$NOW = time();
$cutoff = $NOW - 86400 * 7;
- if ($cutoff < $row['firstseen']) $cutoff = $row['firstseen'];
+ //if ($cutoff < $client['firstseen']) $cutoff = $client['firstseen'];
$scale = 100 / ($NOW - $cutoff);
$res = Database::simpleQuery("SELECT dateline, typeid, data FROM statistic"
. " WHERE dateline > :cutoff AND typeid IN ('~session-length', '~offline-length') AND machineuuid = :uuid ORDER BY dateline ASC", array(
- 'cutoff' => $cutoff - 86400,
+ 'cutoff' => $cutoff - 86400 * 14,
'uuid' => $uuid
));
$spans['rows'] = array();
+ $spans['graph'] = '';
$last = false;
+ $first = true;
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ if ($first && $row['dateline'] > $cutoff && $client['lastboot'] > $cutoff) {
+ // Special case: offline before
+ $spans['graph'] .= '<div style="background:#444;left:0%;width:' . round((min($row['dateline'], $client['lastboot']) - $cutoff) * $scale, 2) . '%">&nbsp;</div>';
+ }
+ $first = false;
if ($row['dateline'] + $row['data'] < $cutoff || $row['data'] > 864000) continue;
if ($last !== false && abs($last['dateline'] - $row['dateline']) < 30
&& abs($last['data'] - $row['data']) < 30) continue;
@@ -471,6 +515,10 @@ class Page_Statistics extends Page
$spans['rows'][] = $row;
$last = $row;
}
+ if ($first && $client['lastboot'] > $cutoff) {
+ // Special case: offline before
+ $spans['graph'] .= '<div style="background:#444;left:0%;width:' . round(($client['lastboot'] - $cutoff) * $scale, 2) . '%">&nbsp;</div>';
+ }
if (isset($client['state_occupied'])) {
$spans['graph'] .= '<div style="background:#e99;left:' . round(($client['logintime'] - $cutoff) * $scale, 2) . '%;width:' . round(($NOW - $client['logintime'] + 900) * $scale, 2) . '%">&nbsp;</div>';
} elseif (isset($client['state_off'])) {
@@ -496,8 +544,50 @@ class Page_Statistics extends Page
Render::addScriptBottom('chart.min');
Render::addTemplate('statistics/machine-hdds', $hdds);
}
+ // Client log
+ $lres = Database::simpleQuery("SELECT logid, dateline, logtypeid, clientip, description, extra FROM clientlog"
+ . " WHERE clientip = :clientip ORDER BY logid DESC LIMIT 25", array('clientip' => $client['clientip']));
+ $today = date('d.m.Y');
+ $yesterday = date('d.m.Y', time() - 86400);
+ $count = 0;
+ $log = array();
+ while ($row = $lres->fetch(PDO::FETCH_ASSOC)) {
+ if (substr($row['description'], -5) === 'on :0' && strpos($row['description'], 'root logged') === false) continue;
+ $day = date('d.m.Y', $row['dateline']);
+ if ($day === $today) {
+ $day = Dictionary::translate('today');
+ } elseif ($day === $yesterday) {
+ $day = Dictionary::translate('yesterday');
+ }
+ $row['date'] = $day . date(' H:i', $row['dateline']);
+ $row['icon'] = $this->eventToIconName($row['logtypeid']);
+ $log[] = $row;
+ if (++$count === 10) break;
+ }
+ Render::addTemplate('statistics/syslog', array(
+ 'clientip' => $client['clientip'],
+ 'list' => $log
+ ));
+ // Notes
Render::addTemplate('statistics/machine-notes', $client);
}
+
+ private function eventToIconName($event)
+ {
+ switch ($event) {
+ case 'session-open':
+ return 'glyphicon-log-in';
+ case 'session-close':
+ return 'glyphicon-log-out';
+ case 'partition-swap':
+ return 'glyphicon-info-sign';
+ case 'partition-temp':
+ case 'smartctl-realloc':
+ return 'glyphicon-exclamation-sign';
+ default:
+ return 'glyphicon-minus';
+ }
+ }
private function parseCpu(&$row, $data)
{
@@ -586,7 +676,7 @@ class Page_Statistics extends Page
private function parseHdd(&$row, $data)
{
$hdds = array();
- // Could have more than one partition - linear scan
+ // Could have more than one disk - linear scan
$lines = preg_split("/[\r\n]+/", $data);
$dev = false;
$i = 0;
@@ -650,5 +740,46 @@ class Page_Statistics extends Page
unset($hdd);
$row['hdds'] = &$hdds;
}
+
+ private function parseSmartctl(&$hdds, $data)
+ {
+ $lines = preg_split("/[\r\n]+/", $data);
+ $i = 0;
+ foreach ($lines as $line) {
+ if (preg_match('/^NEXTHDD=(.+)$/', $line, $out)) {
+ unset($dev);
+ foreach ($hdds as &$hdd) {
+ if ($hdd['dev'] === $out[1]) $dev =& $hdd;
+ }
+ continue;
+ }
+ if (!isset($dev)) continue;
+ if (preg_match('/^([A-Z][^:]+):\s*(.*)$/', $line, $out)) {
+ $dev['s_' . preg_replace('/\s|-|_/', '', $out[1])] = $out[2];
+ } elseif (preg_match('/^\s*\d+\s+(\S+)\s+\S+\s+\d+\s+\d+\s+\d+\s+\S+\s+(\d+)(\s|$)/', $line, $out)) {
+ $dev['s_' . preg_replace('/\s|-|_/', '', $out[1])] = $out[2];
+ }
+ }
+ // Format strings
+ foreach ($hdds as &$hdd) {
+ if (isset($hdd['s_PowerOnHours'])) {
+ $hdd['PowerOnTime'] = '';
+ $val = (int)$hdd['s_PowerOnHours'];
+ if ($val > 8760) {
+ $hdd['PowerOnTime'] .= floor($val / 8760) . 'Y, ';
+ $val %= 8760;
+ }
+ if ($val > 720) {
+ $hdd['PowerOnTime'] .= floor($val / 720) . 'M, ';
+ $val %= 720;
+ }
+ if ($val > 24) {
+ $hdd['PowerOnTime'] .= floor($val / 24) . 'd, ';
+ $val %= 24;
+ }
+ $hdd['PowerOnTime'] .= $val . 'h';
+ }
+ }
+ }
}
diff --git a/templates/statistics/cpumodels.html b/templates/statistics/cpumodels.html
index f98b89db..2f24cd92 100644
--- a/templates/statistics/cpumodels.html
+++ b/templates/statistics/cpumodels.html
@@ -1,21 +1,23 @@
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
- {{lang_cpuStats}}
+ {{lang_modelStats}}
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-8">
<table class="table table-condensed table-striped">
<tr>
- <th>{{lang_cpuName}}</th>
+ <th>{{lang_modelName}}</th>
<th class="text-right">{{lang_cpuCores}}</th>
- <th class="text-right">{{lang_cpuCount}}</th>
+ <th class="text-right">{{lang_modelCount}}</th>
</tr>
{{#rows}}
<tr id="{{id}}">
- <td class="text-left slx-nowrap"><a href="?do=Statistics&amp;filter=cpumodel&amp;argument={{urlcpumodel}}">{{cpumodel}}</a></td>
- <td class="text-right"><a href="?do=Statistics&amp;filter=realcores&amp;argument={{realcores}}">{{realcores}}</a></td>
+ <td class="text-left slx-nowrap">
+ <a href="?do=Statistics&amp;filter=systemmodel&amp;argument={{urlsystemmodel}}">{{systemmodel}}</a>
+ </td>
+ <td class="text-right"><a href="?do=Statistics&amp;filter=realcores&amp;argument={{cores}}">{{cores}}</a></td>
<td class="text-right">{{count}}</td>
</tr>
{{/rows}}
@@ -27,7 +29,7 @@
document.addEventListener("DOMContentLoaded", function() {
var data = {{{json}}};
var sel = false;
- new Chart(document.getElementById('cpumodelchart').getContext('2d')).Pie(data, {
+ new Chart(document.getElementById('cpumodelchart').getContext('2d')).Pie(data, {
animation: false,
tooltipTemplate: "<%if (label){%><%=label%><%}%>",
customTooltips: function(tooltip) {
@@ -46,4 +48,4 @@
</div>
</div>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/templates/statistics/machine-hdds.html b/templates/statistics/machine-hdds.html
index cb3cbffc..fd6cf1be 100644
--- a/templates/statistics/machine-hdds.html
+++ b/templates/statistics/machine-hdds.html
@@ -4,9 +4,21 @@
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
- {{dev}}
+ <b>{{s_ModelFamily}}</b> {{dev}}
</div>
<div class="panel-body">
+ {{#s_DeviceModel}}
+ <div>{{lang_modelNo}}: {{s_DeviceModel}}, {{lang_serialNo}}: {{s_SerialNumber}}</div>
+ {{/s_DeviceModel}}
+ {{#s_ReallocatedSectorCt}}
+ <div class="red">{{lang_reallocatedSectors}}: {{s_ReallocatedSectorCt}}</div>
+ {{/s_ReallocatedSectorCt}}
+ {{#s_CurrentPendingSector}}
+ <div class="red">{{lang_pendingSectors}}: {{s_CurrentPendingSector}}</div>
+ {{/s_CurrentPendingSector}}
+ {{#s_PowerOnHours}}
+ <div>{{lang_powerOnTime}}: {{s_PowerOnHours}}&thinsp;{{lang_hours}} ({{PowerOnTime}})</div>
+ {{/s_PowerOnHours}}
<div class="row">
<div class="col-sm-6">
<table class="table table-condensed table-striped table-responsive">
diff --git a/templates/statistics/summary.html b/templates/statistics/summary.html
index fb6466fc..5f16fd89 100644
--- a/templates/statistics/summary.html
+++ b/templates/statistics/summary.html
@@ -3,8 +3,8 @@
<div class="panel-body">
<div>
{{lang_knownMachines}}: <b>{{known}}</b>&emsp;
- {{lang_onlineMachines}}: <b>{{online}}</b>&emsp;
- {{lang_inUseMachines}}: <b>{{used}}</b> (<b>{{usedpercent}}%</b>)
+ <a href="?do=Statistics&amp;filter=state&amp;argument=on">{{lang_onlineMachines}}</a>: <b>{{online}}</b>&emsp;
+ <a href="?do=Statistics&amp;filter=state&amp;argument=occupied">{{lang_inUseMachines}}</a>: <b>{{used}}</b> (<b>{{usedpercent}}%</b>)
</div>
{{#badhdd}}
<div>
@@ -16,5 +16,18 @@
{{/badhdd}}
</div>
</div>
+ <div>
+ <canvas id="usagehist" style="width:100%;height:150px"></canvas>
+ <script type="text/javascript">
+ document.addEventListener("DOMContentLoaded", function() {
+ var data = {{{json}}};
+ var sel = false;
+ new Chart(document.getElementById('usagehist').getContext('2d')).Line(data, {
+ animation: false,
+ pointHitDetectionRadius: 5
+ });
+ }, false);
+ </script>
+ </div>
</div>
diff --git a/templates/statistics/syslog.html b/templates/statistics/syslog.html
new file mode 100644
index 00000000..c82cb8ac
--- /dev/null
+++ b/templates/statistics/syslog.html
@@ -0,0 +1,43 @@
+<h3>{{lang_logHeadline}}</h3>
+<table class="table table-striped table-condensed">
+ <thead>
+ <th width="1"></th>
+ <th>{{lang_when}}</th>
+ <th>{{lang_event}}</th>
+ <th width="1">{{lang_details}}</th>
+ </thead>
+ <tbody>
+ {{#list}}
+ <tr>
+ <td><span class="glyphicon {{icon}}" title="{{logtypeid}}" onclick="$('#filterstring').tagsinput('add', '{{logtypeid}}')"></span></td>
+ <td class="text-right" nowrap="nowrap">{{date}}</td>
+ <td>{{description}}</td>
+ <td>{{#extra}}
+ <a class="btn btn-default btn-xs pull-left" onclick="$('#details-body').html($('#extra-{{logid}}').html())" data-toggle="modal" data-target="#myModal">&raquo;</a>
+ <div class="hidden" id="extra-{{logid}}">{{extra}}</div>
+ {{/extra}}</td>
+ </tr>
+ {{/list}}
+ </tbody>
+</table>
+<div class="pull-right"><a class="btn btn-default btn-sm" href="?do=SysLog&amp;ip={{clientip}}">{{lang_more}} &raquo;</a></div>
+<div class="clearfix"></div>
+
+<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
+ <h4 class="modal-title" id="myModalLabel">{{lang_details}}</h4>
+ </div>
+ <div class="modal-body">
+ <pre id="details-body"></pre>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+ </div>
+ </div>
+ </div>
+</div>
+
+