First charts for ping rendering
This commit is contained in:
parent
abb91f7baf
commit
56a412108f
@ -45,9 +45,9 @@ namespace ISPChk.Controllers
|
||||
|
||||
// GET: api/Host/5
|
||||
[HttpGet("{id}/pings/{start}/{end?}")]
|
||||
public async Task<ActionResult<Host>> GetPingsByTimeSpan(long id, long start, long end)
|
||||
public async Task<ActionResult<IEnumerable<PingItem>>> GetPingsByTimeSpan(long id, long start, long end)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("called");
|
||||
System.Diagnostics.Debug.WriteLine("called id:" + id + " start:" + start + " end:" + end);
|
||||
var host = await _context.Hosts.FindAsync(id);
|
||||
|
||||
if (host == null)
|
||||
@ -55,7 +55,13 @@ namespace ISPChk.Controllers
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return host;
|
||||
var startTime = DateTimeOffset.FromUnixTimeMilliseconds(start);
|
||||
var endTime = DateTimeOffset.FromUnixTimeMilliseconds(end);
|
||||
|
||||
_context.Entry(host).Collection(h => h.PingItems).Load();
|
||||
var pis = host.PingItems.Where(p => p.Date > startTime).ToList();
|
||||
|
||||
return pis;
|
||||
}
|
||||
|
||||
// PUT: api/Host/5
|
||||
|
@ -10,6 +10,8 @@ namespace ISPChk.Models
|
||||
public long HostId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string HostName { get; set; }
|
||||
public bool Ping { get; set; }
|
||||
public bool TCP { get; set; }
|
||||
|
||||
public List<PingItem> PingItems { get; set; }
|
||||
}
|
||||
|
@ -10,11 +10,11 @@ namespace ISPChk.Models
|
||||
{
|
||||
[Key]
|
||||
public long PingId { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public DateTimeOffset Date { get; set; }
|
||||
public float Min { get; set; }
|
||||
public float Max { get; set; }
|
||||
public float Avg { get; set; }
|
||||
public int Failures { get; set; }
|
||||
public long HostId { get; set; }
|
||||
public Host Host { get; set; }
|
||||
}
|
||||
}
|
@ -31,11 +31,10 @@ namespace ISPChk
|
||||
}
|
||||
}
|
||||
|
||||
public void AddHost(Host host)
|
||||
private void StartPing(Host host)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("Host added!");
|
||||
var t = Task.Run(async () => {
|
||||
|
||||
|
||||
Ping pingSender = new Ping();
|
||||
|
||||
// Create a buffer of 32 bytes of data to be transmitted.
|
||||
@ -55,11 +54,12 @@ namespace ISPChk
|
||||
|
||||
while (true)
|
||||
{
|
||||
long min = timeout+1;
|
||||
long min = timeout + 1;
|
||||
long max = 0;
|
||||
long avg = 0;
|
||||
int successes = 0;
|
||||
for(var i=0;i<5;++i)
|
||||
int failures = 0;
|
||||
for (var i = 0; i < 5; ++i)
|
||||
{
|
||||
// Send the request.
|
||||
PingReply reply = pingSender.Send(host.HostName, timeout, buffer, options);
|
||||
@ -71,33 +71,41 @@ namespace ISPChk
|
||||
": bytes=" + reply.Buffer.Length +
|
||||
" time=" + reply.RoundtripTime + "ms");
|
||||
avg += reply.RoundtripTime;
|
||||
if(reply.RoundtripTime < min)
|
||||
if (reply.RoundtripTime < min)
|
||||
{
|
||||
min = reply.RoundtripTime;
|
||||
}
|
||||
if(reply.RoundtripTime > max)
|
||||
if (reply.RoundtripTime > max)
|
||||
{
|
||||
max = reply.RoundtripTime;
|
||||
}
|
||||
//System.Diagnostics.Debug.WriteLine("Time to live: {0}", reply.Options.Ttl);
|
||||
//System.Diagnostics.Debug.WriteLine("Don't fragment: {0}", reply.Options.DontFragment);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(reply.Status);
|
||||
failures++;
|
||||
}
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
avg = avg / successes;
|
||||
System.Diagnostics.Debug.WriteLine("min:" + min + " max:" + max + " avg:" + avg);
|
||||
PingItem pi = new PingItem { Date = DateTime.UtcNow, Min = min, Max = max, Avg = avg };
|
||||
if(host.PingItems == null)
|
||||
host = _context.Hosts.Include(host => host.PingItems).Where(h => h.HostId == host.HostId).Single();
|
||||
PingItem pi = new PingItem { Date = DateTimeOffset.UtcNow, Min = min, Max = max, Avg = avg, Failures = failures };
|
||||
host.PingItems.Add(pi);
|
||||
_context.SaveChanges();
|
||||
Thread.Sleep(5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void AddHost(Host host)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("Host added!");
|
||||
if (host.PingItems == null)
|
||||
host = _context.Hosts.Include(host => host.PingItems).Where(h => h.HostId == host.HostId).Single();
|
||||
if(host.Ping)
|
||||
StartPing(host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:65025",
|
||||
"applicationUrl": "http://localhost:4223",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
@ -12,7 +12,7 @@
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "/",
|
||||
"launchUrl": "",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
@ -22,7 +22,7 @@
|
||||
"dotnetRunMessages": "true",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "/",
|
||||
"applicationUrl": "http://localhost:5000",
|
||||
"applicationUrl": "http://localhost:4223",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
|
BIN
ISPChk/ispchk.db
BIN
ISPChk/ispchk.db
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -10,6 +10,10 @@
|
||||
"provider": "jsdelivr",
|
||||
"library": "bootstrap@4.6.0",
|
||||
"destination": "wwwroot/bootstrap/"
|
||||
},
|
||||
{
|
||||
"library": "Chart.js@2.9.4",
|
||||
"destination": "wwwroot/Chart.js/"
|
||||
}
|
||||
]
|
||||
}
|
20776
ISPChk/wwwroot/Chart.js/Chart.bundle.js
Normal file
20776
ISPChk/wwwroot/Chart.js/Chart.bundle.js
Normal file
File diff suppressed because it is too large
Load Diff
7
ISPChk/wwwroot/Chart.js/Chart.bundle.min.js
vendored
Normal file
7
ISPChk/wwwroot/Chart.js/Chart.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
47
ISPChk/wwwroot/Chart.js/Chart.css
Normal file
47
ISPChk/wwwroot/Chart.js/Chart.css
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* DOM element rendering detection
|
||||
* https://davidwalsh.name/detect-node-insertion
|
||||
*/
|
||||
@keyframes chartjs-render-animation {
|
||||
from { opacity: 0.99; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
.chartjs-render-monitor {
|
||||
animation: chartjs-render-animation 0.001s;
|
||||
}
|
||||
|
||||
/*
|
||||
* DOM element resizing detection
|
||||
* https://github.com/marcj/css-element-queries
|
||||
*/
|
||||
.chartjs-size-monitor,
|
||||
.chartjs-size-monitor-expand,
|
||||
.chartjs-size-monitor-shrink {
|
||||
position: absolute;
|
||||
direction: ltr;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
visibility: hidden;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.chartjs-size-monitor-expand > div {
|
||||
position: absolute;
|
||||
width: 1000000px;
|
||||
height: 1000000px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.chartjs-size-monitor-shrink > div {
|
||||
position: absolute;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
16172
ISPChk/wwwroot/Chart.js/Chart.js
vendored
Normal file
16172
ISPChk/wwwroot/Chart.js/Chart.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
ISPChk/wwwroot/Chart.js/Chart.min.css
vendored
Normal file
1
ISPChk/wwwroot/Chart.js/Chart.min.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}
|
7
ISPChk/wwwroot/Chart.js/Chart.min.js
vendored
Normal file
7
ISPChk/wwwroot/Chart.js/Chart.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -5,6 +5,7 @@
|
||||
<title>ISPChk</title>
|
||||
<link href="bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="jquery/jquery.js"></script>
|
||||
<script src="Chart.js/Chart.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
@ -37,14 +38,38 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<label>Name: <input id="inpNameAdd" /></label><br />
|
||||
<label>Host: <input id="inpHostNameAdd" /></label><br />
|
||||
<button id="btnHostAdd">Add Host</button>
|
||||
<form id="frmHostAdd">
|
||||
<div>
|
||||
<label for="inpNameAdd" class="form-label">Name</label>
|
||||
<input type="text" class="form-control" id="inpNameAdd" aria-describedby="inpNameAddHelp">
|
||||
<div id="inpNameAddHelp" class="form-text">This can be anything.</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="inpHostNameAdd" class="form-label">Hostname</label>
|
||||
<input type="text" class="form-control" id="inpHostNameAdd">
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="chkPing">
|
||||
<label class="form-check-label" for="chkPing">Ping</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="chkTCP">
|
||||
<label class="form-check-label" for="chkTCP">TCP</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Host</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
Testlel
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
Testlel
|
||||
</div>
|
||||
</div>
|
||||
<div id="charts" class="row">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="ispchk.js"></script>
|
||||
<script src="bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="ispchk.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,6 +1,7 @@
|
||||
var hosts = [];
|
||||
var charts = {};
|
||||
|
||||
function createHost(host) {
|
||||
async function createHost(host) {
|
||||
$.postJSON("/api/host", host).then((res, status) => {
|
||||
console.log("POSTED" + status, res);
|
||||
if (status === "success") {
|
||||
@ -9,46 +10,139 @@ function createHost(host) {
|
||||
});
|
||||
}
|
||||
|
||||
function deleteHost(hostId) {
|
||||
$.ajax({
|
||||
url: "/api/host/"+hostId,
|
||||
async function deleteHost(hostId) {
|
||||
var res = await $.ajax({
|
||||
url: "/api/host/" + hostId,
|
||||
type: "DELETE"
|
||||
}).then(() => {
|
||||
console.log("DELETED");
|
||||
fetchHosts();
|
||||
});
|
||||
console.log("DELETED");
|
||||
fetchHosts();
|
||||
}
|
||||
|
||||
function fetchHosts() {
|
||||
async function fetchHosts() {
|
||||
var tbody = $("#tblHosts > tbody");
|
||||
tbody.empty();
|
||||
$.getJSON("/api/host").then((res) => {
|
||||
console.log("Got hosts: ", res);
|
||||
for (let host of res) {
|
||||
var row = $("<tr>",).appendTo(tbody);
|
||||
$("<td>").text(host.hostId).appendTo(row);
|
||||
$("<td>").text(host.name).appendTo(row);
|
||||
$("<td>").text(host.hostName).appendTo(row);
|
||||
$("<td>").text("Delete").click(() => {
|
||||
deleteHost(host.hostId);
|
||||
}).appendTo(row);
|
||||
}
|
||||
});
|
||||
var res = await $.getJSON("/api/host");
|
||||
console.log("Got hosts: ", res);
|
||||
for (let host of res) {
|
||||
var row = $("<tr>",).appendTo(tbody);
|
||||
$("<td>").text(host.hostId).appendTo(row);
|
||||
$("<td>").text(host.name).appendTo(row);
|
||||
$("<td>").text(host.hostName).appendTo(row);
|
||||
$("<td>").text("Delete").click(() => {
|
||||
deleteHost(host.hostId);
|
||||
}).appendTo(row);
|
||||
}
|
||||
updateGraphs(res);
|
||||
}
|
||||
|
||||
$('#btnDebug').click(function () {
|
||||
async function fetchPings(hostId, start, end) {
|
||||
var res = await $.getJSON("/api/host/" + hostId + "/pings/" + start + "/" + end);
|
||||
console.log("Fetched pings: ", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
async function transformChartData(pings) {
|
||||
var res = { date: [], min: [], avg: [], max: [], failures: []};
|
||||
for (let ping of pings) {
|
||||
res.date.push(ping.date);
|
||||
res.min.push(ping.min);
|
||||
res.avg.push(ping.avg);
|
||||
res.max.push(ping.max);
|
||||
res.failures.push(ping.failures);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
async function updateGraphs(hosts) {
|
||||
var charts = $("#charts");
|
||||
for (let host of hosts) {
|
||||
console.log("Appending ", host);
|
||||
var before = Date.now() - 300000;
|
||||
var val = await transformChartData(await fetchPings(host.hostId, before, Date.now()));
|
||||
$("<canvas>", { id: "chart_" + host.hostId, width: 200, height: 200 }).appendTo(charts);
|
||||
var ctx = document.getElementById('chart_' + host.hostId).getContext('2d');
|
||||
charts[host.hostId] = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: val.date,
|
||||
datasets: [
|
||||
{
|
||||
label: 'min',
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.3)',
|
||||
borderColor: 'rgb(255, 99, 132)',
|
||||
yAxisID: "y-latency",
|
||||
data: val.min
|
||||
},
|
||||
{
|
||||
label: 'avg',
|
||||
backgroundColor: 'rgba(99, 255, 132, 0.3)',
|
||||
borderColor: 'rgb(99, 255, 132)',
|
||||
yAxisID: "y-latency",
|
||||
data: val.avg
|
||||
},
|
||||
{
|
||||
label: 'max',
|
||||
backgroundColor: 'rgba(132, 99, 255, 0.3)',
|
||||
borderColor: 'rgb(132, 99, 255)',
|
||||
yAxisID: "y-latency",
|
||||
data: val.max
|
||||
},
|
||||
]
|
||||
},
|
||||
options: {
|
||||
title: {
|
||||
display: true,
|
||||
text: host.name
|
||||
},
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
id: "y-latency",
|
||||
position: "left",
|
||||
ticks: {
|
||||
suggestedMin: 10,
|
||||
suggestedMax: 40
|
||||
}
|
||||
},/*
|
||||
{
|
||||
id: "y-avg",
|
||||
position: "left",
|
||||
ticks: {
|
||||
suggestedMin: 950,
|
||||
suggestedMax: 1050
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "y-max",
|
||||
position: "right",
|
||||
ticks: {
|
||||
suggestedMin: 0,
|
||||
suggestedMax: 100
|
||||
}
|
||||
},*/
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$('#btnDebug').click(async () => {
|
||||
console.log("DEBUG");
|
||||
$.getJSON("/api/host/" + id + "/pings/" + Date.now + "/" + Date.now).then((res) => {
|
||||
console.log("CALLED: res ", res);
|
||||
});
|
||||
});
|
||||
|
||||
$('#btnHostAdd').click(function () {
|
||||
$("#frmHostAdd").submit((event) => {
|
||||
event.preventDefault();
|
||||
var name = $("#inpNameAdd").val();
|
||||
var hostname = $("#inpHostNameAdd").val();
|
||||
var ping = $('#chkPing').prop('checked')
|
||||
var tcp = $('#chkPing').prop('checked')
|
||||
var host = {
|
||||
name: name,
|
||||
hostname: hostname
|
||||
hostname: hostname,
|
||||
ping: ping,
|
||||
tcp: tcp
|
||||
}
|
||||
createHost(host);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user