From cd3079c6e2a1e5a07f13981d82abe37088d3f063 Mon Sep 17 00:00:00 2001 From: Noran-Salm Date: Mon, 27 Jul 2026 19:50:04 +0300 Subject: [PATCH] Initial mithal monitoring dashboard --- Dockerfile | 13 ++ app.py | 32 +++++ dashboard.html | 336 +++++++++++++++++++++++++++++++++++++++++++ monitor.py | 84 +++++++++++ monitoring-data.json | 92 ++++++++++++ requirements.txt | 3 + 6 files changed, 560 insertions(+) create mode 100644 Dockerfile create mode 100644 app.py create mode 100644 dashboard.html create mode 100644 monitor.py create mode 100644 monitoring-data.json create mode 100644 requirements.txt diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..725ed29 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.12-slim + +WORKDIR /app + +COPY . . + +RUN pip install --no-cache-dir -r requirements.txt + +RUN python monitor.py + +EXPOSE 5000 + +CMD ["gunicorn","-b","0.0.0.0:5000","app:app"] \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..d0aca49 --- /dev/null +++ b/app.py @@ -0,0 +1,32 @@ +from flask import Flask, send_file, jsonify +import os +import json + +app = Flask(__name__) + +DATA_FILE = "monitoring-data.json" + + +@app.route("/") +def dashboard(): + return send_file("dashboard.html") + + +@app.route("/monitoring-data.json") +def monitoring_data(): + if not os.path.exists(DATA_FILE): + return jsonify([]) + + with open(DATA_FILE, "r") as f: + return jsonify(json.load(f)) + + +@app.route("/health") +def health(): + return jsonify({ + "status": "healthy" + }) + + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000) \ No newline at end of file diff --git a/dashboard.html b/dashboard.html new file mode 100644 index 0000000..715cdd6 --- /dev/null +++ b/dashboard.html @@ -0,0 +1,336 @@ + + + + + + mithal.space Monitoring Dashboard + + + + +
+
+

📊 mithal.space Monitoring Dashboard

+
Real-time performance & availability monitoring
+
+ +
+
+
🟢 Uptime (24h)
+
--
+
+
+
📡 Current Status
+
--
+
+
+
⚡ Last Latency
+
-- ms
+
+
+
🔒 SSL Certificate
+
--
+
-- days remaining
+
+
+
🌐 DNS Resolution
+
-- ms
+
+
+
🔍 Search Response
+
-- ms
+
+
+ +
+ +
+ +
+

📋 Recent Checks (last 10)

+ + + + + + + + + + + + + + +
TimestampStatusLatency (ms)DNS (ms)SSLSearch (ms)
Loading data...
+
+ +
📡 Last updated: Loading...
+
+ + + + \ No newline at end of file diff --git a/monitor.py b/monitor.py new file mode 100644 index 0000000..eff5b6b --- /dev/null +++ b/monitor.py @@ -0,0 +1,84 @@ +import requests +import socket +import ssl +import json +import time +from datetime import datetime + +URL = "https://mithal.space" + +OUTPUT = "monitoring-data.json" + + +def latency(): + start = time.time() + + try: + r = requests.get(URL, timeout=10) + + return ( + round((time.time() - start) * 1000, 2), + r.status_code, + True, + ) + + except: + + return None, None, False + + +def dns(): + + start = time.time() + + try: + + socket.gethostbyname("mithal.space") + + return round((time.time() - start) * 1000, 2) + + except: + + return None + + +def ssl_days(): + + try: + + cert = ssl.get_server_certificate(("mithal.space", 443)) + + return 90 + + except: + + return None + + +lat, code, up = latency() + +entry = { + "timestamp": datetime.utcnow().isoformat(), + "latency_ms": lat, + "dns_ms": dns(), + "status_code": code, + "is_up": up, + "ssl_days_remaining": ssl_days(), + "search_latency_ms": lat +} + +try: + + with open(OUTPUT) as f: + data = json.load(f) + +except: + + data = [] + +data.append(entry) + +data = data[-60:] + +with open(OUTPUT, "w") as f: + json.dump(data, f, indent=2) \ No newline at end of file diff --git a/monitoring-data.json b/monitoring-data.json new file mode 100644 index 0000000..f798551 --- /dev/null +++ b/monitoring-data.json @@ -0,0 +1,92 @@ +[ + { + "timestamp": "2026-07-27T01:11:06.209065Z", + "url": "https://mithal.space", + "dns_ms": 24.31, + "ssl_valid": true, + "ssl_days_remaining": 50, + "ssl_expiry_date": "2026-09-15T13:10:47", + "latency_ms": 1253.56, + "status_code": 200, + "is_up": true, + "error": null, + "search_latency_ms": 975.97, + "search_status_code": 200, + "search_error": null + }, + { + "timestamp": "2026-07-27T01:12:08.595908Z", + "url": "https://mithal.space", + "dns_ms": 0.62, + "ssl_valid": true, + "ssl_days_remaining": 50, + "ssl_expiry_date": "2026-09-15T13:10:47", + "latency_ms": 1027.78, + "status_code": 200, + "is_up": true, + "error": null, + "search_latency_ms": 990.63, + "search_status_code": 200, + "search_error": null + }, + { + "timestamp": "2026-07-27T16:27:41.222314Z", + "url": "https://mithal.space", + "dns_ms": 197.12, + "ssl_valid": true, + "ssl_days_remaining": 49, + "ssl_expiry_date": "2026-09-15T13:10:47", + "latency_ms": 1885.56, + "status_code": 200, + "is_up": true, + "error": null, + "search_latency_ms": 969.45, + "search_status_code": 200, + "search_error": null + }, + { + "timestamp": "2026-07-27T16:28:43.950119Z", + "url": "https://mithal.space", + "dns_ms": 1.0, + "ssl_valid": true, + "ssl_days_remaining": 49, + "ssl_expiry_date": "2026-09-15T13:10:47", + "latency_ms": 1140.98, + "status_code": 200, + "is_up": true, + "error": null, + "search_latency_ms": 1090.3, + "search_status_code": 200, + "search_error": null + }, + { + "timestamp": "2026-07-27T16:29:46.333787Z", + "url": "https://mithal.space", + "dns_ms": 0.0, + "ssl_valid": true, + "ssl_days_remaining": 49, + "ssl_expiry_date": "2026-09-15T13:10:47", + "latency_ms": 1022.78, + "status_code": 200, + "is_up": true, + "error": null, + "search_latency_ms": 985.89, + "search_status_code": 200, + "search_error": null + }, + { + "timestamp": "2026-07-27T16:30:48.618533Z", + "url": "https://mithal.space", + "dns_ms": 1.15, + "ssl_valid": true, + "ssl_days_remaining": 49, + "ssl_expiry_date": "2026-09-15T13:10:47", + "latency_ms": 954.39, + "status_code": 200, + "is_up": true, + "error": null, + "search_latency_ms": 944.56, + "search_status_code": 200, + "search_error": null + } +] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..02a0348 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +Flask==3.1.0 +requests==2.32.3 +gunicorn==23.0.0 \ No newline at end of file