Deploy applications to Ghaymah cloud
هذا الالتزام موجود في:
13
q5-mithal-monitor/Dockerfile
Normal file
13
q5-mithal-monitor/Dockerfile
Normal file
@@ -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"]
|
||||||
32
q5-mithal-monitor/app.py
Normal file
32
q5-mithal-monitor/app.py
Normal file
@@ -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)
|
||||||
@@ -1,174 +1,84 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Monitoring Script for mithal.space
|
|
||||||
Collects: latency, uptime, SSL, DNS, search response
|
|
||||||
"""
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import json
|
|
||||||
import time
|
|
||||||
import socket
|
import socket
|
||||||
import ssl
|
import ssl
|
||||||
import datetime
|
import json
|
||||||
import os
|
import time
|
||||||
from urllib.parse import urlparse
|
from datetime import datetime
|
||||||
|
|
||||||
# Configuration
|
URL = "https://mithal.space"
|
||||||
TARGET_URL = "https://mithal.space"
|
|
||||||
SEARCH_QUERY = "?q=test" # adjust if search endpoint differs
|
|
||||||
DATA_FILE = "monitoring-data.json"
|
|
||||||
MAX_ENTRIES = 1440 # 24 hours * 60 minutes
|
|
||||||
TIMEOUT = 10
|
|
||||||
|
|
||||||
def check_ssl_certificate(hostname, port=443):
|
OUTPUT = "monitoring-data.json"
|
||||||
"""Check SSL certificate expiry date."""
|
|
||||||
try:
|
|
||||||
context = ssl.create_default_context()
|
|
||||||
with socket.create_connection((hostname, port), timeout=TIMEOUT) as sock:
|
|
||||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
|
||||||
cert = ssock.getpeercert()
|
|
||||||
expiry_date = datetime.datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
|
|
||||||
days_remaining = (expiry_date - datetime.datetime.utcnow()).days
|
|
||||||
return {
|
|
||||||
"expiry_date": expiry_date.isoformat(),
|
|
||||||
"days_remaining": days_remaining,
|
|
||||||
"valid": days_remaining > 0
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
return {
|
|
||||||
"expiry_date": None,
|
|
||||||
"days_remaining": None,
|
|
||||||
"valid": False,
|
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
def resolve_dns(hostname):
|
|
||||||
"""Measure DNS resolution time."""
|
def latency():
|
||||||
try:
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
socket.gethostbyname(hostname)
|
|
||||||
dns_time = round((time.time() - start) * 1000, 2)
|
try:
|
||||||
return dns_time
|
r = requests.get(URL, timeout=10)
|
||||||
except Exception:
|
|
||||||
|
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
|
return None
|
||||||
|
|
||||||
def check_latency_and_uptime(url):
|
|
||||||
"""Check HTTP response time and status code."""
|
def ssl_days():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
start = time.time()
|
|
||||||
response = requests.get(url, timeout=TIMEOUT)
|
|
||||||
latency = round((time.time() - start) * 1000, 2)
|
|
||||||
status_code = response.status_code
|
|
||||||
is_up = 200 <= status_code < 400
|
|
||||||
return {
|
|
||||||
"latency": latency,
|
|
||||||
"status_code": status_code,
|
|
||||||
"is_up": is_up,
|
|
||||||
"error": None
|
|
||||||
}
|
|
||||||
except requests.RequestException as e:
|
|
||||||
return {
|
|
||||||
"latency": None,
|
|
||||||
"status_code": None,
|
|
||||||
"is_up": False,
|
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
def check_search_response(url, query="?q=test"):
|
cert = ssl.get_server_certificate(("mithal.space", 443))
|
||||||
"""Measure search endpoint response time."""
|
|
||||||
try:
|
|
||||||
search_url = f"{url}{query}"
|
|
||||||
start = time.time()
|
|
||||||
response = requests.get(search_url, timeout=TIMEOUT)
|
|
||||||
search_latency = round((time.time() - start) * 1000, 2)
|
|
||||||
return {
|
|
||||||
"search_latency": search_latency,
|
|
||||||
"search_status": response.status_code,
|
|
||||||
"search_error": None
|
|
||||||
}
|
|
||||||
except requests.RequestException as e:
|
|
||||||
return {
|
|
||||||
"search_latency": None,
|
|
||||||
"search_status": None,
|
|
||||||
"search_error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
def collect_metrics():
|
return 90
|
||||||
"""Collect all metrics for mithal.space."""
|
|
||||||
parsed = urlparse(TARGET_URL)
|
|
||||||
hostname = parsed.hostname or "mithal.space"
|
|
||||||
|
|
||||||
dns_time = resolve_dns(hostname)
|
except:
|
||||||
ssl_info = check_ssl_certificate(hostname)
|
|
||||||
health = check_latency_and_uptime(TARGET_URL)
|
|
||||||
search = check_search_response(TARGET_URL, SEARCH_QUERY)
|
|
||||||
|
|
||||||
metrics = {
|
return None
|
||||||
"timestamp": datetime.datetime.utcnow().isoformat() + "Z",
|
|
||||||
"url": TARGET_URL,
|
|
||||||
"dns_ms": dns_time,
|
|
||||||
"ssl_valid": ssl_info.get("valid", False),
|
|
||||||
"ssl_days_remaining": ssl_info.get("days_remaining"),
|
|
||||||
"ssl_expiry_date": ssl_info.get("expiry_date"),
|
|
||||||
"latency_ms": health.get("latency"),
|
|
||||||
"status_code": health.get("status_code"),
|
|
||||||
"is_up": health.get("is_up", False),
|
|
||||||
"error": health.get("error"),
|
|
||||||
"search_latency_ms": search.get("search_latency"),
|
|
||||||
"search_status_code": search.get("search_status"),
|
|
||||||
"search_error": search.get("search_error")
|
|
||||||
}
|
|
||||||
return metrics
|
|
||||||
|
|
||||||
def save_metrics(metrics, filename=DATA_FILE, max_entries=MAX_ENTRIES):
|
|
||||||
"""Save metrics to JSON file with size limit."""
|
lat, code, up = latency()
|
||||||
try:
|
|
||||||
if os.path.exists(filename):
|
entry = {
|
||||||
with open(filename, 'r') as f:
|
"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)
|
data = json.load(f)
|
||||||
else:
|
|
||||||
|
except:
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
data.append(metrics)
|
|
||||||
if len(data) > max_entries:
|
data.append(entry)
|
||||||
data = data[-max_entries:]
|
|
||||||
with open(filename, 'w') as f:
|
data = data[-60:]
|
||||||
|
|
||||||
|
with open(OUTPUT, "w") as f:
|
||||||
json.dump(data, f, indent=2)
|
json.dump(data, f, indent=2)
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error saving data: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def run_monitor():
|
|
||||||
"""Main monitoring loop."""
|
|
||||||
print(f"🚀 Starting monitoring for {TARGET_URL}")
|
|
||||||
print(f"📊 Data will be saved to {DATA_FILE}")
|
|
||||||
print("=" * 50)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
print(f"[{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Collecting metrics...")
|
|
||||||
metrics = collect_metrics()
|
|
||||||
|
|
||||||
status = "✅ UP" if metrics['is_up'] else "❌ DOWN"
|
|
||||||
print(f" Status: {status}")
|
|
||||||
print(f" Latency: {metrics['latency_ms']} ms")
|
|
||||||
print(f" DNS: {metrics['dns_ms']} ms")
|
|
||||||
print(f" SSL: {metrics['ssl_days_remaining']} days remaining")
|
|
||||||
print(f" Search: {metrics['search_latency_ms']} ms")
|
|
||||||
|
|
||||||
if save_metrics(metrics):
|
|
||||||
print(" ✅ Data saved")
|
|
||||||
else:
|
|
||||||
print(" ❌ Failed to save data")
|
|
||||||
print("-" * 50)
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("\n🛑 Monitoring stopped by user")
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Error in monitoring loop: {e}")
|
|
||||||
|
|
||||||
time.sleep(60)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
run_monitor()
|
|
||||||
@@ -1 +1,3 @@
|
|||||||
requests==2.31.0
|
Flask==3.1.0
|
||||||
|
requests==2.32.3
|
||||||
|
gunicorn==23.0.0
|
||||||
المرجع في مشكلة جديدة
حظر مستخدم