Implementation of Network status page
This commit is contained in:
parent
b3e0757b29
commit
2cdd61458f
7 changed files with 355 additions and 27 deletions
|
|
@ -74,9 +74,10 @@ public class StatusPage implements WAPage {
|
|||
Map<String, String> request){
|
||||
|
||||
if(request.containsKey("i")) {
|
||||
WAStatus obj = getPlugin(context);
|
||||
DataNode root = new DataNode(DataNode.DataType.Map);
|
||||
obj.jsonUpdate(request, root);
|
||||
WAStatus obj = getPlugin(context);
|
||||
if(obj != null)
|
||||
obj.jsonUpdate(request, root);
|
||||
return root;
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ public class HDDStatus implements WAStatus {
|
|||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "HDD Status";
|
||||
return "Harddrives";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -79,8 +79,7 @@ public class HDDStatus implements WAStatus {
|
|||
node.set("id", idMap.get(device));
|
||||
else{
|
||||
idMap.put(device, nextId);
|
||||
node.set("id", nextId);
|
||||
++nextId;
|
||||
node.set("id", nextId++);
|
||||
}
|
||||
|
||||
FileSystemUsage hdd_use = sigar.getFileSystemUsage(hdd.getDirName());
|
||||
|
|
|
|||
|
|
@ -9,15 +9,24 @@
|
|||
<div id="hdd-container"></div>
|
||||
|
||||
<div id="template" class="hidden">
|
||||
<div id="" class="col-md-12"><div class="panel panel-default">
|
||||
<div id="" class="col-md-4"><div class="panel panel-default">
|
||||
<div class="panel-heading hdd-title">HDD: {{.mount}} ({{.size_total}})</div>
|
||||
<div class="panel-body">
|
||||
<center><img src="img/hdd_ok.png" /></center><br>
|
||||
<div class="progress">
|
||||
<div class="progress-bar hdd-used" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100">
|
||||
5600 MB
|
||||
</div>
|
||||
<div class="progress-bar hdd-used" role="progressbar"></div>
|
||||
<center class="hdd-free">{{.size_free}}</center>
|
||||
</div>
|
||||
<table class="table small hdd-detail">
|
||||
<thead><tr>
|
||||
<th data-field="mount">Mount</th>
|
||||
<th data-field="type" >Type</th>
|
||||
</tr></thead>
|
||||
<tr>
|
||||
<td class="hdd-mount"></td>
|
||||
<td class="hdd-filesystem"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--<div><canvas id="hdd-io" height="400"></canvas></div>-->
|
||||
</div>
|
||||
</div></div>
|
||||
|
|
@ -30,29 +39,13 @@ $(function() {
|
|||
updateHdd();
|
||||
});
|
||||
|
||||
var hdd_io_chart = {};
|
||||
var hdd_io_data = {
|
||||
labels : ["","","","","","","","","",""],
|
||||
datasets: [
|
||||
{
|
||||
strokeColor: "rgba(151,0,0,1)",
|
||||
fillColor: "rgba(151,0,0,0.2)",
|
||||
data: [0,0,0,0,0,0,0,0,0,0,0]
|
||||
},{
|
||||
strokeColor: "rgba(0,187,0,1)",
|
||||
fillColor: "rgba(0,187,0,0.2)",
|
||||
data: [0,0,0,0,0,0,0,0,0,0,0]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
function updateHdd(){
|
||||
$.getJSON("{{nav.url}}&json&hdd", function( data ) {
|
||||
$.each(data['hdd'], function( index, hdd ){
|
||||
var element = null;
|
||||
var html_id = "hdd-id-" + hdd.id;
|
||||
if($("#"+html_id).length)
|
||||
element = $("#hdd-id-" + hdd.id);
|
||||
element = $("#" + html_id);
|
||||
else{ // Create new element
|
||||
element = $("#template").children().clone();
|
||||
$(element).attr("id", html_id);
|
||||
|
|
@ -66,6 +59,8 @@ function updateHdd(){
|
|||
$(element).find(".progress-bar").css("width", (hdd.size_used/hdd.size_total)*100+"%");
|
||||
$(element).find(".hdd-used").html(byteToString(hdd.size_used));
|
||||
$(element).find(".hdd-free").html(byteToString(hdd.size_free));
|
||||
$(element).find(".hdd-filesystem").html(hdd.filesystem);
|
||||
$(element).find(".hdd-mount").html(hdd.mount);
|
||||
});
|
||||
});
|
||||
setTimeout(updateHdd, 2000);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ package wa.server.plugin.hwstatus;
|
|||
import org.hyperic.sigar.*;
|
||||
import org.hyperic.sigar.cmd.Shell;
|
||||
import wa.server.plugin.WAStatus;
|
||||
import zutil.StringUtil;
|
||||
import zutil.io.file.FileUtil;
|
||||
import zutil.parser.DataNode;
|
||||
import zutil.parser.DataNode.DataType;
|
||||
|
|
@ -38,7 +39,7 @@ import java.util.Map;
|
|||
public class HwStatus implements WAStatus {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Cpu Load";
|
||||
return "Hardware Summary";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -55,6 +56,11 @@ public class HwStatus implements WAStatus {
|
|||
try{
|
||||
Sigar sigar = new Shell().getSigar();
|
||||
|
||||
if(request.containsKey("uptime")){
|
||||
root.set("uptime",
|
||||
StringUtil.formatTimeToString(
|
||||
(long)sigar.getUptime().getUptime()));
|
||||
}
|
||||
if(request.containsKey("cpu")) {
|
||||
DataNode cpuNode = new DataNode(DataType.List);
|
||||
CpuInfo cpu_info = sigar.getCpuInfoList()[0];
|
||||
|
|
|
|||
135
src/wa/server/plugin/hwstatus/NetStatus.java
Normal file
135
src/wa/server/plugin/hwstatus/NetStatus.java
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Ziver
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package wa.server.plugin.hwstatus;
|
||||
|
||||
import org.hyperic.sigar.*;
|
||||
import org.hyperic.sigar.cmd.Shell;
|
||||
import wa.server.plugin.WAStatus;
|
||||
import wa.server.util.ThroughputCalculator;
|
||||
import zutil.io.file.FileUtil;
|
||||
import zutil.parser.DataNode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Ziver on 2015-04-28.
|
||||
*/
|
||||
public class NetStatus implements WAStatus{
|
||||
private int nextId;
|
||||
private HashMap<String,Integer> idMap = new HashMap<String,Integer>();
|
||||
|
||||
private HashMap<String,ThroughputCalculator> txMap = new HashMap<String,ThroughputCalculator>();
|
||||
private HashMap<String,ThroughputCalculator> rxMap = new HashMap<String,ThroughputCalculator>();
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Network";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String html() {
|
||||
try {
|
||||
return FileUtil.getContent(FileUtil.findURL("wa/server/plugin/hwstatus/NetStatus.tmpl"));
|
||||
} catch (IOException e) {
|
||||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonUpdate(Map<String, String> request, DataNode root) {
|
||||
try{
|
||||
Sigar sigar = new Shell().getSigar();
|
||||
|
||||
if(request.containsKey("net")){
|
||||
DataNode intfListNode = new DataNode(DataNode.DataType.List);
|
||||
String[] intfNameList = sigar.getNetInterfaceList();
|
||||
for( String intfName : intfNameList ){
|
||||
DataNode intfNode = new DataNode(DataNode.DataType.Map);
|
||||
if(idMap.containsKey(intfName))
|
||||
intfNode.set("id", idMap.get(intfName));
|
||||
else{
|
||||
idMap.put(intfName, nextId);
|
||||
intfNode.set("id", nextId++);
|
||||
}
|
||||
|
||||
NetInterfaceStat net_stat = sigar.getNetInterfaceStat(intfName);
|
||||
intfNode.set("name", intfName);
|
||||
intfNode.set("speed", net_stat.getSpeed());
|
||||
intfNode.set("dropped", net_stat.getRxDropped() + net_stat.getTxDropped() );
|
||||
intfNode.set("error", net_stat.getRxErrors() + net_stat.getTxErrors() );
|
||||
intfNode.set("total_tx", net_stat.getTxBytes());
|
||||
intfNode.set("total_rx", net_stat.getRxBytes());
|
||||
|
||||
ThroughputCalculator txThroughput = txMap.get(intfName);
|
||||
if(txThroughput == null) {
|
||||
txThroughput = new ThroughputCalculator();
|
||||
txMap.put(intfName, txThroughput);
|
||||
}
|
||||
txThroughput.setTotalHandledData(net_stat.getTxBytes());
|
||||
intfNode.set("tx", txThroughput.getBitThroughput());
|
||||
|
||||
ThroughputCalculator rxThroughput = rxMap.get(intfName);
|
||||
if(rxThroughput == null) {
|
||||
rxThroughput = new ThroughputCalculator();
|
||||
rxMap.put(intfName, rxThroughput);
|
||||
}
|
||||
rxThroughput.setTotalHandledData(net_stat.getRxBytes());
|
||||
intfNode.set("rx", rxThroughput.getBitThroughput());
|
||||
|
||||
NetInterfaceConfig net_conf = sigar.getNetInterfaceConfig( intfName );
|
||||
intfNode.set("up", (net_conf.getFlags() & NetFlags.IFF_UP) > 0 );
|
||||
intfNode.set("ip", net_conf.getAddress() );
|
||||
intfNode.set("netmask", net_conf.getNetmask() );
|
||||
intfNode.set("mac", net_conf.getHwaddr() );
|
||||
intfNode.set("type", net_conf.getType() );
|
||||
intfNode.set("flags", NetFlags.getIfFlagsString(net_conf.getFlags()) );
|
||||
intfNode.set("desc", net_conf.getDescription() );
|
||||
|
||||
intfListNode.add(intfNode);
|
||||
}
|
||||
root.set("net", intfListNode);
|
||||
}
|
||||
if(request.containsKey("routing")) {
|
||||
DataNode routeListNode = new DataNode(DataNode.DataType.List);
|
||||
NetRoute[] routes = sigar.getNetRouteList();
|
||||
for( NetRoute route : routes ) {
|
||||
DataNode routeNode = new DataNode(DataNode.DataType.Map);
|
||||
routeNode.set("interface", route.getIfname());
|
||||
routeNode.set("destination", route.getDestination());
|
||||
routeNode.set("gateway", route.getGateway());
|
||||
routeNode.set("netmask", route.getMask());
|
||||
routeNode.set("flags", NetFlags.getIfFlagsString((route.getFlags())));
|
||||
routeNode.set("metric", route.getMetric());
|
||||
routeListNode.add(routeNode);
|
||||
}
|
||||
root.set("routing", routeListNode);
|
||||
}
|
||||
} catch (SigarException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
141
src/wa/server/plugin/hwstatus/NetStatus.tmpl
Normal file
141
src/wa/server/plugin/hwstatus/NetStatus.tmpl
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
<div id="net-container"></div>
|
||||
|
||||
<div class="col-md-9"><div class="panel panel-default">
|
||||
<div class="panel-heading">Routing Table</div>
|
||||
<div class="panel-body">
|
||||
<table id="routing-table" class="table table-hover small" data-sort-name="metric">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="interface" data-sortable="true"><b>Interface</b></th>
|
||||
<th data-field="destination" data-sortable="true">Destination</th>
|
||||
<th data-field="gateway" data-sortable="true">Gateway</th>
|
||||
<th data-field="netmask" data-sortable="true">Netmask</th>
|
||||
<th data-field="flags" data-sortable="true">Flags</th>
|
||||
<th data-field="metric" data-sortable="true">Metric</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
|
||||
<div id="template" class="hidden">
|
||||
<div id="" class="col-md-6"><div class="panel panel-default">
|
||||
<div class="panel-heading net-title"></div>
|
||||
<div class="panel-body">
|
||||
<div class="col-md-8">
|
||||
<div><canvas class="net-graph" height="370"></canvas></div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<table class="table small net-detail">
|
||||
<tr><th>Name</th><td class="net-name"></td></tr>
|
||||
<tr><th>Status</th><td class="net-up"></td></tr>
|
||||
<tr><th>IP</th><td class="net-ip"></td></tr>
|
||||
<tr><th>Netmask</th><td class="net-netmask"></td></tr>
|
||||
<tr><th>Total Rx</th><td class="net-total-rx"></td></tr>
|
||||
<tr><th>Total Tx</th><td class="net-total-tx"></td></tr>
|
||||
<tr><th>Dropped</th><td class="net-dropped"></td></tr>
|
||||
<tr><th>Errors</th><td class="net-error"></td></tr>
|
||||
<tr><th>Mac</th><td class="net-mac"></td></tr>
|
||||
<tr><th>Type</th><td class="net-type"></td></tr>
|
||||
<tr><th>Flags</th><td class="net-flags"></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<!--<div><canvas id="hdd-io" height="400"></canvas></div>-->
|
||||
</div>
|
||||
</div></div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script language="javascript" type="text/javascript">
|
||||
$(function() {
|
||||
updateNet();
|
||||
updateRoutingTable();
|
||||
});
|
||||
|
||||
var net_chart = [];
|
||||
var net_chart_data = {
|
||||
labels : ["","","","","","","","","",""],
|
||||
datasets: [
|
||||
{
|
||||
label: "Tx",
|
||||
strokeColor: "rgba(255,0,0,1)",
|
||||
fillColor: "rgba(255,0,0,0.2)",
|
||||
data: [0,0,0,0,0,0,0,0,0,0,0]
|
||||
},{
|
||||
label: "Rx",
|
||||
strokeColor: "rgba(0,255,0,1)",
|
||||
fillColor: "rgba(0,255,0,0.2)",
|
||||
data: [0,0,0,0,0,0,0,0,0,0,0]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
function updateNet(){
|
||||
$.getJSON("{{nav.url}}&json&net", function( data ) {
|
||||
$.each(data['net'], function( index, net ){
|
||||
var element = null;
|
||||
var html_id = "net-" + net.id;
|
||||
if($("#"+html_id).length)
|
||||
element = $("#" + html_id);
|
||||
else{ // Create new element
|
||||
element = $("#template").children().clone();
|
||||
$(element).attr("id", html_id);
|
||||
$(element).appendTo("#net-container");
|
||||
// Set static values
|
||||
$(element).find(".net-title").html(net.desc);
|
||||
//$(element).find(".net-desc").html(net.desc);
|
||||
$(element).find(".net-name").html(net.name);
|
||||
/// Create Graph
|
||||
var ctx = $(element).find(".net-graph").get(0).getContext("2d");
|
||||
net_chart[net.id] = new Chart(ctx).Line(net_chart_data, {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false, // Fixes stuped behaviour with size
|
||||
datasetFill: true, pointDot: false, showTooltips: false, scaleShowVerticalLines: false,
|
||||
animation : false,
|
||||
});
|
||||
}
|
||||
|
||||
$(element).find(".net-rx").html(byteToString(net.rx));
|
||||
$(element).find(".net-tx").html(byteToString(net.tx));
|
||||
$(element).find(".net-total-rx").html(byteToString(net.total_rx));
|
||||
$(element).find(".net-total-tx").html(byteToString(net.total_tx));
|
||||
$(element).find(".net-dropped").html(net.dropped);
|
||||
$(element).find(".net-error").html(net.error);
|
||||
$(element).find(".net-up").html( (net.up ? "UP" : "DOWN") );
|
||||
$(element).find(".net-ip").html(net.ip);
|
||||
$(element).find(".net-netmask").html(net.netmask);
|
||||
$(element).find(".net-mac").html(net.mac);
|
||||
$(element).find(".net-type").html(net.type);
|
||||
$(element).find(".net-flags").html(net.flags);
|
||||
|
||||
// Update Graph
|
||||
net_chart[net.id].addData([net.tx, net.rx], "");
|
||||
net_chart[net.id].removeData();
|
||||
});
|
||||
});
|
||||
setTimeout(updateNet, 2000);
|
||||
}
|
||||
|
||||
var sizes = ["YB", "ZB", "EB", "PB", "TB", "GB", "MB", "kB", "B"];
|
||||
function byteToString(value){
|
||||
var total = sizes.length-1;
|
||||
|
||||
for(; value > 1024 ;--total) {
|
||||
value /= 1024;
|
||||
}
|
||||
|
||||
value = Math.round(value*10)/10;
|
||||
return value+" "+sizes[total];
|
||||
}
|
||||
|
||||
function updateRoutingTable(){
|
||||
$.getJSON("{{nav.url}}&json&routing", function( data ) {
|
||||
$("#routing-table").bootstrapTable({
|
||||
data: data['routing']
|
||||
});
|
||||
});
|
||||
setTimeout(updateNet, 30000);
|
||||
}
|
||||
</script>
|
||||
51
src/wa/server/util/ThroughputCalculator.java
Normal file
51
src/wa/server/util/ThroughputCalculator.java
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package wa.server.util;
|
||||
|
||||
/**
|
||||
* Created by Ziver Koc
|
||||
*/
|
||||
public class ThroughputCalculator {
|
||||
public static final float UPDATES_PER_SEC = 1;
|
||||
public static final double NANOSEC_PER_SECOND = 1000000000.0;
|
||||
|
||||
private boolean updated;
|
||||
private double throughput;
|
||||
private long previousTimeStamp;
|
||||
private long data_amount;
|
||||
private long total_data_amount;
|
||||
private float frequency = UPDATES_PER_SEC;
|
||||
|
||||
public void setTotalHandledData(long bytes){
|
||||
setHandledData(bytes - total_data_amount);
|
||||
total_data_amount = bytes;
|
||||
}
|
||||
public void setHandledData(long bytes){
|
||||
long currentTimeStamp = System.nanoTime();
|
||||
data_amount += bytes;
|
||||
if(currentTimeStamp - (NANOSEC_PER_SECOND/frequency) > previousTimeStamp) {
|
||||
throughput = data_amount / ((currentTimeStamp - previousTimeStamp) / NANOSEC_PER_SECOND);
|
||||
previousTimeStamp = currentTimeStamp;
|
||||
data_amount = 0;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
public double getByteThroughput(){
|
||||
setHandledData(0); // Update throughput
|
||||
updated = false;
|
||||
return throughput;
|
||||
}
|
||||
public double getBitThroughput(){
|
||||
return getByteThroughput()*8;
|
||||
}
|
||||
|
||||
public boolean isUpdated(){
|
||||
return updated;
|
||||
}
|
||||
|
||||
public void setFrequency(float frequency) {
|
||||
if(frequency < 0)
|
||||
this.frequency = UPDATES_PER_SEC;
|
||||
else
|
||||
this.frequency = frequency;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue