103 أسطر
3.5 KiB
HTML
103 أسطر
3.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ar" dir="rtl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>مراقبة mithal.space</title>
|
|
<style>
|
|
body { font-family: Arial; background: #0f172a; color: #e2e8f0; padding: 30px; }
|
|
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 15px; margin-bottom: 20px; }
|
|
.card { background: #1e293b; padding: 20px; border-radius: 10px; }
|
|
.big { font-size: 28px; font-weight: bold; }
|
|
.status-up { color: #22c55e; }
|
|
.status-down { color: #ef4444; }
|
|
canvas { background: #1e293b; border-radius: 10px; padding: 10px; }
|
|
table { width: 100%; border-collapse: collapse; margin-top: 10px; }
|
|
td, th { padding: 8px; border-bottom: 1px solid #334155; text-align: right; font-size: 13px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>لوحة مراقبة mithal.space</h1>
|
|
|
|
<div class="grid">
|
|
<div class="card">
|
|
<div>نسبة التشغيل (24 ساعة)</div>
|
|
<div class="big" id="uptime-pct">-</div>
|
|
</div>
|
|
<div class="card">
|
|
<div>حالة SSL</div>
|
|
<div class="big" id="ssl-status">-</div>
|
|
</div>
|
|
<div class="card">
|
|
<div>آخر زمن استجابة</div>
|
|
<div class="big" id="latest-latency">-</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div>زمن الاستجابة — آخر ساعة</div>
|
|
<canvas id="latencyChart" height="80"></canvas>
|
|
</div>
|
|
|
|
<div class="card" style="margin-top:15px;">
|
|
<h3>آخر 10 فحوصات</h3>
|
|
<table id="log-table">
|
|
<thead><tr><th>الوقت</th><th>الحالة</th><th>الاستجابة</th><th>SSL</th><th>DNS</th></tr></thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js"></script>
|
|
<script>
|
|
let chart;
|
|
|
|
async function loadData() {
|
|
const res = await fetch('mithal_monitor_log.json');
|
|
const text = await res.text();
|
|
const lines = text.trim().split('\n').filter(Boolean).map(JSON.parse);
|
|
|
|
const last = lines[lines.length - 1];
|
|
const upCount = lines.filter(l => l.uptime.up).length;
|
|
const uptimePct = ((upCount / lines.length) * 100).toFixed(1);
|
|
|
|
document.getElementById('uptime-pct').innerHTML =
|
|
`<span class="${uptimePct > 95 ? 'status-up' : 'status-down'}">${uptimePct}%</span>`;
|
|
document.getElementById('ssl-status').innerHTML = last.ssl.valid
|
|
? `<span class="status-up">صالحة (${last.ssl.days_until_expiry} يوم)</span>`
|
|
: `<span class="status-down">غير صالحة</span>`;
|
|
document.getElementById('latest-latency').innerText = last.uptime.latency_ms + ' ms';
|
|
|
|
const recent = lines.slice(-60);
|
|
const labels = recent.map(l => new Date(l.timestamp).toLocaleTimeString('ar-EG'));
|
|
const data = recent.map(l => l.uptime.latency_ms);
|
|
|
|
if (chart) {
|
|
chart.data.labels = labels;
|
|
chart.data.datasets[0].data = data;
|
|
chart.update();
|
|
} else {
|
|
chart = new Chart(document.getElementById('latencyChart'), {
|
|
type: 'line',
|
|
data: { labels, datasets: [{ label: 'ms', data, borderColor: '#38bdf8', tension: 0.3 }] },
|
|
options: { plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true } } }
|
|
});
|
|
}
|
|
|
|
const tbody = document.querySelector('#log-table tbody');
|
|
tbody.innerHTML = '';
|
|
lines.slice(-10).reverse().forEach(l => {
|
|
tbody.innerHTML += `<tr>
|
|
<td>${new Date(l.timestamp).toLocaleTimeString('ar-EG')}</td>
|
|
<td>${l.uptime.up ? '✅' : '❌'}</td>
|
|
<td>${l.uptime.latency_ms} ms</td>
|
|
<td>${l.ssl.valid ? '✅' : '❌'}</td>
|
|
<td>${l.dns.dns_time_ms} ms</td>
|
|
</tr>`;
|
|
});
|
|
}
|
|
|
|
loadData();
|
|
setInterval(loadData, 60000);
|
|
</script>
|
|
</body>
|
|
</html>
|