<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/groundwork/w3.css" rel>
<title>Status</title>
</head>
<body>
<div style="position: sticky; top: 0;">
<div class="w3-green">
<span id="name" class="stats-api-value"></span>
runing on hostname:
<span id="hostname" class="stats-api-value"></span>
</div>
<div class="w3-bar w3-dark-gray" id="tab-bar">
<button class="w3-bar-item w3-button w3-circle w3-black" onclick="refreshCurrent()">
<svg fill="#e2e2e2" width="15px" version="1.1" viewBox="0 0 487.23 487.23" stroke="#e2e2e2">
<path
d="M55.323,203.641c15.664,0,29.813-9.405,35.872-23.854c25.017-59.604,83.842-101.61,152.42-101.61 c37.797,0,72.449,12.955,100.23,34.442l-21.775,3.371c-7.438,1.153-13.224,7.054-14.232,14.512 c-1.01,7.454,3.008,14.686,9.867,17.768l119.746,53.872c5.249,2.357,11.33,1.904,16.168-1.205 c4.83-3.114,7.764-8.458,7.796-14.208l0.621-131.943c0.042-7.506-4.851-14.144-12.024-16.332 c-7.185-2.188-14.947,0.589-19.104,6.837l-16.505,24.805C370.398,26.778,310.1,0,243.615,0C142.806,0,56.133,61.562,19.167,149.06 c-5.134,12.128-3.84,26.015,3.429,36.987C29.865,197.023,42.152,203.641,55.323,203.641z">
</path>
<path
d="M464.635,301.184c-7.27-10.977-19.558-17.594-32.728-17.594c-15.664,0-29.813,9.405-35.872,23.854 c-25.018,59.604-83.843,101.61-152.42,101.61c-37.798,0-72.45-12.955-100.232-34.442l21.776-3.369 c7.437-1.153,13.223-7.055,14.233-14.514c1.009-7.453-3.008-14.686-9.867-17.768L49.779,285.089 c-5.25-2.356-11.33-1.905-16.169,1.205c-4.829,3.114-7.764,8.458-7.795,14.207l-0.622,131.943 c-0.042,7.506,4.85,14.144,12.024,16.332c7.185,2.188,14.948-0.59,19.104-6.839l16.505-24.805 c44.004,43.32,104.303,70.098,170.788,70.098c100.811,0,187.481-61.561,224.446-149.059 C473.197,326.043,471.903,312.157,464.635,301.184z">
</path>
</svg>
</button>
<button class="w3-bar-item w3-button" onclick="openTab('Resources', this, getStats)">Resources</button>
<button class="w3-bar-item w3-button" onclick="openTab('Logs', this, getLogs)">Logs</button>
<button class="w3-bar-item w3-button" onclick="openTab('Calls', this, getCalls)">Calls</button>
<button class="w3-bar-item w3-button" onclick="openTab('Descriptors', this, getDescriptors)">
Descriptors
</button>
</div>
</div>
<div id="Resources" class="w3-container tab">
<table>
<tr>
<td>Virtual Memory</td>
<td id="memVirtual" class="stats-api-value"></td>
</tr>
<tr>
<td>RSS Memory</td>
<td id="memRss" class="stats-api-value"></td>
</tr>
<tr>
<td>RSS Memory Peak</td>
<td id="memRssPeak" class="stats-api-value"></td>
</tr>
<tr>
<td>Allocated bytes</td>
<td id="memAllocatedBytes" class="stats-api-value"></td>
</tr>
<tr>
<td>Allocations</td>
<td id="allocations" class="stats-api-value"></td>
</tr>
<tr>
<td>Open Descriptors</td>
<td id="fdCount" class="stats-api-value"></td>
</tr>
<tr>
<td>Thread count</td>
<td id="threadsCount" class="stats-api-value"></td>
</tr>
<tr>
<td>Uset Time</td>
<td id="userTimeUs" class="stats-api-value"></td>
</tr>
<tr>
<td>System Time</td>
<td id="systemTimeUs" class="stats-api-value"></td>
</tr>
<tr>
<td>Start Time</td>
<td id="startTimeMs" class="stats-api-value"></td>
</tr>
</table>
</div>
<div id="Logs" class="w3-container tab" style="display:none">
<div id="logs" class="w3-code">
</div>
</div>
<div id="Calls" class="w3-container tab" style="display:none">
<table class="w3-table-all w3-bordered w3-striped w3-border test w3-hoverable">
<tbody>
<tr class="w3-green">
<th>Timestamp</th>
<th>Duration</th>
<th>URL</th>
<th>Result</th>
</tr>
</tbody>
<tbody id="callsTable">
</tbody>
</table>
</div>
<div id="Descriptors" class="w3-container tab" style="display:none">
<table class="w3-table-all w3-bordered w3-striped w3-border test w3-hoverable">
<tbody>
<tr class="w3-green">
<th>#</th>
<th>Type</th>
<th>Details</th>
</tr>
</tbody>
<tbody id="descriptorTable">
</tbody>
</table>
</div>
<script>
function getStats() {
fetch('/groundwork/stats')
.then(c => c.json())
.then(c => {
const fields = document.getElementsByClassName("stats-api-value");
for (const filed of fields) {
if (filed.id.startsWith('mem')) {
filed.innerText = humanSize(c[filed.id]);
} else if (filed.id.endsWith('TimeMs')) {
filed.innerText = humanTimestampMs(c[filed.id]);
} else if (filed.id.endsWith('TimeUs')) {
filed.innerText = humanDurationUs(c[filed.id]);
} else {
filed.innerText = c[filed.id];
}
}
});
}
function getLogs() {
fetch('/groundwork/logs')
.then(c => c.json())
.then(c => {
document.getElementById("logs").innerText = c.map(l => l.trim()).join('\n');
});
}
function getCalls() {
const convertResponse = (response) => {
if (response.ok) {
return `<span class="w3-green">OK length: ${response.ok.length}</span>`;
}
return `<span class="w3-red">ERROR code: ${response.error.code}</span>`;
};
fetch('/groundwork/calls')
.then(c => c.json())
.then(cs => {
document.getElementById("callsTable").innerHTML =
cs.map(c => `<tr><td>${humanTimestampMs(c.timestampMs)}</td><td>${humanDurationUs(c.durationUs)}</td><td>${c.path}</td><td>${convertResponse(c.response)}</td><tr>`)
.join('');
});
}
function getDescriptors() {
fetch('/groundwork/descriptors')
.then(c => c.json())
.then(ds => {
document.getElementById("descriptorTable").innerHTML =
ds.map(d => `<tr><td>${d.n}</td><td>${d.kind}</td><td>${d.details}</td><tr>`)
.join('');
});
}
window.onload = getStats;
currentFunction = getStats
function refreshCurrent() {
currentFunction()
}
function openTab(name, button, func) {
func()
currentFunction = func
const bar = document.getElementById("tab-bar");
for (const item of bar.children) {
item.classList.remove("w3-gray")
}
button.classList.add("w3-gray")
const tabs = document.getElementsByClassName("tab");
for (const tab of tabs) {
tab.style.display = "none";
}
document.getElementById(name).style.display = "block";
}
// from https://stackoverflow.com/questions/10420352/converting-file-size-in-bytes-to-human-readable-string
function humanSize(size) {
var i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
return +((size / Math.pow(1024, i)).toFixed(2)) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
}
function humanDurationUs(us) {
const hours = us / 3600_000_000;
const seconds = (us / 1000_000).toFixed(3);
if (hours > 1) {
return `${hours} hours (${seconds} seconds)`
}
if (seconds > 0) {
return `${seconds} seconds`;
}
return `${us} µs`;
}
function humanTimestampMs(ms) {
return new Date(ms).toISOString();
}
</script>
</body>
</html>