Real-Time Dashboard (Flask + Socket.io)

← Back to Projects

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.


Project Level: Advance

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

  1. Save: Save the code above as a single file named dashboard_app.py.
  2. Open your terminal in the same directory.
  3. Run the application:
  4. 
          python dashboard_app.py
        
  5. Access: Open your browser and navigate to the local host address shown in your console (usually `http://127.0.0.1:5000/`).
You will see the three dashboard metrics updating every second without needing to refresh the page.

← Back to Projects