使用Python+psutil開發(fā)一個(gè)簡(jiǎn)易系統(tǒng)監(jiān)控工具
引言
在運(yùn)維自動(dòng)化、服務(wù)器巡檢、故障排查和資源告警場(chǎng)景中,經(jīng)常需要快速獲取機(jī)器的 CPU、內(nèi)存、磁盤和進(jìn)程狀態(tài)。
如果只依賴系統(tǒng)命令,例如 Linux 下的 top、free、df,或者 Windows 下的任務(wù)管理器,自動(dòng)化能力會(huì)比較弱。Python 的 psutil 庫(kù)正好解決了這個(gè)問(wèn)題:它可以用統(tǒng)一的 Python API 獲取跨平臺(tái)系統(tǒng)信息,非常適合用來(lái)開發(fā)輕量級(jí)系統(tǒng)監(jiān)控腳本。
本文會(huì)從 psutil 基礎(chǔ)用法開始,逐步實(shí)現(xiàn)一個(gè)可以實(shí)時(shí)刷新的簡(jiǎn)易系統(tǒng)監(jiān)控工具。
一、psutil 庫(kù)介紹
psutil 是 Python 中常用的系統(tǒng)和進(jìn)程監(jiān)控庫(kù),全稱可以理解為 process and system utilities。
它可以獲?。?/p>
- CPU 使用率、CPU 核心數(shù)、負(fù)載信息
- 內(nèi)存總量、已用內(nèi)存、可用內(nèi)存、使用率
- 磁盤分區(qū)、磁盤容量、磁盤使用率
- 網(wǎng)絡(luò)連接、網(wǎng)卡收發(fā)數(shù)據(jù)
- 當(dāng)前運(yùn)行的進(jìn)程列表、進(jìn)程 PID、進(jìn)程名稱、CPU 占用、內(nèi)存占用
在運(yùn)維自動(dòng)化方向,psutil 常見用途包括:
- 編寫服務(wù)器巡檢腳本
- 定時(shí)采集系統(tǒng)資源指標(biāo)
- 判斷服務(wù)進(jìn)程是否存活
- 查找高 CPU 或高內(nèi)存進(jìn)程
- 結(jié)合日志、郵件、企業(yè)微信或釘釘實(shí)現(xiàn)告警
- 作為監(jiān)控 Agent 的基礎(chǔ)模塊
安裝方式很簡(jiǎn)單:
pip install psutil
驗(yàn)證安裝:
import psutil print(psutil.cpu_count())
如果能夠輸出 CPU 核心數(shù)量,說(shuō)明安裝成功。
二、獲取 CPU 使用率
CPU 是系統(tǒng)監(jiān)控中最核心的指標(biāo)之一。使用 psutil.cpu_percent() 可以獲取 CPU 使用率。
import psutil
cpu_percent = psutil.cpu_percent(interval=1)
print(f"CPU 使用率:{cpu_percent}%")
這里的 interval=1 表示統(tǒng)計(jì) 1 秒內(nèi)的 CPU 使用情況。
也可以獲取每個(gè) CPU 核心的使用率:
import psutil
cpu_per_core = psutil.cpu_percent(interval=1, percpu=True)
for index, percent in enumerate(cpu_per_core, start=1):
print(f"CPU 核心 {index}:{percent}%")
獲取 CPU 核心數(shù):
import psutil
logical_count = psutil.cpu_count(logical=True)
physical_count = psutil.cpu_count(logical=False)
print(f"邏輯核心數(shù):{logical_count}")
print(f"物理核心數(shù):{physical_count}")
在實(shí)際運(yùn)維場(chǎng)景中,通常會(huì)重點(diǎn)關(guān)注整體 CPU 使用率。如果 CPU 長(zhǎng)時(shí)間超過(guò) 80% 或 90%,就需要進(jìn)一步排查是否存在異常進(jìn)程、流量突增、死循環(huán)任務(wù)或定時(shí)任務(wù)集中運(yùn)行等問(wèn)題。
三、獲取內(nèi)存使用情況
內(nèi)存監(jiān)控可以使用 psutil.virtual_memory()。
import psutil
memory = psutil.virtual_memory()
print(f"內(nèi)存總量:{memory.total}")
print(f"已用內(nèi)存:{memory.used}")
print(f"可用內(nèi)存:{memory.available}")
print(f"內(nèi)存使用率:{memory.percent}%")
直接輸出字節(jié)數(shù)不太方便閱讀,可以封裝一個(gè)單位轉(zhuǎn)換函數(shù):
def format_bytes(size):
for unit in ["B", "KB", "MB", "GB", "TB"]:
if size < 1024:
return f"{size:.2f} {unit}"
size /= 1024
return f"{size:.2f} PB"
結(jié)合起來(lái):
import psutil
def format_bytes(size):
for unit in ["B", "KB", "MB", "GB", "TB"]:
if size < 1024:
return f"{size:.2f} {unit}"
size /= 1024
return f"{size:.2f} PB"
memory = psutil.virtual_memory()
print(f"內(nèi)存總量:{format_bytes(memory.total)}")
print(f"已用內(nèi)存:{format_bytes(memory.used)}")
print(f"可用內(nèi)存:{format_bytes(memory.available)}")
print(f"內(nèi)存使用率:{memory.percent}%")
對(duì)服務(wù)器來(lái)說(shuō),內(nèi)存不足可能導(dǎo)致服務(wù)響應(yīng)變慢、進(jìn)程被系統(tǒng)終止、緩存命中率下降。運(yùn)維腳本中一般會(huì)把內(nèi)存使用率作為告警條件之一。
四、獲取磁盤空間
磁盤空間可以通過(guò) psutil.disk_usage() 獲取。
import psutil
disk = psutil.disk_usage("/")
print(f"磁盤總量:{disk.total}")
print(f"已用空間:{disk.used}")
print(f"剩余空間:{disk.free}")
print(f"磁盤使用率:{disk.percent}%")
如果希望查看所有磁盤分區(qū),可以使用 psutil.disk_partitions():
import psutil
def format_bytes(size):
for unit in ["B", "KB", "MB", "GB", "TB"]:
if size < 1024:
return f"{size:.2f} {unit}"
size /= 1024
return f"{size:.2f} PB"
partitions = psutil.disk_partitions()
for partition in partitions:
try:
usage = psutil.disk_usage(partition.mountpoint)
except PermissionError:
continue
print(f"設(shè)備:{partition.device}")
print(f"掛載點(diǎn):{partition.mountpoint}")
print(f"文件系統(tǒng):{partition.fstype}")
print(f"總空間:{format_bytes(usage.total)}")
print(f"已用空間:{format_bytes(usage.used)}")
print(f"剩余空間:{format_bytes(usage.free)}")
print(f"使用率:{usage.percent}%")
print("-" * 40)
磁盤監(jiān)控非常重要。日志目錄、數(shù)據(jù)庫(kù)目錄、上傳文件目錄如果沒有清理策略,很容易出現(xiàn)磁盤被寫滿的問(wèn)題。一旦磁盤滿了,常見后果包括服務(wù)無(wú)法寫日志、數(shù)據(jù)庫(kù)寫入失敗、容器啟動(dòng)失敗等。
五、獲取進(jìn)程信息
psutil 也可以獲取系統(tǒng)中的進(jìn)程信息。常用方法是 psutil.process_iter()。
import psutil
for process in psutil.process_iter(["pid", "name", "cpu_percent", "memory_percent"]):
info = process.info
print(
f"PID={info['pid']}, "
f"名稱={info['name']}, "
f"CPU={info['cpu_percent']}%, "
f"內(nèi)存={info['memory_percent']:.2f}%"
)
在遍歷進(jìn)程時(shí),可能遇到權(quán)限不足或進(jìn)程已經(jīng)退出的問(wèn)題,所以正式腳本中通常要捕獲異常:
import psutil
for process in psutil.process_iter(["pid", "name", "cpu_percent", "memory_percent"]):
try:
info = process.info
print(info)
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
如果要找出 CPU 占用較高的進(jìn)程,可以排序:
import psutil
import time
# 第一次調(diào)用用于初始化 CPU 統(tǒng)計(jì)
for process in psutil.process_iter():
try:
process.cpu_percent(interval=None)
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
time.sleep(1)
processes = []
for process in psutil.process_iter(["pid", "name", "cpu_percent", "memory_percent"]):
try:
processes.append(process.info)
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
top_processes = sorted(processes, key=lambda item: item["cpu_percent"], reverse=True)[:5]
for item in top_processes:
print(
f"PID={item['pid']}, "
f"名稱={item['name']}, "
f"CPU={item['cpu_percent']}%, "
f"內(nèi)存={item['memory_percent']:.2f}%"
)
這個(gè)功能在排查服務(wù)器負(fù)載過(guò)高時(shí)非常有用。可以快速定位是哪個(gè) Python 程序、Java 服務(wù)、數(shù)據(jù)庫(kù)進(jìn)程或其他后臺(tái)任務(wù)消耗了大量資源。
六、實(shí)時(shí)刷新系統(tǒng)狀態(tài)
系統(tǒng)監(jiān)控工具通常不是只執(zhí)行一次,而是每隔幾秒刷新一次狀態(tài)。
基本思路如下:
- 清空終端屏幕
- 獲取 CPU、內(nèi)存、磁盤、進(jìn)程信息
- 格式化輸出
- 休眠指定秒數(shù)
- 循環(huán)執(zhí)行
清屏函數(shù)可以兼容 Windows、Linux 和 macOS:
import os
def clear_screen():
os.system("cls" if os.name == "nt" else "clear")
循環(huán)刷新:
import time
while True:
clear_screen()
print("系統(tǒng)狀態(tài)刷新中...")
time.sleep(2)
為了方便停止程序,可以捕獲 KeyboardInterrupt。用戶按 Ctrl + C 時(shí),腳本可以優(yōu)雅退出。
try:
while True:
clear_screen()
print("系統(tǒng)狀態(tài)刷新中...")
time.sleep(2)
except KeyboardInterrupt:
print("監(jiān)控已停止")
七、制作一個(gè)簡(jiǎn)易系統(tǒng)監(jiān)控腳本
下面實(shí)現(xiàn)一個(gè)完整腳本,功能包括:
- 顯示當(dāng)前時(shí)間
- 顯示 CPU 核心數(shù)和 CPU 使用率
- 顯示內(nèi)存總量、可用內(nèi)存、內(nèi)存使用率
- 顯示所有磁盤分區(qū)空間
- 顯示 CPU 占用最高的前 5 個(gè)進(jìn)程
- 每 2 秒自動(dòng)刷新
- 支持
Ctrl + C停止
這個(gè)腳本適合用于入門級(jí)服務(wù)器巡檢,也可以繼續(xù)擴(kuò)展為告警工具。
八、完整代碼
文件名可以保存為 system_monitor.py。
import os
import time
from datetime import datetime
import psutil
REFRESH_INTERVAL = 2
TOP_PROCESS_LIMIT = 5
def format_bytes(size):
"""Convert bytes to a human-readable string."""
for unit in ["B", "KB", "MB", "GB", "TB"]:
if size < 1024:
return f"{size:.2f} {unit}"
size /= 1024
return f"{size:.2f} PB"
def clear_screen():
os.system("cls" if os.name == "nt" else "clear")
def get_cpu_info():
return {
"logical_count": psutil.cpu_count(logical=True),
"physical_count": psutil.cpu_count(logical=False),
"percent": psutil.cpu_percent(interval=1),
"per_core": psutil.cpu_percent(interval=None, percpu=True),
}
def get_memory_info():
memory = psutil.virtual_memory()
return {
"total": memory.total,
"available": memory.available,
"used": memory.used,
"percent": memory.percent,
}
def get_disk_info():
disks = []
for partition in psutil.disk_partitions():
try:
usage = psutil.disk_usage(partition.mountpoint)
except (PermissionError, FileNotFoundError):
continue
disks.append(
{
"device": partition.device,
"mountpoint": partition.mountpoint,
"fstype": partition.fstype,
"total": usage.total,
"used": usage.used,
"free": usage.free,
"percent": usage.percent,
}
)
return disks
def init_process_cpu_percent():
for process in psutil.process_iter():
try:
process.cpu_percent(interval=None)
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
def get_top_processes(limit=5):
processes = []
for process in psutil.process_iter(["pid", "name", "cpu_percent", "memory_percent"]):
try:
info = process.info
processes.append(
{
"pid": info["pid"],
"name": info["name"] or "",
"cpu_percent": info["cpu_percent"] or 0.0,
"memory_percent": info["memory_percent"] or 0.0,
}
)
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
continue
return sorted(processes, key=lambda item: item["cpu_percent"], reverse=True)[:limit]
def print_separator():
print("-" * 80)
def print_system_status():
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
cpu = get_cpu_info()
memory = get_memory_info()
disks = get_disk_info()
top_processes = get_top_processes(TOP_PROCESS_LIMIT)
print(f"Python psutil 系統(tǒng)監(jiān)控工具")
print(f"刷新時(shí)間:{now}")
print_separator()
print("CPU 信息")
print(f"物理核心數(shù):{cpu['physical_count']}")
print(f"邏輯核心數(shù):{cpu['logical_count']}")
print(f"CPU 總使用率:{cpu['percent']}%")
print(f"各核心使用率:{', '.join(str(item) + '%' for item in cpu['per_core'])}")
print_separator()
print("內(nèi)存信息")
print(f"內(nèi)存總量:{format_bytes(memory['total'])}")
print(f"已用內(nèi)存:{format_bytes(memory['used'])}")
print(f"可用內(nèi)存:{format_bytes(memory['available'])}")
print(f"內(nèi)存使用率:{memory['percent']}%")
print_separator()
print("磁盤信息")
for disk in disks:
print(
f"{disk['device']} "
f"掛載點(diǎn)={disk['mountpoint']} "
f"文件系統(tǒng)={disk['fstype']} "
f"總量={format_bytes(disk['total'])} "
f"已用={format_bytes(disk['used'])} "
f"剩余={format_bytes(disk['free'])} "
f"使用率={disk['percent']}%"
)
print_separator()
print(f"CPU 占用最高的前 {TOP_PROCESS_LIMIT} 個(gè)進(jìn)程")
print(f"{'PID':<10}{'CPU%':<10}{'MEM%':<10}進(jìn)程名稱")
for process in top_processes:
print(
f"{process['pid']:<10}"
f"{process['cpu_percent']:<10.1f}"
f"{process['memory_percent']:<10.2f}"
f"{process['name']}"
)
print_separator()
print(f"每 {REFRESH_INTERVAL} 秒刷新一次,按 Ctrl + C 停止監(jiān)控")
def main():
init_process_cpu_percent()
try:
while True:
clear_screen()
print_system_status()
time.sleep(REFRESH_INTERVAL)
except KeyboardInterrupt:
print("\n監(jiān)控已停止")
if __name__ == "__main__":
main()
運(yùn)行腳本:
python system_monitor.py
如果是在 Linux 服務(wù)器上,也可以使用:
python3 system_monitor.py
運(yùn)行后,終端會(huì)每隔 2 秒刷新一次系統(tǒng)狀態(tài)。
九、腳本擴(kuò)展方向
這個(gè)腳本只是一個(gè)基礎(chǔ)版本,后續(xù)可以繼續(xù)擴(kuò)展:
- 增加 CPU、內(nèi)存、磁盤閾值判斷
- 超過(guò)閾值后發(fā)送郵件、釘釘或企業(yè)微信告警
- 將監(jiān)控?cái)?shù)據(jù)寫入 CSV、SQLite、MySQL 或 InfluxDB
- 增加網(wǎng)絡(luò)流量監(jiān)控
- 增加指定進(jìn)程存活檢測(cè)
- 使用
argparse支持命令行參數(shù),例如刷新間隔、進(jìn)程數(shù)量、告警閾值 - 配合
schedule、cron或 Windows 任務(wù)計(jì)劃程序?qū)崿F(xiàn)定時(shí)巡檢 - 封裝成 Flask/FastAPI 接口,做成 Web 監(jiān)控面板
例如,增加一個(gè)簡(jiǎn)單的內(nèi)存告警判斷:
import psutil
memory = psutil.virtual_memory()
if memory.percent >= 80:
print(f"警告:當(dāng)前內(nèi)存使用率過(guò)高,已達(dá)到 {memory.percent}%")
再比如,檢查某個(gè)關(guān)鍵進(jìn)程是否存在:
import psutil
target_process = "nginx"
exists = False
for process in psutil.process_iter(["name"]):
try:
if target_process.lower() in (process.info["name"] or "").lower():
exists = True
break
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
if not exists:
print(f"警告:進(jìn)程 {target_process} 未運(yùn)行")
十、總結(jié)
psutil 是 Python 運(yùn)維自動(dòng)化中非常實(shí)用的系統(tǒng)監(jiān)控庫(kù)。它屏蔽了不同操作系統(tǒng)之間的差異,讓我們可以用統(tǒng)一的 Python 代碼獲取 CPU、內(nèi)存、磁盤和進(jìn)程信息。
本文完成了一個(gè)簡(jiǎn)易系統(tǒng)監(jiān)控工具,核心能力包括:
- 使用
psutil.cpu_percent()獲取 CPU 使用率 - 使用
psutil.virtual_memory()獲取內(nèi)存狀態(tài) - 使用
psutil.disk_usage()和psutil.disk_partitions()獲取磁盤空間 - 使用
psutil.process_iter()獲取進(jìn)程信息 - 使用循環(huán)和清屏實(shí)現(xiàn)實(shí)時(shí)刷新
- 整合為一個(gè)完整可運(yùn)行的系統(tǒng)監(jiān)控腳本
對(duì)于 Python 運(yùn)維自動(dòng)化學(xué)習(xí)者來(lái)說(shuō),這類腳本非常適合作為練手項(xiàng)目。它既能幫助理解系統(tǒng)資源指標(biāo),也能為后續(xù)開發(fā)巡檢工具、告警工具和監(jiān)控 Agent 打下基礎(chǔ)。
以上就是使用Python+psutil開發(fā)一個(gè)簡(jiǎn)易系統(tǒng)監(jiān)控工具的詳細(xì)內(nèi)容,更多關(guān)于Python psutil系統(tǒng)監(jiān)控工具的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python中使用PyExecJS庫(kù)執(zhí)行JavaScript函數(shù)
Python在運(yùn)行JavaScript函數(shù)時(shí),需要用到外部庫(kù)來(lái)執(zhí)行JavaScript,本文主要介紹了Python中使用PyExecJS庫(kù)執(zhí)行JavaScript函數(shù),具有一定的參考價(jià)值,感興趣的可以了解一下2024-04-04
python判斷一個(gè)數(shù)是否能被另一個(gè)整數(shù)整除的實(shí)例
今天小編就為大家分享一篇python判斷一個(gè)數(shù)是否能被另一個(gè)整數(shù)整除的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
pycharm如何實(shí)現(xiàn)跨目錄調(diào)用文件
這篇文章主要介紹了pycharm如何實(shí)現(xiàn)跨目錄調(diào)用文件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
python識(shí)別圖標(biāo)并點(diǎn)擊功能實(shí)現(xiàn)
這篇文章主要介紹了python識(shí)別圖標(biāo)并點(diǎn)擊功能實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-07-07
使用Flask-Cache緩存實(shí)現(xiàn)給Flask提速的方法詳解
這篇文章主要介紹了使用Flask-Cache緩存實(shí)現(xiàn)給Flask提速的方法,結(jié)合實(shí)例形式詳細(xì)分析了Flask-Cache的安裝、配置及緩存使用相關(guān)操作技巧,需要的朋友可以參考下2019-06-06
使用OpenCV實(shí)現(xiàn)鼠標(biāo)事件回調(diào)功能并繪制圖形
這篇文章主要為大家詳細(xì)介紹了如何使用OpenCV實(shí)現(xiàn)鼠標(biāo)事件回調(diào)功能,并通過(guò)鼠標(biāo)操作在圖像上繪制圓圈和矩形,感興趣的小伙伴可以了解下2024-11-11
Python庫(kù)Gym開發(fā)和比較強(qiáng)化學(xué)習(xí)算法使用探究
這篇文章主要介紹了Python庫(kù)Gym開發(fā)和比較強(qiáng)化學(xué)習(xí)算法使用探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
Python中號(hào)稱神仙的六個(gè)內(nèi)置函數(shù)詳解
這篇文章主要介紹了Python中號(hào)稱神仙的六個(gè)內(nèi)置函數(shù),今天分享的這6個(gè)內(nèi)置函數(shù),在使用?Python?進(jìn)行數(shù)據(jù)分析或者其他復(fù)雜的自動(dòng)化任務(wù)時(shí)非常方便,需要的朋友可以參考下2022-05-05
Python實(shí)現(xiàn) 版本號(hào)對(duì)比功能的實(shí)例代碼
這篇文章主要介紹了 Python實(shí)現(xiàn) 版本號(hào)對(duì)比功能的實(shí)例代碼,文末給大家補(bǔ)充介紹了python 比較兩個(gè)版本號(hào)大小 ,需要的朋友可以參考下2019-04-04

