Add Question 5 Mithal monitoring dashboard
هذا الالتزام موجود في:
179
q5-mithal-monitor/dashboard.html
Normal file
179
q5-mithal-monitor/dashboard.html
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
|
||||||
|
<title>Mithal Monitoring Dashboard</title>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
body{
|
||||||
|
|
||||||
|
font-family:Arial;
|
||||||
|
|
||||||
|
background:#f4f4f4;
|
||||||
|
|
||||||
|
text-align:center;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.card{
|
||||||
|
|
||||||
|
background:white;
|
||||||
|
|
||||||
|
padding:20px;
|
||||||
|
|
||||||
|
margin:20px auto;
|
||||||
|
|
||||||
|
width:90%;
|
||||||
|
|
||||||
|
max-width:900px;
|
||||||
|
|
||||||
|
border-radius:10px;
|
||||||
|
|
||||||
|
box-shadow:0 0 10px rgba(0,0,0,.15);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
table{
|
||||||
|
|
||||||
|
width:100%;
|
||||||
|
|
||||||
|
border-collapse:collapse;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
th,td{
|
||||||
|
|
||||||
|
border:1px solid #ddd;
|
||||||
|
|
||||||
|
padding:10px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Mithal Monitoring Dashboard</h1>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
|
||||||
|
<h2>Uptime (24 Hours)</h2>
|
||||||
|
|
||||||
|
<p id="uptime">Loading...</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
|
||||||
|
<h2>SSL Certificate</h2>
|
||||||
|
|
||||||
|
<p id="ssl">Loading...</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
|
||||||
|
<h2>Latency (Last Hour)</h2>
|
||||||
|
|
||||||
|
<canvas id="chart"></canvas>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
|
||||||
|
<h2>Last 10 Checks</h2>
|
||||||
|
|
||||||
|
<table id="table"></table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
fetch("metrics.csv")
|
||||||
|
|
||||||
|
.then(r=>r.text())
|
||||||
|
|
||||||
|
.then(text=>{
|
||||||
|
|
||||||
|
let rows=text.trim().split("\n").slice(1);
|
||||||
|
|
||||||
|
let labels=[];
|
||||||
|
|
||||||
|
let latency=[];
|
||||||
|
|
||||||
|
let success=0;
|
||||||
|
|
||||||
|
let ssl=0;
|
||||||
|
|
||||||
|
let table="<tr><th>Time</th><th>Status</th><th>Latency</th></tr>";
|
||||||
|
|
||||||
|
rows.forEach(row=>{
|
||||||
|
|
||||||
|
let c=row.split(",");
|
||||||
|
|
||||||
|
labels.push(c[0]);
|
||||||
|
|
||||||
|
latency.push(Number(c[1]));
|
||||||
|
|
||||||
|
ssl=c[3];
|
||||||
|
|
||||||
|
if(c[2]=="200") success++;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("uptime").innerHTML=
|
||||||
|
((success/rows.length)*100).toFixed(2)+" %";
|
||||||
|
|
||||||
|
document.getElementById("ssl").innerHTML=
|
||||||
|
ssl+" days remaining";
|
||||||
|
|
||||||
|
rows.slice(-10).forEach(row=>{
|
||||||
|
|
||||||
|
let c=row.split(",");
|
||||||
|
|
||||||
|
table+=`<tr>
|
||||||
|
<td>${c[0]}</td>
|
||||||
|
<td>${c[2]}</td>
|
||||||
|
<td>${c[1]} ms</td>
|
||||||
|
</tr>`;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("table").innerHTML=table;
|
||||||
|
|
||||||
|
new Chart(document.getElementById("chart"),{
|
||||||
|
|
||||||
|
type:"line",
|
||||||
|
|
||||||
|
data:{
|
||||||
|
|
||||||
|
labels:labels.slice(-60),
|
||||||
|
|
||||||
|
datasets:[{
|
||||||
|
|
||||||
|
label:"Latency (ms)",
|
||||||
|
|
||||||
|
data:latency.slice(-60)
|
||||||
|
|
||||||
|
}]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
2
q5-mithal-monitor/metrics.csv
Normal file
2
q5-mithal-monitor/metrics.csv
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
timestamp,latency_ms,status_code,ssl_days_left,dns_ms,search_ms
|
||||||
|
2026-07-28 21:48:04,1089.54,200,48,3.73,9141.39
|
||||||
|
94
q5-mithal-monitor/monitor.py
Normal file
94
q5-mithal-monitor/monitor.py
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import csv
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import ssl
|
||||||
|
import socket
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import dns.resolver
|
||||||
|
from OpenSSL import crypto
|
||||||
|
|
||||||
|
URL = "https://mithal.space"
|
||||||
|
SEARCH_URL = "https://mithal.space"
|
||||||
|
|
||||||
|
CSV_FILE = "metrics.csv"
|
||||||
|
|
||||||
|
if not os.path.exists(CSV_FILE):
|
||||||
|
with open(CSV_FILE, "w", newline="") as file:
|
||||||
|
writer = csv.writer(file)
|
||||||
|
writer.writerow([
|
||||||
|
"timestamp",
|
||||||
|
"latency_ms",
|
||||||
|
"status_code",
|
||||||
|
"ssl_days_left",
|
||||||
|
"dns_ms",
|
||||||
|
"search_ms"
|
||||||
|
])
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
# HTTP Latency + Uptime
|
||||||
|
try:
|
||||||
|
start = time.time()
|
||||||
|
response = requests.get(URL, timeout=10)
|
||||||
|
latency = round((time.time() - start) * 1000, 2)
|
||||||
|
status = response.status_code
|
||||||
|
except:
|
||||||
|
latency = -1
|
||||||
|
status = 0
|
||||||
|
|
||||||
|
# SSL
|
||||||
|
try:
|
||||||
|
cert = ssl.get_server_certificate(("mithal.space", 443))
|
||||||
|
cert = crypto.load_certificate(
|
||||||
|
crypto.FILETYPE_PEM,
|
||||||
|
cert
|
||||||
|
)
|
||||||
|
|
||||||
|
expire = datetime.strptime(
|
||||||
|
cert.get_notAfter().decode(),
|
||||||
|
"%Y%m%d%H%M%SZ"
|
||||||
|
)
|
||||||
|
|
||||||
|
ssl_days = (expire - datetime.utcnow()).days
|
||||||
|
|
||||||
|
except:
|
||||||
|
ssl_days = -1
|
||||||
|
|
||||||
|
# DNS
|
||||||
|
try:
|
||||||
|
start = time.time()
|
||||||
|
dns.resolver.resolve("mithal.space", "A")
|
||||||
|
dns_time = round((time.time() - start) * 1000, 2)
|
||||||
|
except:
|
||||||
|
dns_time = -1
|
||||||
|
|
||||||
|
# Search
|
||||||
|
try:
|
||||||
|
start = time.time()
|
||||||
|
requests.get(
|
||||||
|
SEARCH_URL,
|
||||||
|
params={"q": "cloud"},
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
search_time = round((time.time() - start) * 1000, 2)
|
||||||
|
except:
|
||||||
|
search_time = -1
|
||||||
|
|
||||||
|
with open(CSV_FILE, "a", newline="") as file:
|
||||||
|
writer = csv.writer(file)
|
||||||
|
writer.writerow([
|
||||||
|
timestamp,
|
||||||
|
latency,
|
||||||
|
status,
|
||||||
|
ssl_days,
|
||||||
|
dns_time,
|
||||||
|
search_time
|
||||||
|
])
|
||||||
|
|
||||||
|
print(timestamp, status, latency)
|
||||||
|
|
||||||
|
time.sleep(60)
|
||||||
المرجع في مشكلة جديدة
حظر مستخدم