Initial deployment
هذا الالتزام موجود في:
16
Dockerfile
Normal file
16
Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
CMD ["python", "app.py"]
|
||||
38
app.py
Normal file
38
app.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from flask import Flask, jsonify
|
||||
import time
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
request_count = 0
|
||||
start_time = time.time()
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def home():
|
||||
global request_count
|
||||
request_count += 1
|
||||
return jsonify({
|
||||
"message": "Hello from Ghaymah!",
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
|
||||
@app.route("/health")
|
||||
def health():
|
||||
global request_count
|
||||
request_count += 1
|
||||
return jsonify({
|
||||
"status": "healthy"
|
||||
})
|
||||
|
||||
|
||||
@app.route("/metrics")
|
||||
def metrics():
|
||||
return jsonify({
|
||||
"request_count": request_count,
|
||||
"uptime": round(time.time() - start_time, 2)
|
||||
})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=5000)
|
||||
293
dashboard.html
Normal file
293
dashboard.html
Normal file
@@ -0,0 +1,293 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>API Monitoring Dashboard</title>
|
||||
<!-- Chart.js (lightweight, cached) -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: #f0f2f5;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
h1 {
|
||||
font-weight: 300;
|
||||
color: #1a1a2e;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.card {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
transition: 0.2s;
|
||||
}
|
||||
.card:hover {
|
||||
box-shadow: 0 4px 16px rgba(0,0,0,0.12);
|
||||
}
|
||||
.card-label {
|
||||
font-size: 0.85rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
color: #6c757d;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.card-value {
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.status-up { color: #28a745; }
|
||||
.status-down { color: #dc3545; }
|
||||
.chart-container {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
margin-bottom: 20px;
|
||||
height: 300px;
|
||||
}
|
||||
.table-container {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
overflow-x: auto;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
th {
|
||||
text-align: left;
|
||||
padding: 10px 8px;
|
||||
border-bottom: 2px solid #dee2e6;
|
||||
color: #495057;
|
||||
}
|
||||
td {
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
}
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.badge-up { background: #d4edda; color: #155724; }
|
||||
.badge-down { background: #f8d7da; color: #721c24; }
|
||||
.text-muted {
|
||||
color: #6c757d;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
.card-value {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>📊 API Monitoring Dashboard</h1>
|
||||
|
||||
<!-- Summary Cards -->
|
||||
<div class="grid" id="summary">
|
||||
<div class="card">
|
||||
<div class="card-label">Uptime (24h)</div>
|
||||
<div class="card-value" id="uptime">--</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-label">Current Status</div>
|
||||
<div class="card-value" id="status">--</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-label">Last Latency</div>
|
||||
<div class="card-value" id="last-latency">--</div>
|
||||
<div class="text-muted">milliseconds</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-label">Total Requests</div>
|
||||
<div class="card-value" id="total-requests">--</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Latency Chart -->
|
||||
<div class="chart-container">
|
||||
<canvas id="latencyChart"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Recent Checks Table -->
|
||||
<div class="table-container">
|
||||
<h3 style="margin-bottom: 10px; font-weight: 400;">Recent Checks (last 10)</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Timestamp</th>
|
||||
<th>Status</th>
|
||||
<th>Latency (ms)</th>
|
||||
<th>Request Count</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="checks-body">
|
||||
<tr><td colspan="4" class="text-muted">Loading data…</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let chart = null;
|
||||
|
||||
// Compute uptime for the last 24 hours
|
||||
function computeUptime(data) {
|
||||
if (!data || data.length === 0) return 0;
|
||||
const now = new Date();
|
||||
const last24h = data.filter(entry => {
|
||||
const ts = new Date(entry.timestamp);
|
||||
return (now - ts) <= 24 * 60 * 60 * 1000;
|
||||
});
|
||||
if (last24h.length === 0) return 0;
|
||||
const up = last24h.filter(e => e.status === 'up').length;
|
||||
return (up / last24h.length) * 100;
|
||||
}
|
||||
|
||||
// Update the dashboard with new data
|
||||
function updateDashboard(data) {
|
||||
if (!data || data.length === 0) {
|
||||
document.getElementById('uptime').textContent = '--';
|
||||
document.getElementById('status').innerHTML = '--';
|
||||
document.getElementById('last-latency').textContent = '--';
|
||||
document.getElementById('total-requests').textContent = '--';
|
||||
document.getElementById('checks-body').innerHTML = '<tr><td colspan="4" class="text-muted">No data</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Latest entry
|
||||
const latest = data[data.length - 1];
|
||||
// Status with badge
|
||||
const statusEl = document.getElementById('status');
|
||||
if (latest.status === 'up') {
|
||||
statusEl.innerHTML = '<span class="status-up">🟢 UP</span>';
|
||||
} else {
|
||||
statusEl.innerHTML = '<span class="status-down">🔴 DOWN</span>';
|
||||
}
|
||||
document.getElementById('last-latency').textContent = latest.latency >= 0 ? latest.latency : 'N/A';
|
||||
document.getElementById('total-requests').textContent = latest.request_count || 0;
|
||||
|
||||
// Uptime
|
||||
const uptime = computeUptime(data);
|
||||
document.getElementById('uptime').textContent = uptime.toFixed(2) + '%';
|
||||
|
||||
// Update table (last 10, newest first)
|
||||
const tbody = document.getElementById('checks-body');
|
||||
tbody.innerHTML = '';
|
||||
const last10 = data.slice(-10).reverse();
|
||||
last10.forEach(entry => {
|
||||
const row = document.createElement('tr');
|
||||
const statusBadge = entry.status === 'up'
|
||||
? '<span class="badge badge-up">UP</span>'
|
||||
: '<span class="badge badge-down">DOWN</span>';
|
||||
row.innerHTML = `
|
||||
<td>${entry.timestamp}</td>
|
||||
<td>${statusBadge}</td>
|
||||
<td>${entry.latency >= 0 ? entry.latency : '—'}</td>
|
||||
<td>${entry.request_count || '—'}</td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
|
||||
// Update chart (use last 60 entries, or all if less)
|
||||
const chartData = data.slice(-60);
|
||||
const labels = chartData.map(e => {
|
||||
const d = new Date(e.timestamp);
|
||||
return d.toLocaleTimeString();
|
||||
});
|
||||
const latencies = chartData.map(e => e.latency >= 0 ? e.latency : 0);
|
||||
|
||||
if (chart) {
|
||||
chart.data.labels = labels;
|
||||
chart.data.datasets[0].data = latencies;
|
||||
chart.update();
|
||||
} else {
|
||||
const ctx = document.getElementById('latencyChart').getContext('2d');
|
||||
chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Latency (ms)',
|
||||
data: latencies,
|
||||
borderColor: '#007bff',
|
||||
backgroundColor: 'rgba(0,123,255,0.1)',
|
||||
tension: 0.2,
|
||||
fill: true,
|
||||
pointRadius: 2
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: { display: false }
|
||||
},
|
||||
scales: {
|
||||
x: { grid: { display: false } },
|
||||
y: { beginAtZero: true, grid: { color: '#f0f0f0' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the JSON data
|
||||
async function fetchData() {
|
||||
try {
|
||||
const response = await fetch('monitoring-data.json');
|
||||
if (!response.ok) throw new Error('Network error');
|
||||
const data = await response.json();
|
||||
// Ensure data is an array
|
||||
if (!Array.isArray(data)) {
|
||||
console.warn('Data is not an array; converting to empty array');
|
||||
return [];
|
||||
}
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch data:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh loop
|
||||
async function refresh() {
|
||||
const data = await fetchData();
|
||||
updateDashboard(data);
|
||||
}
|
||||
|
||||
// Initial load and periodic refresh every 10 seconds
|
||||
refresh();
|
||||
setInterval(refresh, 10000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
38
health-check.sh
Normal file
38
health-check.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
URL="http://localhost:5000"
|
||||
|
||||
REQUESTS=0
|
||||
|
||||
while true
|
||||
do
|
||||
REQUESTS=$((REQUESTS+1))
|
||||
|
||||
RESPONSE=$(curl -o /dev/null -s -w "%{http_code} %{time_total}" "$URL/health")
|
||||
|
||||
STATUS_CODE=$(echo "$RESPONSE" | cut -d' ' -f1)
|
||||
RESPONSE_TIME=$(echo "$RESPONSE" | cut -d' ' -f2)
|
||||
|
||||
if [ "$STATUS_CODE" = "200" ]
|
||||
then
|
||||
STATUS="UP"
|
||||
else
|
||||
STATUS="DOWN"
|
||||
fi
|
||||
|
||||
TIMESTAMP=$(date -Iseconds)
|
||||
LATENCY_MS=$(awk "BEGIN {print $RESPONSE_TIME * 1000}")
|
||||
|
||||
python update_monitor.py \
|
||||
"$TIMESTAMP" \
|
||||
"$(echo $STATUS | tr '[:upper:]' '[:lower:]')" \
|
||||
"$LATENCY_MS" \
|
||||
"$REQUESTS"
|
||||
|
||||
echo "Status : $STATUS"
|
||||
echo "Latency : ${LATENCY_MS} ms"
|
||||
echo "Requests : $REQUESTS"
|
||||
echo "-------------------------"
|
||||
|
||||
sleep 30
|
||||
done
|
||||
296
monitoring-data.json
Normal file
296
monitoring-data.json
Normal file
@@ -0,0 +1,296 @@
|
||||
[
|
||||
{
|
||||
"timestamp": "2026-07-27T03:10:22+03:00",
|
||||
"status": "up",
|
||||
"latency": 9.449,
|
||||
"request_count": 1
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:10:53+03:00",
|
||||
"status": "up",
|
||||
"latency": 7.223,
|
||||
"request_count": 2
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:11:24+03:00",
|
||||
"status": "up",
|
||||
"latency": 5.266,
|
||||
"request_count": 3
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:11:54+03:00",
|
||||
"status": "up",
|
||||
"latency": 5.777,
|
||||
"request_count": 4
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:12:25+03:00",
|
||||
"status": "up",
|
||||
"latency": 10.061,
|
||||
"request_count": 5
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:12:55+03:00",
|
||||
"status": "up",
|
||||
"latency": 6.11,
|
||||
"request_count": 6
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:13:26+03:00",
|
||||
"status": "up",
|
||||
"latency": 25.41,
|
||||
"request_count": 7
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:13:56+03:00",
|
||||
"status": "up",
|
||||
"latency": 16.302,
|
||||
"request_count": 8
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:14:27+03:00",
|
||||
"status": "up",
|
||||
"latency": 11.741,
|
||||
"request_count": 9
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:14:58+03:00",
|
||||
"status": "up",
|
||||
"latency": 26.753,
|
||||
"request_count": 10
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:15:28+03:00",
|
||||
"status": "up",
|
||||
"latency": 13.328,
|
||||
"request_count": 11
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:15:59+03:00",
|
||||
"status": "up",
|
||||
"latency": 6.945,
|
||||
"request_count": 12
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:16:29+03:00",
|
||||
"status": "up",
|
||||
"latency": 8.735,
|
||||
"request_count": 13
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:16:59+03:00",
|
||||
"status": "up",
|
||||
"latency": 7.036,
|
||||
"request_count": 14
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:17:30+03:00",
|
||||
"status": "up",
|
||||
"latency": 13.428,
|
||||
"request_count": 15
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:18:00+03:00",
|
||||
"status": "up",
|
||||
"latency": 7.623,
|
||||
"request_count": 16
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:18:31+03:00",
|
||||
"status": "up",
|
||||
"latency": 77.742,
|
||||
"request_count": 17
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:19:02+03:00",
|
||||
"status": "up",
|
||||
"latency": 5.957,
|
||||
"request_count": 18
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:19:32+03:00",
|
||||
"status": "up",
|
||||
"latency": 11.503,
|
||||
"request_count": 19
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:20:03+03:00",
|
||||
"status": "up",
|
||||
"latency": 8.375,
|
||||
"request_count": 20
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:20:33+03:00",
|
||||
"status": "up",
|
||||
"latency": 8.342,
|
||||
"request_count": 21
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:21:04+03:00",
|
||||
"status": "up",
|
||||
"latency": 33.106,
|
||||
"request_count": 22
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:21:34+03:00",
|
||||
"status": "up",
|
||||
"latency": 7.304,
|
||||
"request_count": 23
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:22:05+03:00",
|
||||
"status": "up",
|
||||
"latency": 36.75,
|
||||
"request_count": 24
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:22:35+03:00",
|
||||
"status": "up",
|
||||
"latency": 9.297,
|
||||
"request_count": 25
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:23:06+03:00",
|
||||
"status": "up",
|
||||
"latency": 12.333,
|
||||
"request_count": 26
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:23:36+03:00",
|
||||
"status": "up",
|
||||
"latency": 8.061,
|
||||
"request_count": 27
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:24:07+03:00",
|
||||
"status": "up",
|
||||
"latency": 10.166,
|
||||
"request_count": 28
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:24:37+03:00",
|
||||
"status": "up",
|
||||
"latency": 5.104,
|
||||
"request_count": 29
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:25:08+03:00",
|
||||
"status": "up",
|
||||
"latency": 27.727,
|
||||
"request_count": 30
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:25:38+03:00",
|
||||
"status": "up",
|
||||
"latency": 7.573,
|
||||
"request_count": 31
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:26:09+03:00",
|
||||
"status": "up",
|
||||
"latency": 6.931,
|
||||
"request_count": 32
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:26:39+03:00",
|
||||
"status": "up",
|
||||
"latency": 7.046,
|
||||
"request_count": 33
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:27:10+03:00",
|
||||
"status": "up",
|
||||
"latency": 9.342,
|
||||
"request_count": 34
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:27:40+03:00",
|
||||
"status": "up",
|
||||
"latency": 6.77,
|
||||
"request_count": 35
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:28:11+03:00",
|
||||
"status": "up",
|
||||
"latency": 6.837,
|
||||
"request_count": 36
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:28:41+03:00",
|
||||
"status": "up",
|
||||
"latency": 9.652,
|
||||
"request_count": 37
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:29:12+03:00",
|
||||
"status": "up",
|
||||
"latency": 15.207,
|
||||
"request_count": 38
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:29:43+03:00",
|
||||
"status": "up",
|
||||
"latency": 10.94,
|
||||
"request_count": 39
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:30:13+03:00",
|
||||
"status": "up",
|
||||
"latency": 6.731,
|
||||
"request_count": 40
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:30:44+03:00",
|
||||
"status": "up",
|
||||
"latency": 7.411,
|
||||
"request_count": 41
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:31:15+03:00",
|
||||
"status": "up",
|
||||
"latency": 13.245,
|
||||
"request_count": 42
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:31:45+03:00",
|
||||
"status": "up",
|
||||
"latency": 6.691,
|
||||
"request_count": 43
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:32:16+03:00",
|
||||
"status": "up",
|
||||
"latency": 7.81,
|
||||
"request_count": 44
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:32:46+03:00",
|
||||
"status": "up",
|
||||
"latency": 22.151,
|
||||
"request_count": 45
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:33:16+03:00",
|
||||
"status": "up",
|
||||
"latency": 7.746,
|
||||
"request_count": 46
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:33:47+03:00",
|
||||
"status": "up",
|
||||
"latency": 10.829,
|
||||
"request_count": 47
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:34:18+03:00",
|
||||
"status": "up",
|
||||
"latency": 18.731,
|
||||
"request_count": 48
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-27T03:34:48+03:00",
|
||||
"status": "up",
|
||||
"latency": 9.383,
|
||||
"request_count": 49
|
||||
}
|
||||
]
|
||||
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
Flask==2.3.3
|
||||
31
update_monitor.py
Normal file
31
update_monitor.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
FILE = "monitoring-data.json"
|
||||
MAX_ENTRIES = 100
|
||||
|
||||
entry = {
|
||||
"timestamp": sys.argv[1],
|
||||
"status": sys.argv[2],
|
||||
"latency": float(sys.argv[3]),
|
||||
"request_count": int(sys.argv[4])
|
||||
}
|
||||
|
||||
if os.path.exists(FILE):
|
||||
try:
|
||||
with open(FILE, "r") as f:
|
||||
data = json.load(f)
|
||||
if not isinstance(data, list):
|
||||
data = []
|
||||
except Exception:
|
||||
data = []
|
||||
else:
|
||||
data = []
|
||||
|
||||
data.append(entry)
|
||||
|
||||
data = data[-MAX_ENTRIES:]
|
||||
|
||||
with open(FILE, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
المرجع في مشكلة جديدة
حظر مستخدم