From dcc35d35bb5b093a1034b76012d9a696f2c081cc Mon Sep 17 00:00:00 2001 From: abdosaad203 Date: Mon, 27 Jul 2026 16:54:24 +0300 Subject: [PATCH] Complete Task 1: Deploy and Monitoring --- .gitignore | 21 ++++++++++ README.md | 0 q1-deploy-monitor/.dockerignore | 5 +++ q1-deploy-monitor/Dockerfile | 7 ++++ q1-deploy-monitor/app.py | 54 ++++++++++++++++++++++++++ q1-deploy-monitor/monitor.py | 22 +++++++++++ q1-deploy-monitor/requirements.txt | 3 ++ q1-deploy-monitor/static/script.js | 50 ++++++++++++++++++++++++ q1-deploy-monitor/static/style.css | 52 +++++++++++++++++++++++++ q1-deploy-monitor/templates/index.html | 45 +++++++++++++++++++++ 10 files changed, 259 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 q1-deploy-monitor/.dockerignore create mode 100644 q1-deploy-monitor/Dockerfile create mode 100644 q1-deploy-monitor/app.py create mode 100644 q1-deploy-monitor/monitor.py create mode 100644 q1-deploy-monitor/requirements.txt create mode 100644 q1-deploy-monitor/static/script.js create mode 100644 q1-deploy-monitor/static/style.css create mode 100644 q1-deploy-monitor/templates/index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..33e954a --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Python virtual environments +**/venv/ +**/.venv/ + +# Python cache +**/__pycache__/ +*.py[cod] + +# Environment +.env +.env.* + +# VS Code +.vscode/ + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/q1-deploy-monitor/.dockerignore b/q1-deploy-monitor/.dockerignore new file mode 100644 index 0000000..7c30034 --- /dev/null +++ b/q1-deploy-monitor/.dockerignore @@ -0,0 +1,5 @@ +venv/ +__pycache__/ +*.pyc +.git +.gitignore \ No newline at end of file diff --git a/q1-deploy-monitor/Dockerfile b/q1-deploy-monitor/Dockerfile new file mode 100644 index 0000000..653f14c --- /dev/null +++ b/q1-deploy-monitor/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.12-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY . . +EXPOSE 5000 +CMD ["python", "app.py"] \ No newline at end of file diff --git a/q1-deploy-monitor/app.py b/q1-deploy-monitor/app.py new file mode 100644 index 0000000..9f37e57 --- /dev/null +++ b/q1-deploy-monitor/app.py @@ -0,0 +1,54 @@ +from flask import Flask, g, render_template +from flask_cors import CORS +from time import time + +app = Flask(__name__) +CORS(app) + +request_count = 0 +start_time = time() +last_response_time = 0 + +@app.before_request +def count_requests(): + global request_count + request_count += 1 + +@app.before_request +def before_request(): + g.start = time() + +@app.after_request +def after_request(response): + global last_response_time + + last_response_time = round((time() - g.start) * 1000, 2) + + return response + +@app.route("/") +def home(): + return render_template("index.html") + +@app.route("/health") +def health(): + return { + "status": "healthy" + } + +@app.route("/stats") +def stats(): + uptime = int(time() - start_time) + + return { + "application": "Ghaymah SRE Exam", + "status": "healthy", + "version": "1.0.0", + "requests": request_count, + "uptime_seconds": uptime, + "response_time_ms": last_response_time + } + + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000) \ No newline at end of file diff --git a/q1-deploy-monitor/monitor.py b/q1-deploy-monitor/monitor.py new file mode 100644 index 0000000..d24249e --- /dev/null +++ b/q1-deploy-monitor/monitor.py @@ -0,0 +1,22 @@ +import time +import requests + +URL = "http://localhost:5000/health" + +while True: + start = time.time() + + try: + response = requests.get(URL, timeout=5) + + response_time = (time.time() - start) * 1000 + + print( + f"[OK] Status: {response.status_code} | " + f"Response Time: {response_time:.2f} ms" + ) + + except requests.exceptions.RequestException: + print("[DOWN] Service is unavailable") + + time.sleep(30) \ No newline at end of file diff --git a/q1-deploy-monitor/requirements.txt b/q1-deploy-monitor/requirements.txt new file mode 100644 index 0000000..44ff604 --- /dev/null +++ b/q1-deploy-monitor/requirements.txt @@ -0,0 +1,3 @@ +Flask==3.1.1 +requests==2.32.4 +flask-cors==6.0.1 \ No newline at end of file diff --git a/q1-deploy-monitor/static/script.js b/q1-deploy-monitor/static/script.js new file mode 100644 index 0000000..29dacf6 --- /dev/null +++ b/q1-deploy-monitor/static/script.js @@ -0,0 +1,50 @@ +async function loadStats() { + try { + const response = await fetch("/stats"); + const data = await response.json(); + + // Service Status + const statusElement = document.getElementById("status"); + + if (data.status === "healthy") { + statusElement.textContent = "🟢 Healthy"; + statusElement.style.color = "green"; + } else { + statusElement.textContent = "🔴 Down"; + statusElement.style.color = "red"; + } + + // Response Time + const responseElement = document.getElementById("response-time"); + responseElement.textContent = data.response_time_ms + " ms"; + + if (data.response_time_ms < 100) { + responseElement.style.color = "green"; + } else { + responseElement.style.color = "orange"; + } + + // Request Count + document.getElementById("requests").textContent = data.requests; + + // Uptime + const minutes = Math.floor(data.uptime_seconds / 60); + const seconds = data.uptime_seconds % 60; + + document.getElementById("uptime").textContent = + `${minutes} min ${seconds} sec`; + + } catch (error) { + + const statusElement = document.getElementById("status"); + statusElement.textContent = "🔴 Down"; + statusElement.style.color = "red"; + + document.getElementById("response-time").textContent = "--"; + document.getElementById("requests").textContent = "--"; + document.getElementById("uptime").textContent = "--"; + } +} + +loadStats(); +setInterval(loadStats, 5000); \ No newline at end of file diff --git a/q1-deploy-monitor/static/style.css b/q1-deploy-monitor/static/style.css new file mode 100644 index 0000000..052b8e7 --- /dev/null +++ b/q1-deploy-monitor/static/style.css @@ -0,0 +1,52 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: Arial, Helvetica, sans-serif; + background-color: #f5f7fa; + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; +} + +.container { + width: 90%; + max-width: 700px; + text-align: center; +} + +h1 { + margin-bottom: 30px; + color: #333; +} + +.card { + background-color: white; + margin: 15px 0; + padding: 20px; + border-radius: 10px; + border-left: 5px solid #007bff; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); +} + +.card h2 { + color: #555; + margin-bottom: 10px; + font-size: 26px; +} + +.card p { + font-size: 32px; + font-weight: bold; + color: #007bff; +} + +.refresh { + margin-top: 20px; + color: #777; + font-size: 15px; +} \ No newline at end of file diff --git a/q1-deploy-monitor/templates/index.html b/q1-deploy-monitor/templates/index.html new file mode 100644 index 0000000..0ee1091 --- /dev/null +++ b/q1-deploy-monitor/templates/index.html @@ -0,0 +1,45 @@ + + + + + + Ghaymah Monitoring Dashboard + + + + + +
+ +

🚀 Ghaymah Monitoring Dashboard

+ +
+

Service Status

+

Loading...

+
+ +
+

Response Time

+

Loading...

+
+ +
+

Request Count

+

Loading...

+
+ +
+

Uptime

+

Loading...

+
+ +

+ 🔄 Auto Refresh Every 5 Seconds +

+ +
+ + + + + \ No newline at end of file