welcome ghaymah
هذا الالتزام موجود في:
1
README.md
Normal file
1
README.md
Normal file
@@ -0,0 +1 @@
|
||||
https://qabilah.com/profile/abdulrahmanabdalla88/professional-profile
|
||||
35
common-mortakaz/integration-1.md
Normal file
35
common-mortakaz/integration-1.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# مقترح تكامل: منصة إدارة المشاريع "فريقي" مع مزود السحابة "غيمة" (Ghaymah.systems)
|
||||
|
||||
## 1. وصف المنتج المختار
|
||||
**"فريقي"** هي منصة عربية متكاملة لإدارة المشاريع والمهام، صُممت لتمنح الفرق العربية طريقة أوضح وأكثر سلاسة للعمل معًا، تنظيم المهام، ومتابعة الإنتاجية دون تعقيد.
|
||||
|
||||
## 2. كيف يتكامل مع ghaymah.systems
|
||||
يمكن ربط منصة "فريقي" مع البنية التحتية لمنصة **غيمة (Ghaymah.systems)** السحابية بالآلية التالية:
|
||||
* **نشر البيئات التلقائي (Automated Environment Provisioning):** ربط مهام المشروع داخل منصة "فريقي" (مثل حالة المهام عند انتقالها إلى "تم التنفيذ") بإطلاق حاويات تطوير أو بيئات اختبار (Testing Environments) مباشرة على سيرفرات "غيمة" عبر الـ Webhooks والـ APIs.
|
||||
* **مزامنة الموارد السحابية:** تتبع استهلاك الموارد المخصصة لكل مشروع فريق واستعراض مؤشراتها داخل لوحة تحكم "فريقي".
|
||||
|
||||
## 3. القيمة المضافة للمستخدم النهائي
|
||||
* **ربط دورة حياة التطوير بإدارة المهام:** الانتقال السلس من تخطيط المهام وبنائها إلى نشرها واختبارها على السحابة بضغطة زر واحدة.
|
||||
* **توفير الوقت والجهد:** إلغاء الحاجة للتدخل اليدوي لإعداد خوادم التطوير، مما يعزز كفاءة فرق الـ DevOps والـ Developers العرب.
|
||||
* **متابعة موحدة:** رؤية شاملة لمدير المشروع تشمل حالة المهام وحالة السيرفرات المستضافة على "غيمة" في مكان واحد.
|
||||
|
||||
## 4. رسم بسيط يوضح التكامل (Architecture Sketch)
|
||||
+-----------------------------------+
|
||||
| منصة إدارة المشاريع "فريقي" |
|
||||
| (Task & Team Management) |
|
||||
+-----------------------------------+
|
||||
|
|
||||
v (Trigger via Webhook / API)
|
||||
+-----------------------------------+
|
||||
| منصة غيمة (Ghaymah.systems) |
|
||||
| (Cloud Provider & Docker) |
|
||||
+-----------------------------------+
|
||||
|
|
||||
v (Provisioning & Deployment)
|
||||
+-----------------------------------+
|
||||
| بيئات العمل والخوادم السحابية |
|
||||
+-----------------------------------+
|
||||
|
||||
## 5. التحديات التقنية أو التجارية المحتملة
|
||||
* **التحديات التقنية:** إدارة صلاحيات الوصول وتأمين مفاتيح الربط (API Tokens) بين منصة إدارة المهام ومزود السحابة لمنع أي وصول غير مصرح به.
|
||||
* **التحديات التجارية:** إدارة استهلاك الموارد السحابية المرتبطة بالمهام وضمان تسعيرها بشكل عادل يتناسب مع باقات المستخدمين على المنصتين.
|
||||
40
common-mortakaz/integration-2.md
Normal file
40
common-mortakaz/integration-2.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# مقترح تكامل: واجهة "إسأل مرتكز" مع محرك البحث العربي "ميثال" (Mithal.space)
|
||||
|
||||
## 1. وصف المنتج المختار
|
||||
**"إسأل مرتكز"** هي أداة استعلام ذكية تعتمد على استخراج وتحليل بيانات المشاريع والمطورين العرب المسجلين على منصة مرتكز. تقدم الأداة تقارير مبسطة ومرئية وسهلة الهضم (مثل التوزيع النسبي للفئات، المشاريع الداعمة للقضايا، وأكثر المطورين نشاطاً) بدلاً من إغراق المستخدم بكميات البيانات الخام.
|
||||
|
||||
## 2. كيف يتكامل مع mithal.space
|
||||
تعتمد منصة **ميثال (mithal.space)** كـ محرك بحث عربي متقدم، ويمكن تحقيق التكامل بالآلية التالية:
|
||||
* **موتور البحث الخلفي (Search & RAG Backend):** يتم ربط واجهة استعلام "إسأل مرتكز" بمحرك بحث "ميثال" عبر واجهات البرمجة (RESTful APIs) بحيث تُرسل استفسارات المستخدمين (مثل البحث عن مطورين أو مشاريع معينة) لتتم معالجتها وفهرستها عبر محرك "ميثال".
|
||||
* **الفهرسة الدلالية (Semantic Indexing):** يقوم محرك "ميثال" بفهرسة البيانات الوصفية للمشاريع (Metadata) وأوصافها باللغة العربية بدقة عالية، مما يرفع سرعة واستجابة استعلامات "إسأل مرتكز".
|
||||
|
||||
## 3. القيمة المضافة للمستخدم النهائي
|
||||
* **دقة وسرعة الاستعلام:** الاستفادة من قوة محرك بحث "ميثال" في معالجة النصوص العربية لاسترجاع النتائج بدقة فائقة وفورية.
|
||||
* **إثراء المحتوى التقني العربي:** مساعدة الباحثين والمطورين في الوصول إلى المشاريع المفتوحة المصدر وأصحابها بضغطة زر واحدة ومن خلال واجهة محادثة ذكية مبسطة.
|
||||
* **تجربة مستخدم تفاعلية:** دمج تقارير "مرتكز" الإحصائية والمرئية مع قوة الفهرسة البحثية لـ "ميثال".
|
||||
|
||||
## 4. رسم بسيط يوضح التكامل (Architecture Sketch)
|
||||
+-----------------------------------+
|
||||
| مستخدم منصة "مرتكز" |
|
||||
| (User Query / Interface) |
|
||||
+-----------------------------------+
|
||||
|
|
||||
v
|
||||
+-----------------------------------+
|
||||
| واجهة "إسأل مرتكز" (API) |
|
||||
+-----------------------------------+
|
||||
| (HTTP JSON Request)
|
||||
v
|
||||
+-----------------------------------+
|
||||
| محرك البحث العربي "ميثال" |
|
||||
| (Mithal.space Core) |
|
||||
+-----------------------------------+
|
||||
| (Data Retrieval & RAG)
|
||||
v
|
||||
+-----------------------------------+
|
||||
| قاعدة البيانات وفهرسة المشاريع |
|
||||
+-----------------------------------+
|
||||
|
||||
## 5. التحديات التقنية أو التجارية المحتملة
|
||||
* **التحديات التقنية:** معالجة الغموض اللغوي في استعلامات البحث باللغة العربية وضمان توافق زمن الاستجابة (Latency) مع التحديثات المستمرة للبيانات.
|
||||
* **التحديات التجارية:** ضمان استدامة الموارد الحسابية لموتور البحث مع تزايد عدد المشاريع والمستخدمين المسجلين على منصة مرتكز.
|
||||
1
common-qabilah/qabilah-profile.txt
Normal file
1
common-qabilah/qabilah-profile.txt
Normal file
@@ -0,0 +1 @@
|
||||
https://qabilah.com/profile/abdulrahmanabdalla88/professional-profile
|
||||
17
q1-deploy-monitor/Dockerfile
Normal file
17
q1-deploy-monitor/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
# Use an official lightweight Python image
|
||||
FROM python:3.9-slim
|
||||
|
||||
# Set the working directory inside the container
|
||||
WORKDIR /app
|
||||
|
||||
# Install required dependencies
|
||||
RUN pip install --no-cache-dir fastapi uvicorn
|
||||
|
||||
# Copy all project files into the container
|
||||
COPY . /app
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 8000
|
||||
|
||||
# Command to run the application using Uvicorn server
|
||||
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
31
q1-deploy-monitor/app.py
Normal file
31
q1-deploy-monitor/app.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import time
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# Global counter to track total requests
|
||||
request_count = 0
|
||||
|
||||
@app.middleware("http")
|
||||
async def count_requests(request: Request, call_next):
|
||||
global request_count
|
||||
request_count += 1
|
||||
start_time = time.time()
|
||||
|
||||
response = await call_next(request)
|
||||
|
||||
process_time = (time.time() - start_time) * 1000
|
||||
response.headers["X-Process-Time"] = f"{process_time:.2f}ms"
|
||||
return response
|
||||
|
||||
# 3. Health Endpoint required by the task
|
||||
@app.get("/health")
|
||||
def health_check():
|
||||
return {"status": "healthy", "requests": request_count}
|
||||
|
||||
# 5. Dashboard Endpoint serving the HTML file
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
def get_dashboard():
|
||||
with open("dashboard.html", "r", encoding="utf-8") as f:
|
||||
return f.read()
|
||||
53
q1-deploy-monitor/dashboard.html
Normal file
53
q1-deploy-monitor/dashboard.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Ghaymah App Dashboard</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; background: #0f172a; color: #fff; text-align: center; padding-top: 50px; }
|
||||
.card { background: #1e293b; padding: 20px; margin: 15px auto; width: 320px; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.3); }
|
||||
h3 { color: #38bdf8; margin-bottom: 5px; }
|
||||
p { font-size: 20px; font-weight: bold; margin: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Application Monitoring Dashboard</h1>
|
||||
|
||||
<div class="card">
|
||||
<h3>Status</h3>
|
||||
<p id="status" style="color: #4ade80;">Loading...</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Total Requests</h3>
|
||||
<p id="count">0</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Response Time</h3>
|
||||
<p id="time">0 ms</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function fetchMetrics() {
|
||||
const start = performance.now();
|
||||
try {
|
||||
const response = await fetch('/health');
|
||||
const end = performance.now();
|
||||
const data = await response.json();
|
||||
|
||||
document.getElementById('status').innerText = data.status;
|
||||
document.getElementById('count').innerText = data.requests;
|
||||
document.getElementById('time').innerText = (end - start).toFixed(2) + ' ms';
|
||||
} catch (error) {
|
||||
document.getElementById('status').innerText = 'Down';
|
||||
document.getElementById('status').style.color = '#f87171';
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch metrics every 30 seconds as required
|
||||
setInterval(fetchMetrics, 30000);
|
||||
fetchMetrics();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
20
q1-deploy-monitor/health-check.sh
Normal file
20
q1-deploy-monitor/health-check.sh
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
URL="http://localhost:8000/health"
|
||||
|
||||
echo "Starting application monitoring. Checking every 30 seconds..."
|
||||
|
||||
while true; do
|
||||
# Send HTTP GET request and get the status code
|
||||
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" $URL)
|
||||
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
if [ "$RESPONSE" -eq 200 ]; then
|
||||
echo "[$TIMESTAMP] Status: HEALTHY (HTTP 200)"
|
||||
else
|
||||
echo "[$TIMESTAMP] Status: DOWN (HTTP $RESPONSE)"
|
||||
fi
|
||||
|
||||
# Wait for 30 seconds before the next check
|
||||
sleep 30
|
||||
done
|
||||
44
q2-postmortem/postmortem-report.md
Normal file
44
q2-postmortem/postmortem-report.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Incident Postmortem: Application Frequent Crashes (OOMKilled)
|
||||
|
||||
---
|
||||
|
||||
## 1. Incident Overview & Summary
|
||||
- **Incident Date:** July 26, 2026
|
||||
- **Impact:** The application deployed on Ghaymah Cloud suffered from repeated crashes every 45 minutes, causing service downtime for users.
|
||||
- **Root Cause:** **OOMKilled (Out Of Memory)** error triggered because the container exceeded its allocated memory limit due to unoptimized resource configuration or a potential memory leak.
|
||||
|
||||
---
|
||||
|
||||
## 2. Timeline
|
||||
- **00:00** - Application deployed and running normally.
|
||||
- **00:30** - Memory consumption gradually increases as traffic and background tasks accumulate.
|
||||
- **00:45** - Memory usage reaches 100% of the container limit; the Linux kernel terminates the process (`OOMKilled`).
|
||||
- **00:46** - Container restarts automatically, and the cycle repeats precisely every 45 minutes.
|
||||
|
||||
---
|
||||
|
||||
## 3. Root Cause Analysis
|
||||
1. **Resource Limits:** The container was assigned insufficient RAM limits in its deployment configuration.
|
||||
2. **Memory Leak / Garbage Collection:** Long-running background jobs or unclosed database connections failed to release memory back to the system, leading to a steady upward trend until exhaustion.
|
||||
|
||||
---
|
||||
|
||||
## 4. Preventive Actions & Recommendations
|
||||
- **Increase Container RAM:** Scale up the memory limits in the deployment configuration on Ghaymah Cloud.
|
||||
- **Code Optimization:** Audit the application code to fix any memory leaks and ensure proper resource disposal.
|
||||
- **Health & Memory Probes:** Implement stricter liveness and readiness probes.
|
||||
|
||||
---
|
||||
|
||||
## 5. Auto-Scaling Policy Design
|
||||
To prevent recurring downtime under high load, an auto-scaling policy should be configured on Ghaymah Cloud:
|
||||
- **Trigger Metric:** Memory Utilization or CPU Utilization.
|
||||
- **Scale-Up Threshold:** Automatically add a new container instance (replica) when memory usage exceeds **75%** for 5 consecutive minutes.
|
||||
- **Max Instances:** Set a cap of 3 instances to handle traffic spikes safely without exhausting cluster resources.
|
||||
|
||||
---
|
||||
|
||||
## 6. Early Detection & Monitoring Setup
|
||||
Using Ghaymah Cloud monitoring tools to detect the issue proactively before crashes occur:
|
||||
- **Custom Alerts:** Set up an alerting rule (via Webhook/Email) to notify the DevOps team when container memory usage crosses **70%**.
|
||||
- **Real-Time Dashboards:** Monitor memory trends continuously using the metrics dashboard to spot gradual upward slopes before hitting the OOM threshold.
|
||||
14
q3-cicd/README.md
Normal file
14
q3-cicd/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# --- Q3 Theoretical Documentation ---
|
||||
|
||||
## 1. Difference Between Staging and Production Environments:
|
||||
- **Staging Environment:** A pre-production, isolated environment identical to production, used exclusively for testing updates, running integration tests, and catching bugs safely before real users see them.
|
||||
- **Production Environment:** The live, primary environment accessed by end-users, where stability, high availability, and security are critical.
|
||||
|
||||
## 2. Ghaymah CLI Integration & Connection:
|
||||
To link and authenticate with Ghaymah CLI locally or in pipelines:
|
||||
1. Install the CLI tool:
|
||||
`curl -sL https://cli.ghaymah.systems/install.sh | bash`
|
||||
2. Authenticate using your API token:
|
||||
`ghaymah auth login --token <YOUR_API_TOKEN>`
|
||||
3. Verify connection status:
|
||||
`ghaymah cluster status`
|
||||
55
q3-cicd/workflow.yml
Normal file
55
q3-cicd/workflow.yml
Normal file
@@ -0,0 +1,55 @@
|
||||
name: CI/CD Pipeline to Ghaymah
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Log in to Ghaymah Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.ghaymah.systems
|
||||
username: ${{ secrets.GHAYMAH_USERNAME }}
|
||||
password: ${{ secrets.GHAYMAH_TOKEN }}
|
||||
|
||||
- name: Build and Push Docker Image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: registry.ghaymah.systems/abdulrahman/deploy-monitor:latest
|
||||
|
||||
staging-deploy:
|
||||
needs: build-and-push
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Deploy to Staging Environment
|
||||
run: |
|
||||
echo "Deploying the built image to Staging server for testing..."
|
||||
# ghaymah CLI command example for staging
|
||||
|
||||
production-approval:
|
||||
needs: staging-deploy
|
||||
runs-on: ubuntu-latest
|
||||
environment: production # This triggers the GitHub Manual Approval gate
|
||||
steps:
|
||||
- name: Approved for Production
|
||||
run: echo "Manual approval passed. Proceeding to production deployment."
|
||||
|
||||
production-deploy:
|
||||
needs: production-approval
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Deploy to Production
|
||||
run: |
|
||||
echo "Deploying application to live Production server..."
|
||||
# ghaymah CLI command example for production
|
||||
|
||||
|
||||
|
||||
ثنائية
q4-scalability/architecture.png
Normal file
ثنائية
q4-scalability/architecture.png
Normal file
ملف ثنائي غير معروض.
|
بعد العرض: | الارتفاع: | الحجم: 75 KiB |
33
q4-scalability/calculations.md
Normal file
33
q4-scalability/calculations.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Q4: Scalability Sizing Calculations & Strategy
|
||||
|
||||
---
|
||||
|
||||
## 1. Container Capacity Calculation (Sizing)
|
||||
|
||||
- **Total Incoming Traffic:** $15,000 \text{ req/s}$
|
||||
- **Single Container Capacity:** $500 \text{ req/s}$
|
||||
- **Base Containers Required:**
|
||||
$$\frac{15,000}{500} = 30 \text{ containers}$$
|
||||
- **Safety Margin (30% buffer for traffic spikes & high availability):**
|
||||
$$30 \times 0.30 = 9 \text{ extra containers}$$
|
||||
- **Total Containers Needed:**
|
||||
$$30 + 9 = 39 \text{ containers}$$
|
||||
|
||||
---
|
||||
|
||||
## 2. Cold Start Mitigation Strategy
|
||||
|
||||
To minimize latency and prevent performance drops when new containers spin up rapidly during auto-scaling:
|
||||
- **Pre-warmed / Min Replicas:** Maintain a baseline of idle warm containers ready to take traffic immediately.
|
||||
- **Lightweight Container Images:** Optimize the Dockerfile (using multi-stage builds and slim base images) to reduce image pull and startup time.
|
||||
- **Health Check Optimization:** Tune liveness probes to detect readiness faster without overloading the container during boot.
|
||||
|
||||
---
|
||||
|
||||
## 3. Ghaymah Block Storage for Stateful Workloads
|
||||
|
||||
- **The Problem:** Containers are inherently ephemeral (stateless)—any data written inside the container's internal file system is lost if the container crashes or restarts.
|
||||
- **The Solution (Ghaymah Block Storage):**
|
||||
- Provides high-performance, persistent network-attached storage volumes.
|
||||
- By mounting a Ghaymah Block Storage volume to the stateful workload (e.g., databases or file uploads), data is decoupled from the container lifecycle.
|
||||
- If a container dies, a new container spins up and attaches to the exact same persistent storage volume with zero data loss.
|
||||
17
q5-mithal-monitor/Dockerfile
Normal file
17
q5-mithal-monitor/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
# استخدام صورة بايثون خفيفة
|
||||
FROM python:3.9-slim
|
||||
|
||||
# تحديد مجلد العمل داخل الحاوية
|
||||
WORKDIR /app
|
||||
|
||||
# تثبيت المكاتب المطلوبة مباشرة بدون الحاجة لملف requirements.txt منفصل
|
||||
RUN pip install --no-cache-dir fastapi uvicorn requests
|
||||
|
||||
# نسخ باقي ملفات المشروع (مثل monitor.py و dashboard.html) إلى مجلد العمل
|
||||
COPY . /app
|
||||
|
||||
# فتح البورت الذي يعمل عليه التطبيق
|
||||
EXPOSE 8000
|
||||
|
||||
# أمر التشغيل المباشر باستخدام Uvicorn
|
||||
CMD ["uvicorn", "monitor:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
149
q5-mithal-monitor/dashboard.html
Normal file
149
q5-mithal-monitor/dashboard.html
Normal file
@@ -0,0 +1,149 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>لوحة مراقبة موقع مثال - Mithal Monitor</title>
|
||||
<!-- مكتبة الرسم البياني Chart.js -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; background: #0f172a; margin: 0; padding: 40px 20px; color: #ffffff; }
|
||||
.container { max-width: 800px; margin: auto; text-align: center; }
|
||||
h1 { color: #ffffff; font-size: 24px; margin-bottom: 30px; }
|
||||
.metrics-box { display: flex; gap: 15px; margin-bottom: 20px; }
|
||||
.card { background: #1e293b; border-radius: 8px; padding: 20px; flex: 1; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); }
|
||||
.card h3 { margin: 0 0 8px; font-size: 14px; color: #38bdf8; }
|
||||
.card p { font-size: 18px; margin: 0; font-weight: bold; color: #ffffff; }
|
||||
.chart-container { background: #1e293b; border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); }
|
||||
.status-ok { color: #4ade80 !important; }
|
||||
.status-down { color: #f87171 !important; }
|
||||
table { width: 100%; border-collapse: collapse; margin-top: 20px; background: #1e293b; border-radius: 8px; overflow: hidden; }
|
||||
th, td { padding: 12px; text-align: center; font-size: 14px; border-bottom: 1px solid #334155; }
|
||||
th { background: #0f172a; color: #38bdf8; }
|
||||
tr:last-child td { border-bottom: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>لوحة مراقبة موقع مثال (mithal.space)</h1>
|
||||
|
||||
<div class="metrics-box">
|
||||
<div class="card">
|
||||
<h3>حالة الموقع</h3>
|
||||
<p id="siteStatus" class="status-ok">جاري التحميل...</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>حالة SSL وتاريخ الانتهاء</h3>
|
||||
<p id="sslStatus" style="font-size: 14px;">جاري التحميل...</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>متوسط الـ Latency</h3>
|
||||
<p id="latencyStatus">جاري التحميل...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- الرسم البياني (Line Chart) لزمن الاستجابة -->
|
||||
<div class="chart-container">
|
||||
<h3 style="color: #38bdf8; margin-top: 0; text-align: right;">رسم بياني لزمن الاستجابة (Latency - آخر ساعة)</h3>
|
||||
<canvas id="latencyChart"></canvas>
|
||||
</div>
|
||||
|
||||
<h2 style="font-size: 18px; margin-top: 30px; color: #38bdf8; text-align: right;">سجل آخر الفحصات</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>الوقت</th>
|
||||
<th>حالة الموقع</th>
|
||||
<th>زمن الاستجابة</th>
|
||||
<th>زمن البحث</th>
|
||||
<th>حالة SSL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="logTableBody">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// إعداد الرسم البياني باستخدام Chart.js
|
||||
const ctx = document.getElementById('latencyChart').getContext('2d');
|
||||
const latencyChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'زمن الاستجابة (ms)',
|
||||
data: [],
|
||||
borderColor: '#38bdf8',
|
||||
backgroundColor: 'rgba(56, 189, 248, 0.1)',
|
||||
borderWidth: 2,
|
||||
fill: true,
|
||||
tension: 0.3
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: { labels: { color: '#ffffff' } }
|
||||
},
|
||||
scales: {
|
||||
x: { ticks: { color: '#94a3b8' }, grid: { color: '#334155' } },
|
||||
y: { ticks: { color: '#94a3b8' }, grid: { color: '#334155' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function fetchMetrics() {
|
||||
try {
|
||||
const response = await fetch('/api/metrics');
|
||||
const data = await response.json();
|
||||
|
||||
if (data && data.length > 0) {
|
||||
const latest = data[data.length - 1];
|
||||
|
||||
// تحديث الكروت العلوية
|
||||
const statusElem = document.getElementById('siteStatus');
|
||||
if (latest.status_code === 200) {
|
||||
statusElem.textContent = "متصل (200 OK)";
|
||||
statusElem.className = "status-ok";
|
||||
} else {
|
||||
statusElem.textContent = `غير متصل (${latest.status_code})`;
|
||||
statusElem.className = "status-down";
|
||||
}
|
||||
|
||||
document.getElementById('sslStatus').textContent = latest.ssl_status;
|
||||
document.getElementById('latencyStatus').textContent = `${latest.latency_ms} ms`;
|
||||
|
||||
// تحديث بيانات الرسم البياني (Line Chart) من السكريبت
|
||||
const timestamps = data.map(row => row.timestamp.split(' ')[1]); // أخذ الوقت فقط
|
||||
const latencies = data.map(row => row.latency_ms);
|
||||
|
||||
latencyChart.data.labels = timestamps;
|
||||
latencyChart.data.datasets[0].data = latencies;
|
||||
latencyChart.update();
|
||||
|
||||
// تحديث الجدول
|
||||
const tableBody = document.getElementById('logTableBody');
|
||||
tableBody.innerHTML = '';
|
||||
const reversedData = [...data].reverse().slice(0, 10);
|
||||
reversedData.forEach(row => {
|
||||
const tr = document.createElement('tr');
|
||||
tr.innerHTML = `
|
||||
<td>${row.timestamp}</td>
|
||||
<td class="${row.status_code === 200 ? 'status-ok' : 'status-down'}">${row.status_code} OK</td>
|
||||
<td>${row.latency_ms} ms</td>
|
||||
<td>${row.search_response_ms} ms</td>
|
||||
<td>${row.ssl_status}</td>
|
||||
`;
|
||||
tableBody.appendChild(tr);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error fetching metrics");
|
||||
}
|
||||
}
|
||||
|
||||
fetchMetrics();
|
||||
setInterval(fetchMetrics, 5000); // تحديث الجراف والبيانات تلقائياً كل 5 ثوانٍ
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
74
q5-mithal-monitor/metrics.json
Normal file
74
q5-mithal-monitor/metrics.json
Normal file
@@ -0,0 +1,74 @@
|
||||
[
|
||||
{
|
||||
"timestamp": "2026-07-27 19:52:03",
|
||||
"status_code": 200,
|
||||
"latency_ms": 1041.82,
|
||||
"dns_ms": 9.59,
|
||||
"search_response_ms": 944.04,
|
||||
"ssl_status": "صحيحة (تنتهي خلال 49 يوم)"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27 19:53:06",
|
||||
"status_code": 200,
|
||||
"latency_ms": 961.73,
|
||||
"dns_ms": 1.01,
|
||||
"search_response_ms": 951.24,
|
||||
"ssl_status": "صحيحة (تنتهي خلال 49 يوم)"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27 19:54:09",
|
||||
"status_code": 200,
|
||||
"latency_ms": 1117.17,
|
||||
"dns_ms": 21.45,
|
||||
"search_response_ms": 849.41,
|
||||
"ssl_status": "صحيحة (تنتهي خلال 49 يوم)"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27 19:55:12",
|
||||
"status_code": 200,
|
||||
"latency_ms": 1785.42,
|
||||
"dns_ms": 0.0,
|
||||
"search_response_ms": 846.86,
|
||||
"ssl_status": "صحيحة (تنتهي خلال 49 يوم)"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27 19:56:23",
|
||||
"status_code": 200,
|
||||
"latency_ms": 3183.29,
|
||||
"dns_ms": 1.12,
|
||||
"search_response_ms": 4690.82,
|
||||
"ssl_status": "صحيحة (تنتهي خلال 49 يوم)"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27 19:57:25",
|
||||
"status_code": 200,
|
||||
"latency_ms": 1111.06,
|
||||
"dns_ms": 8.02,
|
||||
"search_response_ms": 848.63,
|
||||
"ssl_status": "صحيحة (تنتهي خلال 49 يوم)"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27 19:58:28",
|
||||
"status_code": 200,
|
||||
"latency_ms": 1030.14,
|
||||
"dns_ms": 1.01,
|
||||
"search_response_ms": 839.49,
|
||||
"ssl_status": "صحيحة (تنتهي خلال 49 يوم)"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27 19:59:31",
|
||||
"status_code": 200,
|
||||
"latency_ms": 985.51,
|
||||
"dns_ms": 18.2,
|
||||
"search_response_ms": 931.7,
|
||||
"ssl_status": "صحيحة (تنتهي خلال 49 يوم)"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27 20:00:33",
|
||||
"status_code": 200,
|
||||
"latency_ms": 936.12,
|
||||
"dns_ms": 13.48,
|
||||
"search_response_ms": 939.24,
|
||||
"ssl_status": "صحيحة (تنتهي خلال 49 يوم)"
|
||||
}
|
||||
]
|
||||
120
q5-mithal-monitor/monitor.py
Normal file
120
q5-mithal-monitor/monitor.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import time
|
||||
import requests
|
||||
import json
|
||||
import ssl
|
||||
import socket
|
||||
import os
|
||||
import asyncio
|
||||
from datetime import datetime, timezone
|
||||
from urllib.parse import urlparse
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import JSONResponse, FileResponse
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
# --- تعريف الـ Lifespan لحل مشكلة الـ startup وتوليد الخلفية ---
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
task = asyncio.create_task(background_monitor())
|
||||
yield
|
||||
task.cancel()
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
TARGET_URL = "https://mithal.space"
|
||||
LOG_FILE = "metrics.json"
|
||||
|
||||
# --- دالة الفحص الخلفية بـ FastAPI ---
|
||||
async def background_monitor():
|
||||
while True:
|
||||
parsed_url = urlparse(TARGET_URL)
|
||||
hostname = parsed_url.netloc
|
||||
|
||||
start_time = time.time()
|
||||
status_code = 0
|
||||
latency = 0
|
||||
ssl_expiry = "N/A"
|
||||
dns_time = 0
|
||||
search_time = 0
|
||||
|
||||
try:
|
||||
dns_start = time.time()
|
||||
socket.gethostbyname(hostname)
|
||||
dns_time = round((time.time() - dns_start) * 1000, 2)
|
||||
except:
|
||||
dns_time = -1
|
||||
|
||||
try:
|
||||
response = requests.get(TARGET_URL, timeout=10)
|
||||
latency = round((time.time() - start_time) * 1000, 2)
|
||||
status_code = response.status_code
|
||||
except:
|
||||
latency = -1
|
||||
status_code = 503
|
||||
|
||||
try:
|
||||
search_start = time.time()
|
||||
requests.get(f"{TARGET_URL}/search?q=test", timeout=5)
|
||||
search_time = round((time.time() - search_start) * 1000, 2)
|
||||
except:
|
||||
search_time = -1
|
||||
|
||||
try:
|
||||
context = ssl.create_default_context()
|
||||
with socket.create_connection((hostname, 443), timeout=5) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
cert = ssock.getpeercert()
|
||||
expiry_date = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z').replace(tzinfo=timezone.utc)
|
||||
days_left = (expiry_date - datetime.now(timezone.utc)).days
|
||||
ssl_expiry = f"صحيحة (تنتهي خلال {days_left} يوم)"
|
||||
except:
|
||||
ssl_expiry = "خطأ في جلب SSL"
|
||||
|
||||
timestamp_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
record = {
|
||||
"timestamp": timestamp_str,
|
||||
"status_code": status_code,
|
||||
"latency_ms": latency,
|
||||
"dns_ms": dns_time,
|
||||
"search_response_ms": search_time,
|
||||
"ssl_status": ssl_expiry
|
||||
}
|
||||
|
||||
try:
|
||||
if os.path.exists(LOG_FILE):
|
||||
with open(LOG_FILE, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
else:
|
||||
data = []
|
||||
except:
|
||||
data = []
|
||||
|
||||
data.append(record)
|
||||
if len(data) > 20:
|
||||
data = data[-20:]
|
||||
|
||||
with open(LOG_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
|
||||
print(f"[{timestamp_str}] Background Checked {TARGET_URL} - Status: {status_code} - Latency: {latency}ms")
|
||||
|
||||
# الانتظار لمدة 30 ثانية أو دقيقة بحسب رغبتك
|
||||
await asyncio.sleep(60)
|
||||
|
||||
# --- المسارات (Endpoints) ---
|
||||
@app.get("/")
|
||||
def index():
|
||||
if os.path.exists("dashboard.html"):
|
||||
return FileResponse("dashboard.html")
|
||||
return {"message": "Dashboard file not found"}
|
||||
|
||||
@app.get("/api/metrics")
|
||||
def get_metrics():
|
||||
if os.path.exists(LOG_FILE):
|
||||
try:
|
||||
with open(LOG_FILE, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
return JSONResponse(content=data)
|
||||
except:
|
||||
return JSONResponse(content=[])
|
||||
return JSONResponse(content=[])
|
||||
|
||||
المرجع في مشكلة جديدة
حظر مستخدم