Build a Windows System Health Monitor
Write a Python script that monitors CPU, memory, and disk usage in real-time.
Introduction
30 Second Summary
Your computer is constantly juggling dozens of tasks behind the scenes. Sometimes things slow down, the fan kicks into high gear, or storage fills up without warning. Instead of manually opening Task Manager to check what is going on, what if a script could watch your system for you and sound the alarm?
In this project, you will build a Python script that monitors your Windows machine's CPU, memory, and disk usage in real time. When any metric crosses a threshold you set, the script logs a timestamped warning so you can spot patterns over time.
What You'll Build
A Python script called health_monitor.py that reads real-time system metrics using the psutil library and compares them against configurable thresholds, logging warnings to both the console and a file.
By the end of this project, you'll have:
- A health_monitor.py script that reads CPU, memory, and disk metrics from your Windows machine using psutil.
- A configurable threshold system that triggers warnings when resources exceed limits you define.
- A system_health.log file with timestamped alerts you can review to spot patterns over time.
- Secret Mission: Make your monitor run continuously on a loop and generate a summary report of all alerts.
Are there any prerequisites?
None. This guide walks you through installing everything you need, including Python and the psutil library. All you need is a Windows machine with PyCharm installed.
Set Up Your Python Environment
Before you can monitor your system, you need a working Python environment with the right tools installed.
In this step, you will create a new project in PyCharm, confirm Python is available, and install the psutil library that reads your system metrics.
In this step, get ready to:
- Create a new PyCharm project and verify Python is available in the terminal.
- Install the psutil library using pip.
- Verify psutil is working by running a quick test in the Python console.
Create a new project and verify Python
PyCharm organises your code into projects. You need a fresh project to hold your health monitor script.
- In PyCharm, click New Project on the Welcome screen.
- If you already have a project open, go to File in the menu bar, then click New Project.
- In the Location field, change the last folder name to health-monitor.
- Leave the interpreter set to the default Project venv option.
- Uncheck Create a main.py welcome script if it is selected.
- Click Create.
What just happened?
PyCharm created a project folder called health-monitor and set up a virtual environment inside it.
A virtual environment keeps your project's packages separate from your system-wide Python installation. This means installing psutil here will not affect any other Python projects on your machine.
Now confirm that Python is accessible from PyCharm's built-in terminal.
- Open the terminal by pressing Alt+F12, or go to View then Tool Windows then Terminal.
- Check your Python version by running this command:
python --version
✔️ I see Python 3.x
You should see something like Python 3.11.4 or any version starting with 3. Python is ready to go.
ⓧ 'python' is not recognized
PyCharm's virtual environment may not have activated automatically. Try running:
py --version
If that shows a Python 3 version, use py instead of python for the rest of this project.
If neither command works, close the terminal tab and reopen it with Alt+F12. PyCharm should detect your interpreter on the next attempt.
Install the psutil library
Your script needs a way to read CPU, memory, and disk metrics from your machine. The psutil library provides a simple interface for exactly this.
- Install psutil by running this command in the terminal:
pip install psutil
What does this command do?
The pip tool is Python's package manager. It downloads psutil from the Python Package Index (PyPI) and installs it into your project's virtual environment.
- Confirm the installation succeeded. You should see a line near the end of the output that says Successfully installed psutil followed by a version number.
Seeing a permissions error?
Make sure you are running the command inside PyCharm's terminal, not a system-level command prompt. PyCharm's terminal automatically activates the project's virtual environment, which avoids permission issues.
If the error persists, try running:
python -m pip install psutil
Help me fix a pip install error in PyCharm.
Test psutil and create your script file
Before writing your full script, confirm psutil can actually read your system data.
- Open the Python interactive console by running this command in the terminal:
python
- You should see a >>> prompt appear. Type the following lines one at a time, pressing Enter after each:
import psutil
print(psutil.cpu_percent(interval=1))
What should I see?
After a one-second pause, Python prints a number representing your current CPU usage as a percentage (for example, 12.5). Any number means psutil is working correctly.
The interval=1 argument tells psutil to measure CPU activity over one second. Without it, the first call always returns 0.0 because there is no baseline to compare against.
- Exit the Python console by typing:
exit()
Now create the file that will hold your health monitor script.
- In the Project panel on the left side of PyCharm, right-click the health-monitor project root folder.
- Select New, then click Python File.
- Type health_monitor as the filename and press Enter.
Why health_monitor and not health-monitor?
Python filenames use underscores instead of hyphens. A hyphen in a filename would prevent you from importing it as a module later.
- Confirm health_monitor.py appears in the Project panel and opens as an empty file in the editor.
Don't see the file in the Project panel?
Make sure you right-clicked on the project root folder (the top-level health-monitor folder), not the venv folder inside it. If the file ended up in the wrong location, drag it to the project root in the Project panel.
Help me create a Python file in PyCharm.
Your environment is ready. You have Python, psutil, and an empty script file waiting for code. Next up, you will write functions that read your system's CPU, memory, and disk usage in real time.
Read System Metrics with psutil
In the previous step, you installed psutil and confirmed it can talk to your system. Now it's time to put it to work.
Your health monitor needs to read real data from your machine. In this step, you'll write functions that grab CPU, memory, and disk usage percentages using psutil, then format those numbers into a readable health report.
In this step, get ready to:
- Write functions that read CPU, memory, and disk metrics.
- Explore what psutil returns by testing functions in the Python console.
- Format the raw values into a readable health report.
Write functions to read CPU, memory, and disk usage
Each metric your monitor tracks needs its own function. This keeps the code organized and makes it easy to add new metrics later.
- Switch to the health_monitor.py tab in PyCharm.
- Replace the empty file contents with the following imports and metric functions:
import psutil
import logging
from datetime import datetime
# --- Metric Functions ---
def get_cpu_usage():
# Block for 1 second then return the CPU usage percentage
return psutil.cpu_percent(interval=1)
def get_memory_usage():
# Get the virtual memory stats as a named tuple
memory = psutil.virtual_memory()
return memory.percent
def get_disk_usage():
# Check the C:\ drive usage on Windows
disk = psutil.disk_usage("C:\\")
return disk.percent
What does this code do?
Each function calls a different psutil method and returns a single percentage value.
- get_cpu_usage() uses psutil.cpu_percent(interval=1) which blocks for 1 second to measure actual CPU load. Without the interval parameter, the first call always returns 0.0.
- get_memory_usage() calls psutil.virtual_memory() which returns a named tuple with fields like total, available, and percent. You grab just the percent field.
- get_disk_usage() checks the C:\\ drive specifically, since this is a Windows project.
The logging and datetime imports are not used yet. You will wire them up in later steps.
- Save health_monitor.py by pressing Ctrl+S.
Seeing a red underline on psutil?
If PyCharm shows an unresolved reference error on psutil, the interpreter might not match the one where you installed the library. Check that your project interpreter is the same Python where you ran pip install psutil in the previous step.
help me fix an unresolved import error for psutil in PyCharm
Test the metric functions in PyCharm's Python console
Before building the full report, explore what psutil actually returns. The Python console lets you call functions interactively without running the whole file.
- Open PyCharm's interactive console by clicking Tools in the top menu bar.
- Select Python Console. A console panel opens at the bottom of the screen.
- Import psutil by running this command in the console:
import psutil
- Test the CPU function by running:
psutil.cpu_percent(interval=1)
You should see a float like 12.5 representing your current CPU usage percentage. It will pause for one second before returning.
- Test the memory function by running:
psutil.virtual_memory()
You should see a named tuple with fields like total, available, percent, used, and free. The percent field is the one your function extracts.
- Test the disk function by running:
psutil.disk_usage("C:\\")
You should see another named tuple with total, used, free, and percent fields showing your C:\ drive stats.
Why named tuples?
psutil returns named tuples instead of plain numbers. A named tuple is like a lightweight object where you access fields by name (memory.percent) instead of by index. This makes the code more readable than working with raw numbers or dictionaries.
Format the output into a readable health report
Raw percentages are useful, but a formatted report is easier to read at a glance. You will add a function that prints the metrics in a clean table layout.
- In health_monitor.py, add the following code below the get_disk_usage() function:
# --- Health Report ---
def print_health_report(cpu, memory, disk):
# Print a formatted banner with current timestamp
print("\n" + "=" * 50)
print(f" SYSTEM HEALTH REPORT - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 50)
print(f" CPU Usage: {cpu}%")
print(f" Memory Usage: {memory}%")
print(f" Disk Usage: {disk}%")
print("=" * 50)
if __name__ == "__main__":
# Call each metric function and display the report
cpu = get_cpu_usage()
memory = get_memory_usage()
disk = get_disk_usage()
print_health_report(cpu, memory, disk)
What does this code do?
- print_health_report() takes three percentage values and prints them inside a banner of = characters. The datetime.now().strftime() call stamps the report with the current date and time.
- The if __name__ == "__main__": block runs only when you execute the file directly. It calls each metric function, stores the results, and passes them to the report printer.
- f-strings (like f"CPU Usage: {cpu}%") let you embed variable values directly inside strings. The curly braces get replaced with the actual values at runtime.
- Save health_monitor.py by pressing Ctrl+S.
- Run the script by right-clicking inside the editor and selecting Run 'health_monitor'.
You should see a formatted health report in the Run panel at the bottom of PyCharm, showing your current CPU, memory, and disk percentages inside a banner of = characters.
Report not showing up?
- Check that the if __name__ == "__main__": line is flush left (no indentation). If it is indented, Python treats it as part of the function above.
- Make sure there are no typos in print_health_report. The function name must match exactly between the definition and the call.
- If you see NameError: name 'datetime' is not defined, confirm the from datetime import datetime line is at the top of your file.
help me debug my health_monitor.py script that is not printing the report
✔️ Awesome, I've got everything!
Great. Double check you have saved health_monitor.py and the report prints correctly when you run the file.
ⓧ I'd like to double check the full code
Here is the complete health_monitor.py at the end of this step:
import psutil
import logging
from datetime import datetime
# --- Metric Functions ---
def get_cpu_usage():
return psutil.cpu_percent(interval=1)
def get_memory_usage():
memory = psutil.virtual_memory()
return memory.percent
def get_disk_usage():
disk = psutil.disk_usage("C:\\")
return disk.percent
# --- Health Report ---
def print_health_report(cpu, memory, disk):
print("\n" + "=" * 50)
print(f" SYSTEM HEALTH REPORT - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 50)
print(f" CPU Usage: {cpu}%")
print(f" Memory Usage: {memory}%")
print(f" Disk Usage: {disk}%")
print("=" * 50)
if __name__ == "__main__":
cpu = get_cpu_usage()
memory = get_memory_usage()
disk = get_disk_usage()
print_health_report(cpu, memory, disk)
Your script can now read live metrics from your machine and display them in a clean report. Next up, you will add configurable thresholds so the script can warn you when a resource is running hot.
Add Configurable Thresholds and Alerts
Your script can read CPU, memory, and disk metrics. But raw numbers alone are not very useful.
What you really need is a way to know when something is wrong. In this step, you will define threshold values and write a function that compares live metrics against those thresholds. When a metric crosses the line, your script prints a warning.
In this step, get ready to:
- Define a dictionary of threshold values for CPU, memory, and disk.
- Write a function that compares current metrics against thresholds.
- Print warning messages when thresholds are exceeded.
Define threshold values in a dictionary
A threshold is a limit that triggers an alert when crossed. You will store these limits in a Python dictionary so they are easy to update later without digging through your logic code.
- In health_monitor.py, find the # --- Metric Functions --- comment near the top of your file.
- Add the following code above that comment:
# --- Configuration ---
THRESHOLDS = {
"cpu": 80.0,
"memory": 85.0,
"disk": 90.0,
}
What does this code do?
The THRESHOLDS dictionary maps each metric name to a percentage limit. If CPU usage goes above 80%, memory above 85%, or disk above 90%, your script will flag it as a problem.
Storing thresholds in a dictionary at the top of the file means you can tweak the values in one place without hunting through your functions.
- Save health_monitor.py.
- You will not see a change yet. The next chunk uses this dictionary to generate alerts.
Write a function that compares metrics against thresholds
Now you need a function that takes the current CPU, memory, and disk values and checks each one against the matching threshold. If a value exceeds its threshold, the function builds a warning message and collects it in a list.
- In health_monitor.py, find the # --- Health Report --- comment.
- Add the following code above that comment:
# --- Threshold Checking ---
def check_thresholds(cpu, memory, disk):
alerts = []
if cpu > THRESHOLDS["cpu"]:
message = f"CPU usage is at {cpu}% (threshold: {THRESHOLDS['cpu']}%)"
alerts.append(message)
if memory > THRESHOLDS["memory"]:
message = f"Memory usage is at {memory}% (threshold: {THRESHOLDS['memory']}%)"
alerts.append(message)
if disk > THRESHOLDS["disk"]:
message = f"Disk usage is at {disk}% (threshold: {THRESHOLDS['disk']}%)"
alerts.append(message)
return alerts
What does this code do?
The check_thresholds function receives three metric values and compares each one to the matching entry in THRESHOLDS.
When a metric exceeds its threshold, an f-string builds a human-readable message showing both the current value and the threshold. Each message gets appended to the alerts list, which the function returns at the end. An empty list means everything is healthy.
- Save health_monitor.py.
- You will not see a change yet. The next chunk calls this function and prints any alerts.
Print warning messages when thresholds are exceeded
The last piece is to call your new function from the main block and print any alerts to the console so you can see them immediately.
- In health_monitor.py, scroll to the if __name__ == "__main__": block at the bottom.
- Find this line:
print_health_report(cpu, memory, disk)
- Add the following code below that line:
alerts = check_thresholds(cpu, memory, disk)
for alert in alerts:
print(f" [!] {alert}")
What does this code do?
This calls check_thresholds with the metrics you already collected, then loops through any returned alert messages and prints each one with a [!] prefix so warnings stand out in the console output.
- Save health_monitor.py.
- Run the script by right-clicking in the editor and selecting Run 'health_monitor'.
- You should see your health report print to the Run tool window. If any of your system metrics exceed the thresholds (CPU above 80%, memory above 85%, or disk above 90%), you will also see lines starting with [!] showing which metric triggered.
Not seeing any alert messages?
If your system is running comfortably below all thresholds, no alerts will print. That means the script is working correctly. You can temporarily lower a threshold (e.g. change "cpu": 80.0 to "cpu": 5.0) to force an alert and confirm the logic works.
If you see a NameError mentioning THRESHOLDS, make sure the THRESHOLDS dictionary is defined above your functions, not inside one.
Help me debug my threshold alerts not printing.
✔️ Awesome, I've got everything!
Great. Double check you have saved your file.
ⓧ I'd like to double check the full code
import psutil
import logging
from datetime import datetime
# --- Configuration ---
THRESHOLDS = {
"cpu": 80.0,
"memory": 85.0,
"disk": 90.0,
}
# --- Metric Functions ---
def get_cpu_usage():
return psutil.cpu_percent(interval=1)
def get_memory_usage():
memory = psutil.virtual_memory()
return memory.percent
def get_disk_usage():
disk = psutil.disk_usage("C:\\")
return disk.percent
# --- Threshold Checking ---
def check_thresholds(cpu, memory, disk):
alerts = []
if cpu > THRESHOLDS["cpu"]:
message = f"CPU usage is at {cpu}% (threshold: {THRESHOLDS['cpu']}%)"
alerts.append(message)
if memory > THRESHOLDS["memory"]:
message = f"Memory usage is at {memory}% (threshold: {THRESHOLDS['memory']}%)"
alerts.append(message)
if disk > THRESHOLDS["disk"]:
message = f"Disk usage is at {disk}% (threshold: {THRESHOLDS['disk']}%)"
alerts.append(message)
return alerts
# --- Health Report ---
def print_health_report(cpu, memory, disk):
print("\n" + "=" * 50)
print(f" SYSTEM HEALTH REPORT - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 50)
print(f" CPU Usage: {cpu}%")
print(f" Memory Usage: {memory}%")
print(f" Disk Usage: {disk}%")
print("=" * 50)
if __name__ == "__main__":
cpu = get_cpu_usage()
memory = get_memory_usage()
disk = get_disk_usage()
print_health_report(cpu, memory, disk)
alerts = check_thresholds(cpu, memory, disk)
for alert in alerts:
print(f" [!] {alert}")
Your script now has brains. It reads metrics and flags anything that crosses the line. Next up, you will connect these alerts to Python's logging module so warnings get saved to a file with timestamps.
Log Alerts to a File
Your threshold checker prints warnings to the console, which is useful while you're watching. But the moment you close your terminal, those warnings vanish.
In this step, you'll set up Python's logging module to save every alert to a file called system_health.log. Each entry gets a timestamp, so you can review patterns over time without needing to sit in front of the screen.
In this step, get ready to:
- Set up Python's logging module to write alerts to a file.
- Configure the log format with timestamps and severity levels.
- Connect your threshold alerts to the logging system so warnings are saved to disk.
Configure the logging module
Python's built-in logging module lets you send messages to multiple destinations at once. You'll configure it to write warnings to both a log file and the console simultaneously.
- In health_monitor.py, find the line that says # --- Metric Functions ---.
- Add the following logging configuration block directly above that line:
# --- Logging Setup ---
logging.basicConfig(
level=logging.WARNING,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[
logging.FileHandler("system_health.log"),
logging.StreamHandler(),
],
)
logger = logging.getLogger("health_monitor")
What does this code do?
logging.basicConfig() sets up the logging system with your chosen settings in one call.
- level=logging.WARNING tells the logger to only process messages at WARNING severity or above. It ignores lower-priority messages like debug or info.
- format controls what each log line looks like. %(asctime)s adds a timestamp, %(levelname)s adds the severity level, and %(message)s adds your actual alert text.
- handlers is a list of destinations. FileHandler("system_health.log") writes to the log file (in append mode by default). StreamHandler() prints to the console.
- logging.getLogger("health_monitor") creates a named logger you can call directly in your code.
Why use the logging module instead of simple file writes?
You could open a file and write to it with open(), but the logging module gives you timestamps, severity levels, and multiple output destinations for free. It is the standard approach in production Python applications.
- Save health_monitor.py.
You won't see a change yet. The next section wires the logger into your threshold checker.
Connect your threshold alerts to the logger
Right now, check_thresholds() only appends messages to a list. You need to call logger.warning() so each alert is also saved to the log file with a timestamp.
- In health_monitor.py, replace your entire check_thresholds function with this updated version:
# --- Threshold Checking ---
def check_thresholds(cpu, memory, disk):
alerts = []
if cpu > THRESHOLDS["cpu"]:
message = f"CPU usage is at {cpu}% (threshold: {THRESHOLDS['cpu']}%)"
logger.warning(message)
alerts.append(message)
if memory > THRESHOLDS["memory"]:
message = f"Memory usage is at {memory}% (threshold: {THRESHOLDS['memory']}%)"
logger.warning(message)
alerts.append(message)
if disk > THRESHOLDS["disk"]:
message = f"Disk usage is at {disk}% (threshold: {THRESHOLDS['disk']}%)"
logger.warning(message)
alerts.append(message)
return alerts
What changed here?
Each if block now has a logger.warning(message) call between creating the message and appending it to the list. This sends the alert to both the log file and the console via the two handlers you configured.
- In the same file, scroll to the if __name__ == "__main__": block at the bottom.
- Find these two lines:
for alert in alerts:
print(f" [!] {alert}")
- Delete those two lines. The logger now handles printing alerts to the console, so this manual print loop is no longer needed.
- Save health_monitor.py.
- Run the script in PyCharm's terminal by running:
python health_monitor.py
- After the script runs, check your project folder in PyCharm's file explorer on the left. You should see a new file called system_health.log.
- Double-click system_health.log to open it. If any of your thresholds were exceeded, you'll see timestamped WARNING entries. If all metrics are below thresholds, the file will be empty (only warnings get logged).
Don't see system_health.log?
- Make sure you saved the file before running the script. Unsaved changes won't take effect.
- Check that the logging.basicConfig() block appears BEFORE any function definitions. Python needs to configure logging before it tries to use it.
- Right-click your project folder in PyCharm and select Reload from Disk to refresh the file list.
Why isn't my system_health.log file appearing after I run the script?
Force a threshold alert for testing
If your system metrics are all healthy and the log file is empty, temporarily lower a threshold in the THRESHOLDS dictionary (e.g. set "cpu": 5.0) to trigger a warning. Run the script again and you'll see the entry in your log file. Remember to change the threshold back when you're done testing.
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
Here's the full health_monitor.py at this point:
import psutil
import logging
from datetime import datetime
# --- Configuration ---
THRESHOLDS = {
"cpu": 80.0,
"memory": 85.0,
"disk": 90.0,
}
# --- Logging Setup ---
logging.basicConfig(
level=logging.WARNING,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[
logging.FileHandler("system_health.log"),
logging.StreamHandler(),
],
)
logger = logging.getLogger("health_monitor")
# --- Metric Functions ---
def get_cpu_usage():
return psutil.cpu_percent(interval=1)
def get_memory_usage():
memory = psutil.virtual_memory()
return memory.percent
def get_disk_usage():
disk = psutil.disk_usage("C:\\")
return disk.percent
# --- Threshold Checking ---
def check_thresholds(cpu, memory, disk):
alerts = []
if cpu > THRESHOLDS["cpu"]:
message = f"CPU usage is at {cpu}% (threshold: {THRESHOLDS['cpu']}%)"
logger.warning(message)
alerts.append(message)
if memory > THRESHOLDS["memory"]:
message = f"Memory usage is at {memory}% (threshold: {THRESHOLDS['memory']}%)"
logger.warning(message)
alerts.append(message)
if disk > THRESHOLDS["disk"]:
message = f"Disk usage is at {disk}% (threshold: {THRESHOLDS['disk']}%)"
logger.warning(message)
alerts.append(message)
return alerts
# --- Health Report ---
def print_health_report(cpu, memory, disk):
print("\n" + "=" * 50)
print(f" SYSTEM HEALTH REPORT - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 50)
print(f" CPU Usage: {cpu}%")
print(f" Memory Usage: {memory}%")
print(f" Disk Usage: {disk}%")
print("=" * 50)
if __name__ == "__main__":
cpu = get_cpu_usage()
memory = get_memory_usage()
disk = get_disk_usage()
print_health_report(cpu, memory, disk)
alerts = check_thresholds(cpu, memory, disk)
Your alerts now persist to disk with timestamps. In the next step, you'll tie everything together into a clean run_health_check() function that produces a polished health report.
Tie It All Together
You have all the building blocks in place. Your script can read system metrics, check them against thresholds, and print a formatted report.
Right now, though, your if __name__ block runs everything as loose code. In this step, you will wrap that logic into a single run_health_check() function that ties the whole script together into one clean entry point.
In this step, get ready to:
- Combine all metric and reporting logic into a single run_health_check() function.
- Add a status message that tells you whether everything is healthy or alerts were triggered.
- Run the complete script and verify output appears in both the console and the log file.
Write the run_health_check() function
Encapsulating your logic in a named function makes the script reusable. Other scripts can import and call run_health_check() without running the whole file.
- In health_monitor.py, scroll to the bottom and find the existing if __name__ == "__main__": block:
if __name__ == "__main__":
cpu = get_cpu_usage()
memory = get_memory_usage()
disk = get_disk_usage()
print_health_report(cpu, memory, disk)
alerts = check_thresholds(cpu, memory, disk)
- Delete that entire block and replace it with the following code:
# --- Main Function ---
def run_health_check():
cpu = get_cpu_usage()
memory = get_memory_usage()
disk = get_disk_usage()
print_health_report(cpu, memory, disk)
alerts = check_thresholds(cpu, memory, disk)
if alerts:
print(f"\n [!] {len(alerts)} alert(s) triggered! Check system_health.log for details.")
else:
print("\n [OK] All systems healthy.")
print("")
if __name__ == "__main__":
run_health_check()
What does this code do?
The run_health_check() function pulls all the pieces together. It calls your three metric functions, passes the results to print_health_report(), and then runs check_thresholds() to see if anything needs attention.
The if alerts: conditional checks whether the list returned by check_thresholds() has any entries. An empty list evaluates to False in Python, so you get a clean binary outcome.
The if __name__ == "__main__": guard means the function only runs when you execute the file directly. If another script imports this module, it will not trigger a health check automatically.
- Save health_monitor.py.
Seeing a syntax error?
Make sure you deleted the old if __name__ block completely before pasting the new code. Leftover lines from the previous version will cause indentation or duplicate-definition errors.
Also check that the if alerts: line is indented inside run_health_check(), not at the top level.
help me fix an indentation or syntax error in my run_health_check function
Run your health monitor
Time to see your complete monitor in action. When you run the script, it will pause for one second while measuring CPU, then print the full report.
- Run your script in the PyCharm terminal by entering this command:
python health_monitor.py
You should see a bordered health report showing your current CPU, memory, and disk percentages. Below the report, you will see either [OK] All systems healthy. or a message telling you how many alerts fired.
What about the log file?
If any of your metrics exceeded the thresholds, the warning also appeared in your console output as a separate line from the logging module. That same line was written to system_health.log in your project folder.
Open system_health.log in PyCharm to confirm the timestamped entries are there. If all your metrics are below thresholds, the file will be empty or may not exist yet.
Script runs but no log file appears?
This is expected if none of your thresholds were exceeded. The logging module only writes when a logger.warning() call fires.
To force a log entry for testing, temporarily lower a threshold in your THRESHOLDS dictionary (e.g., set "cpu" to 1.0), run the script again, then reset it back to 80.0.
help me troubleshoot why my system_health.log file is not appearing
✔️ Awesome, I've got everything!
Great. Double check you have saved health_monitor.py and confirmed the script runs without errors.
ⓧ I'd like to double check the full code
Here is the complete health_monitor.py file at this point:
import psutil
import logging
from datetime import datetime
# --- Configuration ---
THRESHOLDS = {
"cpu": 80.0,
"memory": 85.0,
"disk": 90.0,
}
# --- Logging Setup ---
logging.basicConfig(
level=logging.WARNING,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[
logging.FileHandler("system_health.log"),
logging.StreamHandler(),
],
)
logger = logging.getLogger("health_monitor")
# --- Metric Functions ---
def get_cpu_usage():
return psutil.cpu_percent(interval=1)
def get_memory_usage():
memory = psutil.virtual_memory()
return memory.percent
def get_disk_usage():
disk = psutil.disk_usage("C:\\")
return disk.percent
# --- Threshold Checking ---
def check_thresholds(cpu, memory, disk):
alerts = []
if cpu > THRESHOLDS["cpu"]:
message = f"CPU usage is at {cpu}% (threshold: {THRESHOLDS['cpu']}%)"
logger.warning(message)
alerts.append(message)
if memory > THRESHOLDS["memory"]:
message = f"Memory usage is at {memory}% (threshold: {THRESHOLDS['memory']}%)"
logger.warning(message)
alerts.append(message)
if disk > THRESHOLDS["disk"]:
message = f"Disk usage is at {disk}% (threshold: {THRESHOLDS['disk']}%)"
logger.warning(message)
alerts.append(message)
return alerts
# --- Health Report ---
def print_health_report(cpu, memory, disk):
print("\n" + "=" * 50)
print(f" SYSTEM HEALTH REPORT - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 50)
print(f" CPU Usage: {cpu}%")
print(f" Memory Usage: {memory}%")
print(f" Disk Usage: {disk}%")
print("=" * 50)
# --- Main Function ---
def run_health_check():
cpu = get_cpu_usage()
memory = get_memory_usage()
disk = get_disk_usage()
print_health_report(cpu, memory, disk)
alerts = check_thresholds(cpu, memory, disk)
if alerts:
print(f"\n [!] {len(alerts)} alert(s) triggered! Check system_health.log for details.")
else:
print("\n [OK] All systems healthy.")
print("")
if __name__ == "__main__":
run_health_check()
Your health monitor is fully functional. Next up, you will take it even further in the Secret Mission by making it run continuously and generate a summary report.
Secret mission
Continuous Monitoring with Summary Report
Your health monitor runs once and exits. What if you could keep it running in the background, watching your system continuously and building up a picture of how your machine performs over time? In this secret mission, you'll add a monitoring loop with a session summary report.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally, so there are no ongoing costs. Decide whether to keep your files for future use or delete them entirely.
Resources you used:
- Project folder containing health_monitor.py and system_health.log.
- The psutil Python package installed via pip.
Keep everything running
No action needed. Choose this if you plan to keep using or extending your health monitor script.
- Your health_monitor.py script stays in your project folder, ready to run anytime.
- The system_health.log file will continue to accumulate alerts each time you run the script.
- The psutil package remains installed in your Python environment.
Pause - I'll come back to this later
Since the script only runs when you execute it manually, there is nothing actively running to pause. Your files will stay on disk until you return.
- If the continuous monitor is still running in PyCharm's terminal, press Ctrl+C to stop it.
- Close PyCharm when you are done. Your project files remain saved on disk.
Delete - I don't want to use this again
Remove all project files and the installed package to start fresh.
- If the script is still running, press Ctrl+C in the terminal to stop it.
- Uninstall the psutil package by running this command in PyCharm's terminal:
pip uninstall psutil
- When prompted, type y and press Enter to confirm the uninstall.
- Delete the project folder. Open File Explorer, navigate to the folder containing your project, right-click the project folder, and select Delete.
- This removes both health_monitor.py and system_health.log.
That's a Wrap!
That's a Wrap!
Nice work! You just built a fully functional system health monitor in Python that reads live metrics from your Windows machine, checks them against configurable thresholds, and logs timestamped alerts to a file.
You've learned how to:
- Built a Python script that reads real-time CPU, memory, and disk metrics from your Windows machine using psutil.
- Created a configurable threshold system using dictionaries and conditional logic that triggers warnings when resources run hot.
- Implemented Python's logging module to write timestamped alerts to both a log file and the console.
- Secret Mission: Added continuous monitoring with a loop and a session summary report with graceful shutdown handling.
Ready to quiz yourself?