Python實(shí)現(xiàn)監(jiān)控系統(tǒng)資源的腳本工具
簡(jiǎn)介
系統(tǒng)資源監(jiān)控是系統(tǒng)管理員和開發(fā)人員日常工作中的重要任務(wù)。通過(guò)實(shí)時(shí)監(jiān)控CPU、內(nèi)存、磁盤和網(wǎng)絡(luò)等關(guān)鍵資源的使用情況,我們可以及時(shí)發(fā)現(xiàn)系統(tǒng)性能瓶頸、預(yù)防系統(tǒng)故障并優(yōu)化資源配置。本文將介紹一個(gè)實(shí)用的Python腳本——系統(tǒng)資源監(jiān)控工具,它可以實(shí)時(shí)顯示系統(tǒng)的各項(xiàng)關(guān)鍵指標(biāo),并支持歷史數(shù)據(jù)記錄和告警功能。
功能介紹
這個(gè)系統(tǒng)資源監(jiān)控工具具有以下核心功能:
- 實(shí)時(shí)監(jiān)控:實(shí)時(shí)顯示CPU、內(nèi)存、磁盤和網(wǎng)絡(luò)使用情況
- 多維度監(jiān)控:監(jiān)控CPU使用率、內(nèi)存占用、磁盤IO、網(wǎng)絡(luò)流量等多個(gè)維度
- 歷史數(shù)據(jù)記錄:將監(jiān)控?cái)?shù)據(jù)保存到CSV文件,便于后續(xù)分析
- 可視化圖表:生成資源使用趨勢(shì)圖,直觀展示系統(tǒng)性能變化
- 閾值告警:當(dāng)資源使用超過(guò)設(shè)定閾值時(shí)發(fā)出告警
- 定時(shí)監(jiān)控:支持按指定間隔持續(xù)監(jiān)控系統(tǒng)資源
- 跨平臺(tái)支持:支持Windows、Linux和macOS操作系統(tǒng)
- 輕量級(jí)設(shè)計(jì):占用系統(tǒng)資源極少,不影響被監(jiān)控系統(tǒng)的正常運(yùn)行
應(yīng)用場(chǎng)景
這個(gè)工具適用于以下場(chǎng)景:
- 服務(wù)器監(jiān)控:監(jiān)控生產(chǎn)服務(wù)器的資源使用情況
- 性能調(diào)優(yōu):分析應(yīng)用程序運(yùn)行時(shí)的資源消耗
- 故障排查:定位系統(tǒng)性能問(wèn)題的根本原因
- 容量規(guī)劃:根據(jù)歷史數(shù)據(jù)預(yù)測(cè)系統(tǒng)資源需求
- 開發(fā)測(cè)試:在開發(fā)和測(cè)試階段監(jiān)控應(yīng)用程序性能
- 系統(tǒng)維護(hù):定期檢查系統(tǒng)健康狀況
報(bào)錯(cuò)處理
腳本包含了完善的錯(cuò)誤處理機(jī)制:
- 權(quán)限檢測(cè):檢測(cè)是否具有足夠的權(quán)限訪問(wèn)系統(tǒng)信息
- 依賴檢查:檢查必要的第三方庫(kù)是否已安裝
- 網(wǎng)絡(luò)異常處理:處理網(wǎng)絡(luò)監(jiān)控中的連接異常
- 文件操作保護(hù):安全地讀寫監(jiān)控?cái)?shù)據(jù)文件
- 資源限制處理:在資源受限環(huán)境下優(yōu)雅降級(jí)
- 異常捕獲:捕獲并處理運(yùn)行過(guò)程中可能出現(xiàn)的各種異常
代碼實(shí)現(xiàn)
import psutil
import time
import csv
import argparse
import os
from datetime import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from collections import deque
import threading
import sys
class SystemResourceMonitor:
def __init__(self, interval=1, history_size=100):
self.interval = interval
self.history_size = history_size
self.monitoring = False
self.data_history = deque(maxlen=history_size)
# 初始化歷史數(shù)據(jù)存儲(chǔ)
self.timestamps = deque(maxlen=history_size)
self.cpu_percentages = deque(maxlen=history_size)
self.memory_percentages = deque(maxlen=history_size)
self.disk_usages = deque(maxlen=history_size)
self.network_bytes_sent = deque(maxlen=history_size)
self.network_bytes_recv = deque(maxlen=history_size)
# 網(wǎng)絡(luò)流量基準(zhǔn)值
self.net_io_baseline = psutil.net_io_counters()
def get_cpu_info(self):
"""獲取CPU信息"""
try:
cpu_percent = psutil.cpu_percent(interval=1)
cpu_count = psutil.cpu_count()
cpu_freq = psutil.cpu_freq()
return {
'percent': cpu_percent,
'count': cpu_count,
'frequency': cpu_freq.current if cpu_freq else 0
}
except Exception as e:
return {'error': str(e)}
def get_memory_info(self):
"""獲取內(nèi)存信息"""
try:
memory = psutil.virtual_memory()
swap = psutil.swap_memory()
return {
'total': memory.total,
'available': memory.available,
'used': memory.used,
'percent': memory.percent,
'swap_total': swap.total,
'swap_used': swap.used,
'swap_percent': swap.percent
}
except Exception as e:
return {'error': str(e)}
def get_disk_info(self):
"""獲取磁盤信息"""
try:
disk = psutil.disk_usage('/')
disk_io = psutil.disk_io_counters()
return {
'total': disk.total,
'used': disk.used,
'free': disk.free,
'percent': disk.percent,
'read_bytes': disk_io.read_bytes if disk_io else 0,
'write_bytes': disk_io.write_bytes if disk_io else 0
}
except Exception as e:
return {'error': str(e)}
def get_network_info(self):
"""獲取網(wǎng)絡(luò)信息"""
try:
net_io = psutil.net_io_counters()
# 計(jì)算相對(duì)于基準(zhǔn)值的流量
bytes_sent = net_io.bytes_sent - self.net_io_baseline.bytes_sent
bytes_recv = net_io.bytes_recv - self.net_io_baseline.bytes_recv
return {
'bytes_sent': bytes_sent,
'bytes_recv': bytes_recv,
'packets_sent': net_io.packets_sent,
'packets_recv': net_io.packets_recv
}
except Exception as e:
return {'error': str(e)}
def format_bytes(self, bytes_value):
"""格式化字節(jié)單位"""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes_value < 1024.0:
return f"{bytes_value:.2f} {unit}"
bytes_value /= 1024.0
return f"{bytes_value:.2f} PB"
def display_system_info(self):
"""顯示系統(tǒng)信息"""
# 清屏(兼容不同操作系統(tǒng))
os.system('cls' if os.name == 'nt' else 'clear')
print("=" * 80)
print("系統(tǒng)資源監(jiān)控工具")
print("=" * 80)
print(f"監(jiān)控時(shí)間: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print()
# CPU信息
cpu_info = self.get_cpu_info()
if 'error' not in cpu_info:
print("CPU信息:")
print(f" 使用率: {cpu_info['percent']:.1f}%")
print(f" 核心數(shù): {cpu_info['count']}")
print(f" 頻率: {cpu_info['frequency']:.2f} MHz")
else:
print(f"CPU信息獲取失敗: {cpu_info['error']}")
print()
# 內(nèi)存信息
memory_info = self.get_memory_info()
if 'error' not in memory_info:
print("內(nèi)存信息:")
print(f" 總計(jì): {self.format_bytes(memory_info['total'])}")
print(f" 已用: {self.format_bytes(memory_info['used'])}")
print(f" 可用: {self.format_bytes(memory_info['available'])}")
print(f" 使用率: {memory_info['percent']:.1f}%")
if memory_info['swap_total'] > 0:
print(f" 交換分區(qū): {memory_info['swap_percent']:.1f}%")
else:
print(f"內(nèi)存信息獲取失敗: {memory_info['error']}")
print()
# 磁盤信息
disk_info = self.get_disk_info()
if 'error' not in disk_info:
print("磁盤信息:")
print(f" 總計(jì): {self.format_bytes(disk_info['total'])}")
print(f" 已用: {self.format_bytes(disk_info['used'])}")
print(f" 可用: {self.format_bytes(disk_info['free'])}")
print(f" 使用率: {disk_info['percent']:.1f}%")
else:
print(f"磁盤信息獲取失敗: {disk_info['error']}")
print()
# 網(wǎng)絡(luò)信息
network_info = self.get_network_info()
if 'error' not in network_info:
print("網(wǎng)絡(luò)信息:")
print(f" 發(fā)送: {self.format_bytes(network_info['bytes_sent'])}")
print(f" 接收: {self.format_bytes(network_info['bytes_recv'])}")
print(f" 發(fā)送包: {network_info['packets_sent']:,}")
print(f" 接收包: {network_info['packets_recv']:,}")
else:
print(f"網(wǎng)絡(luò)信息獲取失敗: {network_info['error']}")
print()
print("=" * 80)
print("按 Ctrl+C 停止監(jiān)控")
def collect_data(self):
"""收集監(jiān)控?cái)?shù)據(jù)"""
timestamp = datetime.now()
data = {
'timestamp': timestamp,
'cpu': self.get_cpu_info(),
'memory': self.get_memory_info(),
'disk': self.get_disk_info(),
'network': self.get_network_info()
}
# 添加到歷史記錄
self.data_history.append(data)
# 更新圖表數(shù)據(jù)
self.timestamps.append(timestamp)
if 'error' not in data['cpu']:
self.cpu_percentages.append(data['cpu']['percent'])
if 'error' not in data['memory']:
self.memory_percentages.append(data['memory']['percent'])
if 'error' not in data['disk']:
self.disk_usages.append(data['disk']['percent'])
return data
def save_to_csv(self, filename="system_monitor.csv"):
"""保存數(shù)據(jù)到CSV文件"""
try:
file_exists = os.path.exists(filename)
with open(filename, 'a', newline='', encoding='utf-8') as csvfile:
fieldnames = [
'timestamp', 'cpu_percent', 'memory_percent', 'disk_percent',
'network_sent', 'network_recv'
]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
# 如果是新文件,寫入表頭
if not file_exists:
writer.writeheader()
# 寫入最新數(shù)據(jù)
if self.data_history:
latest_data = self.data_history[-1]
row = {
'timestamp': latest_data['timestamp'].strftime('%Y-%m-%d %H:%M:%S'),
'cpu_percent': latest_data['cpu'].get('percent', 0) if 'error' not in latest_data['cpu'] else 0,
'memory_percent': latest_data['memory'].get('percent', 0) if 'error' not in latest_data['memory'] else 0,
'disk_percent': latest_data['disk'].get('percent', 0) if 'error' not in latest_data['disk'] else 0,
'network_sent': latest_data['network'].get('bytes_sent', 0) if 'error' not in latest_data['network'] else 0,
'network_recv': latest_data['network'].get('bytes_recv', 0) if 'error' not in latest_data['network'] else 0
}
writer.writerow(row)
return True
except Exception as e:
print(f"保存CSV文件時(shí)出錯(cuò): {e}")
return False
def generate_chart(self, filename="resource_usage.png"):
"""生成資源使用趨勢(shì)圖"""
try:
if len(self.timestamps) < 2:
print("數(shù)據(jù)不足,無(wú)法生成圖表")
return False
plt.figure(figsize=(12, 8))
# 創(chuàng)建子圖
ax1 = plt.subplot(2, 2, 1)
if self.cpu_percentages:
ax1.plot(self.timestamps, self.cpu_percentages, 'b-', label='CPU使用率')
ax1.set_title('CPU使用率')
ax1.set_ylabel('百分比 (%)')
ax1.legend()
ax1.grid(True)
ax2 = plt.subplot(2, 2, 2)
if self.memory_percentages:
ax2.plot(self.timestamps, self.memory_percentages, 'g-', label='內(nèi)存使用率')
ax2.set_title('內(nèi)存使用率')
ax2.set_ylabel('百分比 (%)')
ax2.legend()
ax2.grid(True)
ax3 = plt.subplot(2, 2, 3)
if self.disk_usages:
ax3.plot(self.timestamps, self.disk_usages, 'r-', label='磁盤使用率')
ax3.set_title('磁盤使用率')
ax3.set_ylabel('百分比 (%)')
ax3.set_xlabel('時(shí)間')
ax3.legend()
ax3.grid(True)
ax4 = plt.subplot(2, 2, 4)
if self.network_bytes_sent and self.network_bytes_recv:
ax4.plot(self.timestamps, [b/1024/1024 for b in self.network_bytes_sent], 'c-', label='發(fā)送(MB)')
ax4.plot(self.timestamps, [b/1024/1024 for b in self.network_bytes_recv], 'm-', label='接收(MB)')
ax4.set_title('網(wǎng)絡(luò)流量')
ax4.set_ylabel('流量 (MB)')
ax4.set_xlabel('時(shí)間')
ax4.legend()
ax4.grid(True)
# 格式化時(shí)間軸
for ax in [ax1, ax2, ax3, ax4]:
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))
ax.xaxis.set_major_locator(mdates.MinuteLocator(interval=5))
plt.setp(ax.xaxis.get_majorticklabels(), rotation=45)
plt.tight_layout()
plt.savefig(filename, dpi=300, bbox_inches='tight')
plt.close()
print(f"圖表已保存到: {filename}")
return True
except Exception as e:
print(f"生成圖表時(shí)出錯(cuò): {e}")
return False
def check_thresholds(self, thresholds):
"""檢查閾值并發(fā)出告警"""
if not self.data_history:
return
latest_data = self.data_history[-1]
# 檢查CPU閾值
if 'error' not in latest_data['cpu'] and thresholds.get('cpu'):
cpu_percent = latest_data['cpu']['percent']
if cpu_percent > thresholds['cpu']:
print(f"?? CPU使用率過(guò)高: {cpu_percent:.1f}% (閾值: {thresholds['cpu']}%)")
# 檢查內(nèi)存閾值
if 'error' not in latest_data['memory'] and thresholds.get('memory'):
memory_percent = latest_data['memory']['percent']
if memory_percent > thresholds['memory']:
print(f"?? 內(nèi)存使用率過(guò)高: {memory_percent:.1f}% (閾值: {thresholds['memory']}%)")
# 檢查磁盤閾值
if 'error' not in latest_data['disk'] and thresholds.get('disk'):
disk_percent = latest_data['disk']['percent']
if disk_percent > thresholds['disk']:
print(f"?? 磁盤使用率過(guò)高: {disk_percent:.1f}% (閾值: {thresholds['disk']}%)")
def start_monitoring(self, duration=None, csv_file=None, chart_file=None, thresholds=None):
"""開始監(jiān)控"""
self.monitoring = True
start_time = time.time()
try:
while self.monitoring:
# 收集數(shù)據(jù)
self.collect_data()
# 顯示信息
self.display_system_info()
# 保存到CSV
if csv_file:
self.save_to_csv(csv_file)
# 檢查閾值
if thresholds:
self.check_thresholds(thresholds)
# 檢查是否達(dá)到指定時(shí)長(zhǎng)
if duration and (time.time() - start_time) >= duration:
break
# 等待下次監(jiān)控
time.sleep(self.interval)
except KeyboardInterrupt:
print("\n\n停止監(jiān)控...")
finally:
self.monitoring = False
# 生成圖表
if chart_file:
self.generate_chart(chart_file)
print("監(jiān)控已停止")
def main():
parser = argparse.ArgumentParser(description="系統(tǒng)資源監(jiān)控工具")
parser.add_argument("-i", "--interval", type=int, default=5,
help="監(jiān)控間隔(秒,默認(rèn):5)")
parser.add_argument("-d", "--duration", type=int,
help="監(jiān)控時(shí)長(zhǎng)(秒,不指定則持續(xù)監(jiān)控)")
parser.add_argument("-c", "--csv", help="保存數(shù)據(jù)到CSV文件")
parser.add_argument("-g", "--graph", help="生成圖表文件")
parser.add_argument("--cpu-threshold", type=float,
help="CPU使用率告警閾值(%)")
parser.add_argument("--memory-threshold", type=float,
help="內(nèi)存使用率告警閾值(%)")
parser.add_argument("--disk-threshold", type=float,
help="磁盤使用率告警閾值(%)")
args = parser.parse_args()
# 檢查依賴
try:
import psutil
except ImportError:
print("錯(cuò)誤: 缺少psutil庫(kù),請(qǐng)安裝: pip install psutil")
sys.exit(1)
if args.graph and not plt:
print("警告: 缺少matplotlib庫(kù),無(wú)法生成圖表")
args.graph = None
# 設(shè)置閾值
thresholds = {}
if args.cpu_threshold:
thresholds['cpu'] = args.cpu_threshold
if args.memory_threshold:
thresholds['memory'] = args.memory_threshold
if args.disk_threshold:
thresholds['disk'] = args.disk_threshold
try:
monitor = SystemResourceMonitor(interval=args.interval)
monitor.start_monitoring(
duration=args.duration,
csv_file=args.csv,
chart_file=args.graph,
thresholds=thresholds
)
except Exception as e:
print(f"程序執(zhí)行出錯(cuò): {e}")
sys.exit(1)
if __name__ == "__main__":
main()
使用方法
安裝依賴
在使用此腳本之前,需要安裝必要的庫(kù):
pip install psutil matplotlib
基本使用
# 基本用法,每5秒刷新一次 python system_monitor.py # 設(shè)置監(jiān)控間隔為10秒 python system_monitor.py -i 10 # 監(jiān)控60秒后自動(dòng)停止 python system_monitor.py -d 60 # 保存監(jiān)控?cái)?shù)據(jù)到CSV文件 python system_monitor.py -c monitor_data.csv # 生成資源使用趨勢(shì)圖 python system_monitor.py -g resource_trend.png # 設(shè)置告警閾值 python system_monitor.py --cpu-threshold 80 --memory-threshold 85 --disk-threshold 90
命令行參數(shù)說(shuō)明
-i, --interval: 監(jiān)控間隔(秒),默認(rèn)5秒-d, --duration: 監(jiān)控時(shí)長(zhǎng)(秒),不指定則持續(xù)監(jiān)控-c, --csv: 保存數(shù)據(jù)到指定的CSV文件-g, --graph: 生成資源使用趨勢(shì)圖到指定文件--cpu-threshold: CPU使用率告警閾值(%)--memory-threshold: 內(nèi)存使用率告警閾值(%)--disk-threshold: 磁盤使用率告警閾值(%)
使用示例
持續(xù)監(jiān)控系統(tǒng)資源:
python system_monitor.py
監(jiān)控并保存數(shù)據(jù):
python system_monitor.py -i 10 -d 300 -c system_data.csv -g trend.png
帶告警的監(jiān)控:
python system_monitor.py --cpu-threshold 80 --memory-threshold 85
總結(jié)
這個(gè)系統(tǒng)資源監(jiān)控工具提供了一個(gè)全面的系統(tǒng)監(jiān)控解決方案,能夠?qū)崟r(shí)顯示CPU、內(nèi)存、磁盤和網(wǎng)絡(luò)等關(guān)鍵資源的使用情況。它支持?jǐn)?shù)據(jù)持久化、可視化圖表生成和閾值告警等功能,適用于服務(wù)器監(jiān)控、性能調(diào)優(yōu)和故障排查等多種場(chǎng)景。通過(guò)這個(gè)工具,用戶可以更好地了解系統(tǒng)運(yùn)行狀態(tài),及時(shí)發(fā)現(xiàn)和解決性能問(wèn)題,確保系統(tǒng)的穩(wěn)定運(yùn)行。
以上就是Python實(shí)現(xiàn)監(jiān)控系統(tǒng)資源的腳本工具的詳細(xì)內(nèi)容,更多關(guān)于Python監(jiān)控系統(tǒng)資源的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
如何使用Python對(duì)日期和時(shí)間進(jìn)行排序
本文將教我們?nèi)绾问褂肞ython對(duì)日期和時(shí)間進(jìn)行排序,我們還將學(xué)習(xí)datetime模塊和sorted方法,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2023-06-06
python pygame模塊編寫飛機(jī)大戰(zhàn)
這篇文章主要為大家詳細(xì)介紹了python pygame模塊編寫飛機(jī)大戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11
Python實(shí)現(xiàn)視頻自動(dòng)打碼的示例代碼
我們?cè)谟^看視頻的時(shí)候,有時(shí)候會(huì)出現(xiàn)一些奇怪的馬賽克,影響我們的觀影體驗(yàn),那么這些馬賽克是如何精確的加上去的呢?本文就來(lái)為大家詳細(xì)講講2022-04-04
Python將運(yùn)行結(jié)果導(dǎo)出為CSV格式的兩種常用方法
這篇文章主要給大家介紹了關(guān)于Python將運(yùn)行結(jié)果導(dǎo)出為CSV格式的兩種常用方法,Python生成(導(dǎo)出)csv文件其實(shí)很簡(jiǎn)單,我們一般可以用csv模塊或者pandas庫(kù)來(lái)實(shí)現(xiàn),需要的朋友可以參考下2023-07-07
使用Termux在手機(jī)上運(yùn)行Python的詳細(xì)過(guò)程
這篇文章主要介紹了使用Termux在手機(jī)上運(yùn)行Python的詳細(xì)過(guò)程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-10-10
Python編寫春聯(lián)的示例代碼(支持行書隸書楷書)
這篇文章主要介紹了如何通過(guò)Python代碼編寫春聯(lián),其中春聯(lián)字體支持行書隸書楷書。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動(dòng)手試一試2022-01-01

