☰
Current Page
Main Menu
Home
Home
Editing Building a Real-Time System Monitoring Dashboard with Python
Edit
Preview
H1
H2
H3
default
Set your preferred keybinding
default
vim
emacs
markdown
Set this page's format to
AsciiDoc
Creole
Markdown
MediaWiki
Org-mode
Plain Text
RDoc
Textile
Rendering unavailable for
BibTeX
Pod
reStructuredText
Help 1
Help 1
Help 1
Help 2
Help 3
Help 4
Help 5
Help 6
Help 7
Help 8
Autosaved text is available. Click the button to restore it.
Restore Text
https://towardsdev.com/building-a-real-time-system-monitoring-dashboard-with-python-6e09ff15e0ff # Building a Real-Time System Monitoring Dashboard with Python | by Py-Core Python Programming | Towards Dev [  ](https://medium.com/@ccpythonprogramming?source=post_page---byline--6e09ff15e0ff--------------------------------) [  ](https://towardsdev.com/?source=post_page---byline--6e09ff15e0ff--------------------------------) System Dashboard with Plotly in Python Let’s create a dashboard using Python that monitors your system’s performance in real-time. The dashboard will display your PC’s RAM, CPU load and disk space usage. We will use **Dash** for the web interface, **Plotly** for interactive graphs, **psutil** for system monitoring. This will work on both Windows and Linux systems. However, for macOS users or special configurations, slight modifications may be needed.  Dash/**Plotly** Python GIF Project Setup ------------- Step 1: Create a Project Folder ------------------------------- Begin by creating a folder for the project. Open a terminal (or command prompt) and create a new directory. ``` mkdir system_monitor_dashboard cd system_monitor_dashboard ``` Step 2: Set Up a Virtual Environment ------------------------------------ Isolating your project dependencies is important. We’ll create a virtual environment to keep our environment clean and predictable. For Windows: ------------ ``` python -m venv venv venv\Scripts\activate ``` For Linux/Mac: -------------- ``` python3 -m venv venv source venv/bin/activate ``` Step 3: Install Required Libraries ---------------------------------- We need to install the following Python packages: * `dash`: Web framework for building dashboards. * `plotly`: Used to create graphs and charts. * `pandas`: For handling data in a tabular format. * `psutil`: For monitoring system resources. Install them by running: ``` pip install dash plotly pandas psutil ``` This will install all the libraries required to build our dashboard. Building the Dashboard ---------------------- Step 4: Writing the Code ------------------------ Now we’ll create a Python script that gathers system statistics and displays them using a dynamic, real-time dashboard. 1. **Monitor RAM, CPU, and Disk** The `psutil` library provides cross-platform access to system monitoring information. It works on Windows, Linux, and macOS. Create a new Python file called `app.py`: ``` touch app.py ``` Open `app.py` and paste the following code: ``` import dash from dash import dcc, html from dash.dependencies import Input, Output import plotly.graph_objs as go import psutil import logging from collections import deque from datetime import datetime import sys # Set up basic logging to debug logging.basicConfig(level=logging.INFO) # Initialize the Dash app app = dash.Dash(__name__) # Define fixed-size lists (deque) to store the last 20 data points for RAM, CPU, Disk usage, and time history = { 'ram': deque(maxlen=20), 'cpu': deque(maxlen=20), 'disk': deque(maxlen=20), 'time': deque(maxlen=20) # Store timestamps for x-axis } # Function to get system statistics (RAM, CPU, and Disk) def get_system_stats(): try: # Get memory stats memory = psutil.virtual_memory() ram = memory.percent # Get CPU usage cpu = psutil.cpu_percent(interval=1) # Get Disk usage disk = psutil.disk_usage('/').percent # Return RAM, CPU, and Disk data return { 'RAM Usage (%)': ram, 'CPU Usage (%)': cpu, 'Disk Usage (%)': disk } except Exception as e: logging.error(f"Error fetching system stats: {e}") return {} # Determine whether to run in 'one' or 'multiple' mode based on command-line argument mode = sys.argv[1] if len(sys.argv) > 1 else 'multiple' if mode == 'one': app.layout = html.Div([ html.H1('System Monitoring Dashboard (Combined Graph)'), # Combined Line Chart for RAM, CPU, and Disk dcc.Graph(id='combined-graph'), # Interval for updating the dashboard every 5 seconds dcc.Interval( id='interval-component', interval=5*1000, # 5000 milliseconds (5 seconds) n_intervals=0 ) ]) # Update callback to refresh the combined RAM, CPU, and Disk usage graph every interval @app.callback( Output('combined-graph', 'figure'), [Input('interval-component', 'n_intervals')] ) def update_combined_graph(n): # Fetch system stats (RAM, CPU, and Disk) data = get_system_stats() if not data: logging.info("No data fetched") return {} # Log fetched data in the terminal logging.info(f"Fetched data: {data}") # Append the current time, RAM, CPU, and Disk usage to history current_time = datetime.now().strftime('%H:%M:%S') # Get the current time as a string history['ram'].append(data['RAM Usage (%)']) history['cpu'].append(data['CPU Usage (%)']) history['disk'].append(data['Disk Usage (%)']) history['time'].append(current_time) # Create Combined Line Chart combined_figure = { 'data': [ go.Scatter( x=list(history['time']), y=list(history['ram']), mode='lines+markers', name='RAM Usage (%)' ), go.Scatter( x=list(history['time']), y=list(history['cpu']), mode='lines+markers', name='CPU Usage (%)' ), go.Scatter( x=list(history['time']), y=list(history['disk']), mode='lines+markers', name='Disk Usage (%)' ) ], 'layout': go.Layout( title='RAM, CPU, and Disk Usage Over Time', xaxis=dict(title='Time', tickformat='%H:%M:%S'), # Format the time yaxis=dict(title='Percentage'), ) } return combined_figure else: # Layout for multiple graphs (RAM, CPU, Disk each on its own graph) app.layout = html.Div([ html.H1('System Monitoring Dashboard (Separate Graphs)'), # RAM Usage Line Chart dcc.Graph(id='ram-usage-graph'), # CPU Usage Line Chart dcc.Graph(id='cpu-usage-graph'), # Disk Usage Line Chart dcc.Graph(id='disk-usage-graph'), # Interval for updating the dashboard every 5 seconds dcc.Interval( id='interval-component', interval=5*1000, # 5000 milliseconds (5 seconds) n_intervals=0 ) ]) # Update callback to refresh the RAM, CPU, and Disk usage graphs every interval @app.callback( [Output('ram-usage-graph', 'figure'), Output('cpu-usage-graph', 'figure'), Output('disk-usage-graph', 'figure')], [Input('interval-component', 'n_intervals')] ) def update_separate_graphs(n): # Fetch system stats (RAM, CPU, and Disk) data = get_system_stats() if not data: logging.info("No data fetched") return {}, {}, {} # Log fetched data in the terminal logging.info(f"Fetched data: {data}") # Append the current time, RAM, CPU, and Disk usage to history current_time = datetime.now().strftime('%H:%M:%S') # Get the current time as a string history['ram'].append(data['RAM Usage (%)']) history['cpu'].append(data['CPU Usage (%)']) history['disk'].append(data['Disk Usage (%)']) history['time'].append(current_time) # Create RAM Usage Line Chart ram_figure = { 'data': [go.Scatter( x=list(history['time']), y=list(history['ram']), mode='lines+markers', name='RAM Usage (%)' )], 'layout': go.Layout( title='RAM Usage Over Time', xaxis=dict(title='Time', tickformat='%H:%M:%S'), # Format the time yaxis=dict(title='Percentage'), ) } # Create CPU Usage Line Chart cpu_figure = { 'data': [go.Scatter( x=list(history['time']), y=list(history['cpu']), mode='lines+markers', name='CPU Usage (%)' )], 'layout': go.Layout( title='CPU Usage Over Time', xaxis=dict(title='Time', tickformat='%H:%M:%S'), # Format the time yaxis=dict(title='Percentage'), ) } # Create Disk Usage Line Chart disk_figure = { 'data': [go.Scatter( x=list(history['time']), y=list(history['disk']), mode='lines+markers', name='Disk Usage (%)' )], 'layout': go.Layout( title='Disk Usage Over Time', xaxis=dict(title='Time', tickformat='%H:%M:%S'), # Format the time yaxis=dict(title='Percentage'), ) } return ram_figure, cpu_figure, disk_figure # Run the app if __name__ == '__main__': app.run_server(debug=True) ``` Step 5: Running the Dashboard ----------------------------- 1. Ensure your virtual environment is activated. 2. Run the dashboard with the following command to show one chart with all three metrics: ``` python app.py one ``` 3\. Run the dashboard with the following command to show three charts each with one metric: ``` python app.py multiple ``` This will start the application on a local web server. Open your browser and visit: ``` http://127.0.0.1:8050/ ``` You’ll see a dashboard that updates every 5 seconds, showing: * **RAM Usage** in percentage * **CPU Usage** in percentage * **Disk Usage** in percentage Step 6: Additional Notes ------------------------ * **psutil** works cross-platform, so the code will run on both Windows and Linux without modification. * If you’re on a macOS system, all functions except disk usage should work. You might need to adjust `psutil.disk_usage('/')` if you have a different filesystem configuration. Breakdown of Above Code: ------------------------ 1\. Setting Up the Logging System --------------------------------- The logging configuration is initialized early in the script, allowing us to capture and print important debugging information to the console.# Set up basic logging to debug ``` # Set up basic logging to debug logging.basicConfig(level=logging.INFO) ``` This line configures the logging system to show messages at the `INFO` level or higher, providing useful feedback during the program's execution. 2\. Initializing the Dash Application ------------------------------------- Dash is a powerful Python framework for building interactive web applications. The app is initialized as follows: ``` # Initialize the Dash app app = dash.Dash(__name__) ``` This creates a Dash application, which will serve as the basis for the real-time dashboard. The `__name__` parameter helps Dash locate resources correctly. 3\. Setting Up History with Deques ---------------------------------- Deques (double-ended queues) are used to store the last 20 data points for RAM, CPU, Disk usage, and timestamps. ``` # Define fixed-size lists (deque) to store the last 20 data points for RAM, CPU, Disk usage, and time history = { 'ram': deque(maxlen=20), 'cpu': deque(maxlen=20), 'disk': deque(maxlen=20), 'time': deque(maxlen=20) # Store timestamps for x-axis } ``` The `maxlen=20` ensures that only the last 20 values are kept in memory, and older values are automatically removed. This is particularly useful for real-time graphs, which only need to show a limited number of recent data points. 4\. Fetching System Statistics ------------------------------ We use the `psutil` library to gather system data such as RAM, CPU, and disk usage. The `get_system_stats` function is responsible for this: ``` def get_system_stats(): try: # Get memory stats memory = psutil.virtual_memory() ram = memory.percent # Get CPU usage cpu = psutil.cpu_percent(interval=1) # Get Disk usage disk = psutil.disk_usage('/').percent # Return RAM, CPU, and Disk data return { 'RAM Usage (%)': ram, 'CPU Usage (%)': cpu, 'Disk Usage (%)': disk } except Exception as e: logging.error(f"Error fetching system stats: {e}") return {} ``` **RAM Usage**: We call `psutil.virtual_memory()` to get memory information and extract the percentage of RAM in use. **CPU Usage**: The `psutil.cpu_percent()` function returns the current CPU usage. The `interval=1` argument tells the function to calculate CPU usage over a 1-second period. **Disk Usage**: We use `psutil.disk_usage('/')` to get the disk usage percentage for the root directory (`/`). This function gathers all this data and returns it as a dictionary. If an error occurs, it logs the error and returns an empty dictionary. 5\. Mode Selection: Single or Multiple Graphs --------------------------------------------- The dashboard can operate in two modes: either all data is combined in a single graph, or each metric (RAM, CPU, and Disk) has its own graph. This is determined by checking the command-line arguments: ``` # Determine whether to run in 'one' or 'multiple' mode based on command-line argument mode = sys.argv[1] if len(sys.argv) > 1 else 'multiple' ``` If the argument `one` is provided when the script is run, the application will combine all the data into a single graph. If no argument or `multiple` is provided, separate graphs will be displayed. 6\. Creating the Layout and Callbacks for Combined Graph Mode ------------------------------------------------------------- When running in the `one` mode, the layout contains a single graph, and the data is refreshed every 5 seconds: ``` if mode == 'one': app.layout = html.Div([ html.H1('System Monitoring Dashboard (Combined Graph)'), # Combined Line Chart for RAM, CPU, and Disk dcc.Graph(id='combined-graph'), # Interval for updating the dashboard every 5 seconds dcc.Interval( id='interval-component', interval=5*1000, # 5000 milliseconds (5 seconds) n_intervals=0 ) ]) ``` This layout includes a title (`html.H1`) and a graph component (`dcc.Graph`). The `dcc.Interval` component is used to refresh the data every 5 seconds (`5000 milliseconds`). The callback function below updates the combined graph by fetching the latest system stats and adding them to the `history` deques: ``` @app.callback( Output('combined-graph', 'figure'), [Input('interval-component', 'n_intervals')] ) def update_combined_graph(n): # Fetch system stats (RAM, CPU, and Disk) data = get_system_stats() if not data: logging.info("No data fetched") return {} # Log fetched data in the terminal logging.info(f"Fetched data: {data}") # Append the current time, RAM, CPU, and Disk usage to history current_time = datetime.now().strftime('%H:%M:%S') # Get the current time as a string history['ram'].append(data['RAM Usage (%)']) history['cpu'].append(data['CPU Usage (%)']) history['disk'].append(data['Disk Usage (%)']) history['time'].append(current_time) # Create Combined Line Chart combined_figure = { 'data': [ go.Scatter( x=list(history['time']), y=list(history['ram']), mode='lines+markers', name='RAM Usage (%)' ), go.Scatter( x=list(history['time']), y=list(history['cpu']), mode='lines+markers', name='CPU Usage (%)' ), go.Scatter( x=list(history['time']), y=list(history['disk']), mode='lines+markers', name='Disk Usage (%)' ) ], 'layout': go.Layout( title='RAM, CPU, and Disk Usage Over Time', xaxis=dict(title='Time', tickformat='%H:%M:%S'), # Format the time yaxis=dict(title='Percentage'), ) } return combined_figure ``` This callback fetches the data every 5 seconds, appends it to the `history` deque, and then creates a combined line chart to display the three metrics over time. 7\. Creating the Layout and Callbacks for Multiple Graphs Mode -------------------------------------------------------------- In `multiple` mode, the layout consists of three separate graphs (one for each metric): ``` else: app.layout = html.Div([ html.H1('System Monitoring Dashboard (Separate Graphs)'), # RAM Usage Line Chart dcc.Graph(id='ram-usage-graph'), # CPU Usage Line Chart dcc.Graph(id='cpu-usage-graph'), # Disk Usage Line Chart dcc.Graph(id='disk-usage-graph'), # Interval for updating the dashboard every 5 seconds dcc.Interval( id='interval-component', interval=5*1000, # 5000 milliseconds (5 seconds) n_intervals=0 ) ]) ``` The callback in this mode updates each graph individually: ``` @app.callback( [Output('ram-usage-graph', 'figure'), Output('cpu-usage-graph', 'figure'), Output('disk-usage-graph', 'figure')], [Input('interval-component', 'n_intervals')] ) def update_separate_graphs(n): # Fetch system stats (RAM, CPU, and Disk) data = get_system_stats() if not data: logging.info("No data fetched") return {}, {}, {} # Append the current time, RAM, CPU, and Disk usage to history current_time = datetime.now().strftime('%H:%M:%S') history['ram'].append(data['RAM Usage (%)']) history['cpu'].append(data['CPU Usage (%)']) history['disk'].append(data['Disk Usage (%)']) history['time'].append(current_time) # Create RAM, CPU, and Disk Usage Line Charts ram_figure = { 'data': [go.Scatter( x=list(history['time']), y=list(history['ram']), mode='lines+markers', name='RAM Usage (%)' )], 'layout': go.Layout(title='RAM Usage Over Time', xaxis=dict(title='Time'), yaxis=dict(title='Percentage')) } cpu_figure = { 'data': [go.Scatter( x=list(history['time']), y=list(history['cpu']), mode='lines+markers', name='CPU Usage (%)' )], 'layout': go.Layout(title='CPU Usage Over Time', xaxis=dict(title='Time'), yaxis=dict(title='Percentage')) } disk_figure = { 'data': [go.Scatter( x=list(history['time']), y=list(history['disk']), mode='lines+markers', name='Disk Usage (%)' )], 'layout': go.Layout(title='Disk Usage Over Time', xaxis=dict(title='Time'), yaxis=dict(title='Percentage')) } return ram_figure, cpu_figure, disk_figure ``` Each graph displays its own data set, pulled from the `history` deque and updated every 5 seconds. 8\. Running the App ------------------- Finally, the Dash app is started using the `app.run_server()` function: ``` if __name__ == '__main__': app.run_server(debug=True) ``` Running the app with `python app.py one` will display a combined graph, while `python app.py multiple` will display separate graphs for each metric. Visit this [link](https://medium.com/p/35613932d123) for a similar project that uses Chart.js rather than dash/plotly. Thank you for reading this article. I hope you found it helpful and informative. If you have any questions, or if you would like to suggest new Python code examples or topics for future tutorials, please feel free to reach out. Your feedback and suggestions are always welcome! Happy coding! C. C. Python Programming
Uploading file...
Edit message:
Cancel