هذا الالتزام موجود في:
ayashosha
2026-07-29 05:13:59 +03:00
الأصل f35ecb4d6c
التزام 91e3e0f709
6 ملفات معدلة مع 312 إضافات و0 حذوفات

عرض الملف

@@ -0,0 +1,5 @@
FROM python:3.12-slim
WORKDIR /app
COPY monitor.py dashboard.html ./
EXPOSE 5000
CMD ["python", "monitor.py"]

ملف ثنائي غير معروض.

عرض الملف

@@ -0,0 +1,142 @@
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>mithal.space monitor</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body {
font-family: Arial, sans-serif;
background: #1a1a2e;
color: #eee;
padding: 20px;
margin: 0;
}
h1 { margin-top: 0; }
.box {
background: #16213e;
padding: 15px;
margin-bottom: 15px;
border-radius: 8px;
}
.big { font-size: 32px; font-weight: bold; }
.ok { color: #4caf50; }
.bad { color: #f44336; }
table { width: 100%; border-collapse: collapse; }
th, td {
border-bottom: 1px solid #333;
padding: 8px;
text-align: right;
}
</style>
</head>
<body>
<h1>mithal.space — Monitoring</h1>
<p id="status">loading...</p>
<div class="box">
<div>Uptime (24h)</div>
<div class="big" id="uptime">-</div>
</div>
<div class="box">
<div>SSL (days left)</div>
<div class="big" id="ssl">-</div>
<div id="sslDate"></div>
</div>
<div class="box">
<div>Latency last hour</div>
<canvas id="chart"></canvas>
</div>
<div class="box">
<div>Last 10 checks</div>
<table>
<thead>
<tr>
<th>time</th>
<th>latency</th>
<th>dns</th>
<th>search</th>
<th>status</th>
<th>result</th>
</tr>
</thead>
<tbody id="rows"></tbody>
</table>
</div>
<script>
let chart
function loadData() {
fetch('metrics.json')
.then(r => r.json())
.then(data => {
if (!data.length) return
const last = data[data.length - 1]
document.getElementById('status').textContent =
last.uptime ? 'site is UP' : 'site is DOWN'
document.getElementById('status').className = last.uptime ? 'ok' : 'bad'
const dayAgo = Date.now() - 24 * 60 * 60 * 1000
const dayData = data.filter(d => new Date(d.timestamp).getTime() > dayAgo)
const upCount = dayData.filter(d => d.uptime).length
const uptimePct = dayData.length ? (upCount / dayData.length * 100).toFixed(2) : 0
document.getElementById('uptime').textContent = uptimePct + '%'
document.getElementById('ssl').textContent =
last.ssl_days_remaining != null ? last.ssl_days_remaining + ' days' : 'n/a'
document.getElementById('sslDate').textContent =
last.ssl_expires ? 'expires: ' + last.ssl_expires : ''
const hourAgo = Date.now() - 60 * 60 * 1000
const hourData = data.filter(d => new Date(d.timestamp).getTime() > hourAgo)
const labels = hourData.map(d => d.timestamp.slice(11, 19))
const values = hourData.map(d => d.latency_ms)
if (!chart) {
chart = new Chart(document.getElementById('chart'), {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'ms',
data: values,
borderColor: '#4fc3f7',
tension: 0.2
}]
}
})
} else {
chart.data.labels = labels
chart.data.datasets[0].data = values
chart.update()
}
const last10 = data.slice(-10).reverse()
document.getElementById('rows').innerHTML = last10.map(d => `
<tr>
<td>${d.timestamp.replace('T', ' ').replace('Z', '')}</td>
<td>${d.latency_ms} ms</td>
<td>${d.dns_ms} ms</td>
<td>${d.search_ms} ms</td>
<td>${d.status_code}</td>
<td class="${d.overall ? 'ok' : 'bad'}">${d.overall ? 'ok' : 'fail'}</td>
</tr>
`).join('')
})
.catch(() => {
document.getElementById('status').textContent = 'cannot load metrics.json'
document.getElementById('status').className = 'bad'
})
}
loadData()
setInterval(loadData, 30000)
</script>
</body>
</html>

عرض الملف

@@ -0,0 +1,2 @@
timestamp,latency_ms,uptime,status_code,ssl_valid,ssl_expires,ssl_days_remaining,dns_ms,search_ms,search_status_code,overall
2026-07-29T01:55:40.917123+00:00,705.91,True,200,True,2026-09-15T13:10:47+00:00,48,0.54,1684.08,200,True
1 timestamp latency_ms uptime status_code ssl_valid ssl_expires ssl_days_remaining dns_ms search_ms search_status_code overall
2 2026-07-29T01:55:40.917123+00:00 705.91 True 200 True 2026-09-15T13:10:47+00:00 48 0.54 1684.08 200 True

عرض الملف

@@ -0,0 +1,41 @@
[
{
"timestamp": "2026-07-29T01:55:40.917123+00:00",
"latency_ms": 705.91,
"uptime": true,
"status_code": 200,
"ssl_valid": true,
"ssl_expires": "2026-09-15T13:10:47+00:00",
"ssl_days_remaining": 48,
"dns_ms": 0.54,
"search_ms": 1684.08,
"search_status_code": 200,
"overall": true
},
{
"timestamp": "2026-07-29T02:06:20.105132Z",
"latency_ms": 515.49,
"uptime": true,
"status_code": 200,
"dns_ms": 10.14,
"ssl_valid": false,
"ssl_expires": "Sep 15 13:10:47 2026 GMT",
"ssl_days_remaining": null,
"search_ms": 476.59,
"search_status_code": 200,
"overall": false
},
{
"timestamp": "2026-07-29T02:06:35.031662Z",
"latency_ms": 502.26,
"uptime": true,
"status_code": 200,
"dns_ms": 0.51,
"ssl_valid": false,
"ssl_expires": "Sep 15 13:10:47 2026 GMT",
"ssl_days_remaining": null,
"search_ms": 496.97,
"search_status_code": 200,
"overall": false
}
]

عرض الملف

@@ -0,0 +1,122 @@
import json
import os
import socket
import ssl
import threading
import time
from datetime import datetime
from http.server import HTTPServer, SimpleHTTPRequestHandler
from urllib.error import HTTPError
from urllib.request import urlopen
URL = "https://mithal.space"
SEARCH_URL = "https://mithal.space/search?q=test"
HOST = "mithal.space"
METRICS_FILE = "metrics.json"
def check_http(url):
start = time.time()
status = 0
ok = False
try:
res = urlopen(url, timeout=15)
status = res.status
ok = status == 200
res.read(1024)
except HTTPError as e:
status = e.code
ok = status == 200
except Exception:
ok = False
ms = round((time.time() - start) * 1000, 2)
return ms, status, ok
def check_dns():
start = time.time()
ok = False
try:
socket.gethostbyname(HOST)
ok = True
except Exception:
ok = False
ms = round((time.time() - start) * 1000, 2)
return ms, ok
def check_ssl():
valid = False
expires = None
days_left = None
try:
ctx = ssl.create_default_context()
with socket.create_connection((HOST, 443), timeout=10) as s:
with ctx.wrap_socket(s, server_hostname=HOST) as ss:
cert = ss.getpeercert()
expires = cert["notAfter"]
exp_date = datetime.strptime(expires, "%b %d %H:%M:%S %Y %GMT")
days_left = (exp_date - datetime.utcnow()).days
valid = True
except Exception:
pass
return valid, expires, days_left
def run_check():
latency, status_code, uptime = check_http(URL)
dns_ms, dns_ok = check_dns()
ssl_ok, ssl_expires, ssl_days = check_ssl()
search_ms, search_code, search_ok = check_http(SEARCH_URL)
row = {
"timestamp": datetime.utcnow().isoformat() + "Z",
"latency_ms": latency,
"uptime": uptime,
"status_code": status_code,
"dns_ms": dns_ms,
"ssl_valid": ssl_ok,
"ssl_expires": ssl_expires,
"ssl_days_remaining": ssl_days,
"search_ms": search_ms,
"search_status_code": search_code,
"overall": uptime and dns_ok and ssl_ok and search_ok,
}
return row
def save_row(row):
data = []
if os.path.exists(METRICS_FILE):
with open(METRICS_FILE, "r", encoding="utf-8") as f:
data = json.load(f)
data.append(row)
# keep last 24 hours (1440 checks if every 1 min)
if len(data) > 1440:
data = data[-1440:]
with open(METRICS_FILE, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
def monitor_loop():
while True:
row = run_check()
save_row(row)
print(row)
time.sleep(60)
def start_server():
os.chdir(os.path.dirname(os.path.abspath(__file__)))
server = HTTPServer(("0.0.0.0", 5000), SimpleHTTPRequestHandler)
print("dashboard: http://0.0.0.0:5000/dashboard.html")
server.serve_forever()
if __name__ == "__main__":
save_row(run_check())
threading.Thread(target=monitor_loop, daemon=True).start()
start_server()