Real-Time Dashboard (Flask + Socket.io) in Python
About the project: Here, we are building a real-time dashboard which requires combining a backend web framework (Flask) with a persistent, low-latency communication protocol like Socket.IO.
Here we shall provide the complete, self-contained Python file. This single file manages the Flask web server, the Socket.IO real-time layer, and the HTML/JavaScript client-side application.
Prerequisites
Before running the code, you must install the required libraries:
pip install Flask Flask-SocketIO eventlet
The server uses the eventlet WSGI server, which is recommended for robust Socket.IO performance.
Here is the complete project file.
import time
import random
import threading
from flask import Flask, render_template_string
from flask_socketio import SocketIO, emit
# Configuration
app = Flask(__name__)
# Suppress warning about using the Werkzeug development server
app.config['SECRET_KEY'] = 'a_very_secret_key_for_socketio'
socketio = SocketIO(app, async_mode='eventlet')
# --- 1. Real-Time Data Generation (Background Thread) ---
thread = None
thread_lock = threading.Lock()
STOP_EVENT = threading.Event()
def background_data_generator():
"""
A continuous loop that simulates updating system metrics
and emits the data to all connected clients via Socket.IO.
"""
print("Background data generator thread started.")
# Initial values (simulate some initial load)
cpu_load = 55
users_online = 12
tps = 8
while not STOP_EVENT.is_set():
time.sleep(1) # Emit data every 1 second
# 1. CPU Load: Drifts slowly, bounded between 10% and 95%
cpu_load = min(95, max(10, cpu_load + random.uniform(-3, 3)))
# 2. Users Online: Simulates traffic fluctuation
users_online = users_online + random.choice([-2, -1, 0, 1, 2])
users_online = max(5, users_online) # Minimum 5 users
# 3. Transactions Per Second (TPS): Simulates rapid spikes/drops
tps = tps + random.uniform(-1, 2)
tps = max(1, tps) # Minimum 1 TPS
# Format the data payload
data = {
'cpu_load': round(cpu_load, 1),
'users_online': users_online,
'tps': round(tps, 2),
'timestamp': time.strftime("%H:%M:%S")
}
# Send the data to all connected clients
socketio.emit('new_data', data)
print(f"Emitted data: CPU={data['cpu_load']}%, Users={data['users_online']}")
# --- 2. Flask Routes ---
@app.route('/')
def index():
"""
Serves the main dashboard HTML page.
"""
# Start the background thread only once when the first user connects to the index
global thread
with thread_lock:
if thread is None:
thread = socketio.start_background_task(target=background_data_generator)
return render_template_string(HTML_TEMPLATE)
# --- 3. Socket.IO Event Handlers ---
@socketio.on('connect')
def handle_connect():
"""Handles new client connections."""
print(f"Client connected: {threading.current_thread().name}")
emit('status', {'msg': 'Connected to Real-Time Feed'})
@socketio.on('disconnect')
def handle_disconnect():
"""Handles client disconnections."""
print("Client disconnected.")
# --- 4. Embedded HTML Template (Frontend) ---
# The HTML includes Tailwind CSS, the Socket.IO client, and custom JavaScript
# to handle the real-time updates.
HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Real-Time Dashboard</title>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
}
}
}
</script>
<style>
/* Optional custom styling for better visual */
.progress-bar {
transition: width 0.3s ease-in-out;
}
/* Mobile optimization */
@media (max-width: 640px) {
.grid-cols-3 {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body class="bg-gray-50 font-sans p-4 sm:p-8">
<div class="max-w-6xl mx-auto">
<header class="text-center mb-10">
<h1 class="text-4xl font-extrabold text-blue-700">Live System Dashboard</h1>
<p class="text-gray-500 mt-2">Real-time metrics updated every second via Socket.IO</p>
<p id="last-update" class="text-sm text-gray-400 mt-2">Last Update: --:--:--</p>
</header>
<!-- Metrics Cards Grid -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- Card 1: CPU Load -->
<div class="bg-white rounded-xl shadow-lg p-6 border-l-4 border-red-500">
<h2 class="text-xl font-semibold text-gray-700 mb-4 flex items-center">
<svg class="w-6 h-6 mr-2 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1h-.75m0-13l-1-1h-2l-1 1m0 0h-.01M9 20h6v-3H9v3z"></path></svg>
CPU Load
</h2>
<div class="text-5xl font-bold text-red-600" id="cpu-value">--</div>
<p class="text-sm text-gray-500 mt-1">Percentage of computing power in use.</p>
<div class="mt-4 h-2 bg-gray-200 rounded-full">
<div id="cpu-bar" class="progress-bar h-2 bg-red-500 rounded-full" style="width: 0%"></div>
</div>
</div>
<!-- Card 2: Users Online -->
<div class="bg-white rounded-xl shadow-lg p-6 border-l-4 border-blue-500">
<h2 class="text-xl font-semibold text-gray-700 mb-4 flex items-center">
<svg class="w-6 h-6 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.5v15m0 0l-6-6m6 6l6-6"></path></svg>
Users Online
</h2>
<div class="text-5xl font-bold text-blue-600" id="users-value">--</div>
<p class="text-sm text-gray-500 mt-1">Current active users on the platform.</p>
<div class="mt-4 text-center text-sm text-blue-500 font-medium">
<span id="users-delta">0</span> change
</div>
</div>
<!-- Card 3: Transactions/Sec -->
<div class="bg-white rounded-xl shadow-lg p-6 border-l-4 border-green-500">
<h2 class="text-xl font-semibold text-gray-700 mb-4 flex items-center">
<svg class="w-6 h-6 mr-2 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h-2v3m0 3v3m4-4h2m-2-2h-2"></path></svg>
Transactions/Sec
</h2>
<div class="text-5xl font-bold text-green-600" id="tps-value">--</div>
<p class="text-sm text-gray-500 mt-1">Average processing rate.</p>
<div class="mt-4 text-center text-sm text-green-500 font-medium">
Goal: > 5.00 TPS
</div>
</div>
</div>
<!-- Status Log -->
<div class="mt-10 bg-white p-6 rounded-xl shadow-lg">
<h3 class="text-2xl font-semibold text-gray-700 mb-4">Connection Log</h3>
<div id="log" class="h-24 overflow-y-auto bg-gray-100 p-3 rounded text-sm text-gray-600">
<p>Waiting for connection...</p>
</div>
</div>
</div>
<!-- Socket.IO Client CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
<script type="text/javascript">
// Connect to the Socket.IO server (defaults to current host and port)
var socket = io.connect('http://' + document.domain + ':' + location.port);
// Store previous user count to calculate delta
let previousUsers = 0;
// Function to append messages to the log window
function logMessage(message) {
const logElement = document.getElementById('log');
const p = document.createElement('p');
p.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
logElement.prepend(p);
}
// --- Socket Event Handlers ---
socket.on('connect', function() {
logMessage('Successfully connected to the Flask-SocketIO server.');
});
socket.on('disconnect', function() {
logMessage('Disconnected from the server. Attempting to reconnect...');
});
socket.on('status', function(data) {
logMessage(data.msg);
});
// --- Real-Time Data Handler ---
socket.on('new_data', function(data) {
// Update timestamp
document.getElementById('last-update').innerText = 'Last Update: ' + data.timestamp;
// 1. CPU Load Update
document.getElementById('cpu-value').innerText = data.cpu_load + '%';
document.getElementById('cpu-bar').style.width = data.cpu_load + '%';
// Apply color based on load
const cpuBar = document.getElementById('cpu-bar');
cpuBar.classList.remove('bg-red-500', 'bg-yellow-500', 'bg-green-500');
if (data.cpu_load > 80) {
cpuBar.classList.add('bg-red-500'); // High
} else if (data.cpu_load > 50) {
cpuBar.classList.add('bg-yellow-500'); // Medium
} else {
cpuBar.classList.add('bg-green-500'); // Low
}
// 2. Users Online Update
document.getElementById('users-value').innerText = data.users_online;
// Calculate and display user delta
const delta = data.users_online - previousUsers;
const deltaElement = document.getElementById('users-delta');
deltaElement.innerText = (delta > 0 ? '+' : '') + delta;
deltaElement.classList.remove('text-red-500', 'text-blue-500', 'text-gray-500');
if (delta > 0) {
deltaElement.classList.add('text-green-500'); // Gained users
} else if (delta < 0) {
deltaElement.classList.add('text-red-500'); // Lost users
} else {
deltaElement.classList.add('text-blue-500'); // Stable
}
previousUsers = data.users_online;
// 3. Transactions Per Second (TPS) Update
document.getElementById('tps-value').innerText = data.tps.toFixed(2);
});
</script>
</body>
</html>
"""
# --- 5. Application Run ---
if __name__ == '__main__':
try:
# Use eventlet as the async mode for production-ready SocketIO performance
print("Starting Flask-SocketIO server with eventlet...")
print("Access the dashboard at: http://127.0.0.1:5000/")
socketio.run(app, host='0.0.0.0', port=5000)
except KeyboardInterrupt:
print("\nStopping application...")
finally:
# Ensure the background thread stops cleanly
STOP_EVENT.set()
if thread and thread.is_alive():
thread.join()
print("Cleanup complete. Application terminated.")
How to Run
- Save: Save the code above as a single file named dashboard_app.py.
- Open your terminal in the same directory.
- Run the application:
- Access: Open your browser and navigate to the local host address shown in your console (usually `http://127.0.0.1:5000/`).
python dashboard_app.py
You will see the three dashboard metrics updating every second without needing to refresh the page.
← Back to Projects
