More like a library now

This commit is contained in:
Neale Pickett 2023-03-05 01:01:20 -07:00
parent 141a5bf888
commit 1fe69cd88f
3 changed files with 130 additions and 60 deletions

View File

@ -3,10 +3,16 @@
<head> <head>
<title>Webstat</title> <title>Webstat</title>
<meta charset="utf-8"> <meta charset="utf-8">
<script src="webstat.mjs" type="module"></script> <script src="main.mjs" type="module"></script>
<style>
#pie {
max-width: 50px;
}
</style>
</head> </head>
<body> <body>
<div><canvas id="stats"></canvas></div> <div id="pie"></div>
<div id="chart"></div>
</body> </body>
</html> </html>

32
web/main.mjs Normal file
View File

@ -0,0 +1,32 @@
import * as WebStat from "./webstat.mjs"
const Millisecond = 1
const Second = 1000 * Millisecond
const Minute = 60 * Second
class App {
constructor() {
this.stat = new WebStat.Stat()
this.areaChart = new WebStat.AreaChart(document.querySelector("#chart"))
this.pieChart = new WebStat.PieChart(document.querySelector("#pie"))
setInterval(()=>this.update(), 2 * Second)
}
async update() {
this.stat.update()
this.areaChart.update(this.stat)
this.pieChart.update(this.stat)
}
}
function init() {
new App()
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init)
} else {
init()
}

View File

@ -1,10 +1,6 @@
//import Chart from "https://esm.run/chart.js@4.2.1/auto" //import Chart from "https://esm.run/chart.js@4.2.1/auto"
import Chart from "https://cdn.jsdelivr.net/npm/chart.js@4.2.1/auto/+esm" import Chart from "https://cdn.jsdelivr.net/npm/chart.js@4.2.1/auto/+esm"
const Millisecond = 1
const Second = 1000 * Millisecond
const Minute = 60 * Second
function qpush(arr, val, len) { function qpush(arr, val, len) {
arr.push(val) arr.push(val)
if (arr.length > len) { if (arr.length > len) {
@ -13,36 +9,53 @@ function qpush(arr, val, len) {
} }
class Stat { class Stat {
constructor(text) { constructor() {
let lines = text.split("\n") this.Stat = {}
this.LastStat = {}
}
async update() {
let resp = await fetch("proc/stat")
let stext = await resp.text()
let lines = stext.split("\n")
this.Date = new Date(resp.headers.get("Date"))
this.LastStat = this.Stat
this.Stat = {}
for (let line of lines) { for (let line of lines) {
let parts = line.split(/\s+/) let parts = line.split(/\s+/)
let key = parts.shift() let key = parts.shift()
let vals = parts.map(Number) let vals = parts.map(Number)
if (key.startsWith("cpu")) { this.Stat[key] = vals
this[key] = {
user: vals[0],
nice: vals[1],
sys: vals[2],
idle: vals[3],
wait: vals[4],
irq: vals[5],
softirq: vals[6],
steal: vals[7],
guest: vals[8],
guestNice: vals[9],
}
} else {
this[key] = vals
}
} }
} }
cpu(n="") {
let key = `cpu${n}`
let vals = this.Stat[key]
let prev = this.LastStat[key]
if (!vals || !prev) {
return {}
}
let total = vals.reduce((a,b)=>a+b) - prev.reduce((a,b)=>a+b)
return {
user: (vals[0] - prev[0]) / total,
nice: (vals[1] - prev[1]) / total,
sys: (vals[2] - prev[2]) / total,
idle: (vals[3] - prev[3]) / total,
wait: (vals[4] - prev[4]) / total,
irq: (vals[5] - prev[5]) / total,
softirq: (vals[6] - prev[6]) / total,
steal: (vals[7] - prev[7]) / total,
guest: (vals[8] - prev[8]) / total,
guestNice: (vals[9] - prev[9]) / total,
}
}
} }
class StatUpdater { class AreaChart {
constructor(interval, width=60) { constructor(element, width=60) {
this.width = width this.width = width
this.canvas = document.querySelector("#stats") this.canvas = element.appendChild(document.createElement("canvas"))
this.data ={ this.data ={
labels: [], labels: [],
datasets: [] datasets: []
@ -78,44 +91,63 @@ class StatUpdater {
} }
} }
) )
setInterval(() => this.update(), interval)
this.update()
} }
async update() { async update(stat) {
let now = Date.now() let now = stat.Date
let resp = await fetch("proc/stat") let cpu = stat.cpu()
let stext = await resp.text() qpush(this.data.labels, now, this.width)
let stat = new Stat(stext) qpush(this.datasets.user, cpu.user, this.width)
if (this.last) { qpush(this.datasets.nice, cpu.nice, this.width)
let user = stat.cpu.user - this.last.cpu.user qpush(this.datasets.sys, cpu.sys, this.width)
let nice = stat.cpu.nice - this.last.cpu.nice qpush(this.datasets.idle, cpu.idle, this.width)
let sys = stat.cpu.sys - this.last.cpu.sys qpush(this.datasets.wait, cpu.wait, this.width)
let idle = stat.cpu.idle - this.last.cpu.idle
let wait = stat.cpu.wait - this.last.cpu.wait
let total = user + nice + sys + idle + wait
qpush(this.data.labels, now, this.width)
qpush(this.datasets.user, user/total, this.width)
qpush(this.datasets.nice, nice/total, this.width)
qpush(this.datasets.sys, sys/total, this.width)
qpush(this.datasets.idle, idle/total, this.width)
qpush(this.datasets.wait, wait/total, this.width)
//this.data.datasets[0].label= `user: ${user/total*100}`
}
this.last = stat
this.chart.update() this.chart.update()
} }
} }
function init() { class PieChart {
new StatUpdater(2*Second) constructor(element) {
this.canvas = element.appendChild(document.createElement("canvas"))
this.data ={
labels: ["user", "nice", "sys", "idle", "wait"],
datasets: []
}
this.chart = new Chart(
this.canvas,
{
type: "pie",
data: this.data,
options: {
animation: false,
borderWidth: 0,
backgroundColor: [
"red",
"green",
"orange",
"rgba(0, 64, 0, 0.2)",
"magenta",
],
plugins: {
legend: { display: false },
},
},
}
)
}
async update(stat) {
let cpu = stat.cpu()
this.data.datasets = [{
label: "Current",
data: [cpu.user, cpu.nice, cpu.sys, cpu.idle, cpu.wait],
}]
this.chart.update()
}
} }
if (document.readyState === "loading") { export {
document.addEventListener("DOMContentLoaded", init) Stat,
} else { AreaChart,
init() PieChart,
} }