Python系統(tǒng)監(jiān)控之跨平臺檢查系統(tǒng)服務(wù)運(yùn)行狀態(tài)的完整指南
簡介
系統(tǒng)服務(wù)是操作系統(tǒng)和應(yīng)用程序正常運(yùn)行的基礎(chǔ)。無論是Web服務(wù)器、數(shù)據(jù)庫服務(wù)還是其他后臺進(jìn)程,服務(wù)的狀態(tài)直接影響系統(tǒng)的可用性和穩(wěn)定性。定期檢查關(guān)鍵服務(wù)的運(yùn)行狀態(tài),可以及時發(fā)現(xiàn)服務(wù)異常并采取相應(yīng)措施。本文將介紹一個實(shí)用的Python腳本——系統(tǒng)服務(wù)狀態(tài)檢查工具,它可以跨平臺檢查系統(tǒng)服務(wù)的運(yùn)行狀態(tài),并提供詳細(xì)的報告和告警功能。
功能介紹
這個系統(tǒng)服務(wù)狀態(tài)檢查工具具有以下核心功能:
- 跨平臺支持:支持Windows服務(wù)、Linux systemd服務(wù)和macOS launchd服務(wù)
- 服務(wù)狀態(tài)檢查:檢查指定服務(wù)的運(yùn)行狀態(tài)(運(yùn)行、停止、未知等)
- 批量檢查:支持同時檢查多個服務(wù)的狀態(tài)
- 詳細(xì)信息服務(wù):獲取服務(wù)的詳細(xì)信息,如描述、啟動類型等
- 告警通知:當(dāng)服務(wù)狀態(tài)異常時發(fā)送告警通知
- 定時監(jiān)控:支持定時檢查服務(wù)狀態(tài)
- 日志記錄:記錄服務(wù)狀態(tài)檢查的歷史記錄
- 配置文件支持:通過配置文件管理要檢查的服務(wù)列表
應(yīng)用場景
這個工具適用于以下場景:
- 服務(wù)器監(jiān)控:監(jiān)控關(guān)鍵服務(wù)(如Apache、MySQL、SSH等)的運(yùn)行狀態(tài)
- 故障排查:快速定位服務(wù)異常的根本原因
- 運(yùn)維自動化:集成到運(yùn)維流程中自動檢查服務(wù)狀態(tài)
- 系統(tǒng)維護(hù):定期檢查系統(tǒng)服務(wù)的健康狀況
- 開發(fā)測試:在開發(fā)和測試環(huán)境中驗證服務(wù)狀態(tài)
- 災(zāi)難恢復(fù):在系統(tǒng)恢復(fù)后驗證服務(wù)是否正常啟動
報錯處理
腳本包含了完善的錯誤處理機(jī)制:
- 平臺檢測:自動檢測操作系統(tǒng)類型并使用相應(yīng)的服務(wù)管理工具
- 權(quán)限驗證:檢查是否有足夠的權(quán)限訪問服務(wù)信息
- 服務(wù)存在性檢查:驗證指定服務(wù)是否存在
- 命令執(zhí)行保護(hù):安全地執(zhí)行系統(tǒng)命令并處理執(zhí)行結(jié)果
- 網(wǎng)絡(luò)異常處理:處理遠(yuǎn)程服務(wù)檢查中的網(wǎng)絡(luò)異常
- 異常捕獲:捕獲并處理運(yùn)行過程中可能出現(xiàn)的各種異常
代碼實(shí)現(xiàn)
import os
import sys
import subprocess
import argparse
import json
import time
from datetime import datetime
import platform
import smtplib
from email.mime.text import MimeText
from email.mime.multipart import MimeMultipart
class ServiceStatusChecker:
def __init__(self):
self.os_type = platform.system().lower()
self.services = []
self.results = []
self.errors = []
def add_service(self, name, display_name=None, description=None):
"""添加要檢查的服務(wù)"""
service = {
'name': name,
'display_name': display_name or name,
'description': description or ''
}
self.services.append(service)
def load_services_from_config(self, config_file):
"""從配置文件加載服務(wù)列表"""
try:
with open(config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
services = config.get('services', [])
for service in services:
self.add_service(
service['name'],
service.get('display_name'),
service.get('description')
)
return True
except Exception as e:
self.errors.append(f"加載配置文件失敗: {e}")
return False
def check_windows_service(self, service_name):
"""檢查Windows服務(wù)狀態(tài)"""
try:
# 使用sc query命令檢查服務(wù)狀態(tài)
cmd = ['sc', 'query', service_name]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode != 0:
return {
'name': service_name,
'status': 'unknown',
'error': result.stderr.strip()
}
output = result.stdout.lower()
if 'running' in output:
status = 'running'
elif 'stopped' in output:
status = 'stopped'
else:
status = 'unknown'
return {
'name': service_name,
'status': status,
'details': output
}
except subprocess.TimeoutExpired:
return {
'name': service_name,
'status': 'timeout',
'error': '命令執(zhí)行超時'
}
except Exception as e:
return {
'name': service_name,
'status': 'error',
'error': str(e)
}
def check_linux_service(self, service_name):
"""檢查Linux systemd服務(wù)狀態(tài)"""
try:
# 使用systemctl is-active命令檢查服務(wù)狀態(tài)
cmd = ['systemctl', 'is-active', service_name]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode == 0:
status = result.stdout.strip()
else:
# 如果命令失敗,可能是服務(wù)不存在
status = 'inactive' if 'inactive' in result.stdout.lower() else 'unknown'
# 獲取服務(wù)詳細(xì)信息
details = {}
try:
cmd = ['systemctl', 'show', service_name, '--no-pager']
detail_result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if detail_result.returncode == 0:
for line in detail_result.stdout.strip().split('\n'):
if '=' in line:
key, value = line.split('=', 1)
details[key] = value
except:
pass
return {
'name': service_name,
'status': status,
'details': details
}
except subprocess.TimeoutExpired:
return {
'name': service_name,
'status': 'timeout',
'error': '命令執(zhí)行超時'
}
except Exception as e:
return {
'name': service_name,
'status': 'error',
'error': str(e)
}
def check_macos_service(self, service_name):
"""檢查macOS launchd服務(wù)狀態(tài)"""
try:
# 使用launchctl list命令檢查服務(wù)狀態(tài)
cmd = ['launchctl', 'list']
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode != 0:
return {
'name': service_name,
'status': 'unknown',
'error': result.stderr.strip()
}
# 解析輸出查找服務(wù)
lines = result.stdout.strip().split('\n')[1:] # 跳過標(biāo)題行
service_found = False
pid = None
for line in lines:
parts = line.split()
if len(parts) >= 3 and service_name in parts[2]:
service_found = True
pid = parts[0] if parts[0] != '-' else None
break
if service_found:
status = 'running' if pid else 'loaded'
else:
status = 'not_found'
return {
'name': service_name,
'status': status,
'pid': pid
}
except subprocess.TimeoutExpired:
return {
'name': service_name,
'status': 'timeout',
'error': '命令執(zhí)行超時'
}
except Exception as e:
return {
'name': service_name,
'status': 'error',
'error': str(e)
}
def check_service(self, service_name):
"""檢查服務(wù)狀態(tài)(跨平臺)"""
if self.os_type == 'windows':
return self.check_windows_service(service_name)
elif self.os_type == 'linux':
return self.check_linux_service(service_name)
elif self.os_type == 'darwin': # macOS
return self.check_macos_service(service_name)
else:
return {
'name': service_name,
'status': 'unsupported',
'error': f'不支持的操作系統(tǒng): {self.os_type}'
}
def check_all_services(self):
"""檢查所有服務(wù)的狀態(tài)"""
print(f"開始檢查服務(wù)狀態(tài) (操作系統(tǒng): {self.os_type})")
print("=" * 60)
self.results = []
for service in self.services:
print(f"檢查服務(wù): {service['display_name']} ({service['name']})")
result = self.check_service(service['name'])
result['display_name'] = service['display_name']
result['description'] = service['description']
result['check_time'] = datetime.now().isoformat()
self.results.append(result)
# 顯示結(jié)果
status_display = {
'running': '? 運(yùn)行中',
'stopped': '? 已停止',
'inactive': '?? 未激活',
'loaded': '?? 已加載',
'not_found': '? 未找到',
'timeout': '? 超時',
'error': '?? 錯誤',
'unknown': '? 未知'
}
status_text = status_display.get(result['status'], result['status'])
print(f" 狀態(tài): {status_text}")
if 'error' in result:
print(f" 錯誤: {result['error']}")
print()
return self.results
def generate_report(self):
"""生成服務(wù)狀態(tài)報告"""
report = []
report.append("=" * 80)
report.append("系統(tǒng)服務(wù)狀態(tài)檢查報告")
report.append("=" * 80)
report.append(f"檢查時間: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
report.append(f"操作系統(tǒng): {self.os_type}")
report.append(f"檢查服務(wù)數(shù): {len(self.services)}")
report.append("")
# 統(tǒng)計信息
status_counts = {}
for result in self.results:
status = result['status']
status_counts[status] = status_counts.get(status, 0) + 1
report.append("狀態(tài)統(tǒng)計:")
for status, count in status_counts.items():
report.append(f" {status}: {count}")
report.append("")
# 詳細(xì)結(jié)果
report.append("服務(wù)詳細(xì)信息:")
report.append("-" * 50)
for result in self.results:
status_display = {
'running': '? 運(yùn)行中',
'stopped': '? 已停止',
'inactive': '?? 未激活',
'loaded': '?? 已加載',
'not_found': '? 未找到',
'timeout': '? 超時',
'error': '?? 錯誤',
'unknown': '? 未知'
}
status_text = status_display.get(result['status'], result['status'])
report.append(f"{result['display_name']} ({result['name']}): {status_text}")
if result['description']:
report.append(f" 描述: {result['description']}")
if 'error' in result:
report.append(f" 錯誤: {result['error']}")
report.append("")
# 錯誤信息
if self.errors:
report.append("錯誤信息:")
report.append("-" * 50)
for error in self.errors:
report.append(f" {error}")
report.append("")
report.append("=" * 80)
return "\n".join(report)
def save_report(self, filename):
"""保存報告到文件"""
try:
report = self.generate_report()
with open(filename, 'w', encoding='utf-8') as f:
f.write(report)
print(f"報告已保存到: {filename}")
return True
except Exception as e:
print(f"保存報告時出錯: {e}")
return False
def save_json_report(self, filename):
"""保存JSON格式報告"""
try:
report_data = {
'check_time': datetime.now().isoformat(),
'os_type': self.os_type,
'services': self.results,
'errors': self.errors
}
with open(filename, 'w', encoding='utf-8') as f:
json.dump(report_data, f, indent=2, ensure_ascii=False)
print(f"JSON報告已保存到: {filename}")
return True
except Exception as e:
print(f"保存JSON報告時出錯: {e}")
return False
def send_alert(self, smtp_config, alert_services=None):
"""發(fā)送告警郵件"""
try:
# 確定需要告警的服務(wù)
if alert_services is None:
# 默認(rèn)告警停止或異常的服務(wù)
alert_services = [
r for r in self.results
if r['status'] not in ['running', 'loaded']
]
if not alert_services:
print("沒有需要告警的服務(wù)")
return True
# 構(gòu)建郵件內(nèi)容
subject = f"服務(wù)狀態(tài)告警 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
body = "以下服務(wù)狀態(tài)異常:\n\n"
for service in alert_services:
body += f"服務(wù): {service['display_name']} ({service['name']})\n"
body += f"狀態(tài): {service['status']}\n"
if 'error' in service:
body += f"錯誤: {service['error']}\n"
body += "\n"
# 發(fā)送郵件
msg = MimeMultipart()
msg['From'] = smtp_config['from']
msg['To'] = smtp_config['to']
msg['Subject'] = subject
msg.attach(MimeText(body, 'plain', 'utf-8'))
server = smtplib.SMTP(smtp_config['server'], smtp_config['port'])
server.starttls()
server.login(smtp_config['username'], smtp_config['password'])
server.send_message(msg)
server.quit()
print("告警郵件已發(fā)送")
return True
except Exception as e:
print(f"發(fā)送告警郵件時出錯: {e}")
return False
def continuous_monitor(self, interval=60, max_checks=None):
"""持續(xù)監(jiān)控服務(wù)狀態(tài)"""
check_count = 0
try:
while True:
print(f"\n[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 開始第 {check_count + 1} 次檢查")
self.check_all_services()
# 顯示簡要狀態(tài)
running_count = len([r for r in self.results if r['status'] == 'running'])
print(f"運(yùn)行中服務(wù): {running_count}/{len(self.results)}")
check_count += 1
# 檢查是否達(dá)到最大檢查次數(shù)
if max_checks and check_count >= max_checks:
break
# 等待下次檢查
time.sleep(interval)
except KeyboardInterrupt:
print("\n\n停止監(jiān)控...")
def create_sample_config():
"""創(chuàng)建示例配置文件"""
config = {
"services": [
{
"name": "ssh",
"display_name": "SSH服務(wù)",
"description": "安全Shell服務(wù)"
},
{
"name": "nginx",
"display_name": "Nginx Web服務(wù)器",
"description": "高性能HTTP和反向代理服務(wù)器"
},
{
"name": "mysql",
"display_name": "MySQL數(shù)據(jù)庫",
"description": "關(guān)系型數(shù)據(jù)庫管理系統(tǒng)"
}
]
}
try:
with open('service_config.json', 'w', encoding='utf-8') as f:
json.dump(config, f, indent=2, ensure_ascii=False)
print("示例配置文件已創(chuàng)建: service_config.json")
return True
except Exception as e:
print(f"創(chuàng)建示例配置文件時出錯: {e}")
return False
def main():
parser = argparse.ArgumentParser(description="系統(tǒng)服務(wù)狀態(tài)檢查工具")
parser.add_argument("-c", "--config", help="配置文件路徑")
parser.add_argument("-s", "--service", action='append', help="要檢查的服務(wù)名稱(可多次使用)")
parser.add_argument("-o", "--output", help="保存報告到文件")
parser.add_argument("-j", "--json", help="保存JSON報告到文件")
parser.add_argument("-m", "--monitor", type=int, help="持續(xù)監(jiān)控間隔(秒)")
parser.add_argument("--max-checks", type=int, help="最大檢查次數(shù)")
parser.add_argument("--create-config", action="store_true", help="創(chuàng)建示例配置文件")
parser.add_argument("--smtp-server", help="SMTP服務(wù)器地址")
parser.add_argument("--smtp-port", type=int, default=587, help="SMTP服務(wù)器端口")
parser.add_argument("--smtp-username", help="SMTP用戶名")
parser.add_argument("--smtp-password", help="SMTP密碼")
parser.add_argument("--smtp-from", help="發(fā)件人郵箱")
parser.add_argument("--smtp-to", help="收件人郵箱")
args = parser.parse_args()
# 創(chuàng)建示例配置文件
if args.create_config:
create_sample_config()
return
try:
checker = ServiceStatusChecker()
# 加載服務(wù)列表
if args.config:
if not checker.load_services_from_config(args.config):
print("加載配置文件失敗")
sys.exit(1)
elif args.service:
for service_name in args.service:
checker.add_service(service_name)
else:
print("請指定配置文件或服務(wù)名稱")
sys.exit(1)
# 檢查服務(wù)狀態(tài)
if args.monitor:
# 持續(xù)監(jiān)控模式
checker.continuous_monitor(args.monitor, args.max_checks)
else:
# 單次檢查模式
checker.check_all_services()
# 生成報告
if args.output:
checker.save_report(args.output)
elif args.json:
checker.save_json_report(args.json)
else:
print(checker.generate_report())
# 發(fā)送告警郵件
if args.smtp_server and args.smtp_username and args.smtp_password:
smtp_config = {
'server': args.smtp_server,
'port': args.smtp_port,
'username': args.smtp_username,
'password': args.smtp_password,
'from': args.smtp_from or args.smtp_username,
'to': args.smtp_to
}
checker.send_alert(smtp_config)
except KeyboardInterrupt:
print("\n\n用戶中斷操作")
except Exception as e:
print(f"程序執(zhí)行出錯: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
使用方法
基本使用
# 創(chuàng)建示例配置文件 python service_checker.py --create-config # 使用配置文件檢查服務(wù) python service_checker.py -c service_config.json # 檢查單個服務(wù) python service_checker.py -s nginx # 檢查多個服務(wù) python service_checker.py -s nginx -s mysql -s ssh # 保存報告到文件 python service_checker.py -c service_config.json -o report.txt # 保存JSON報告 python service_checker.py -c service_config.json -j report.json # 持續(xù)監(jiān)控服務(wù)狀態(tài)(每30秒檢查一次) python service_checker.py -c service_config.json -m 30 # 持續(xù)監(jiān)控最多10次 python service_checker.py -c service_config.json -m 30 --max-checks 10
告警功能
# 發(fā)送告警郵件 python service_checker.py -c service_config.json \ --smtp-server smtp.gmail.com \ --smtp-username your_email@gmail.com \ --smtp-password your_password \ --smtp-to admin@example.com
配置文件示例
創(chuàng)建的示例配置文件 service_config.json 內(nèi)容如下:
{
"services": [
{
"name": "ssh",
"display_name": "SSH服務(wù)",
"description": "安全Shell服務(wù)"
},
{
"name": "nginx",
"display_name": "Nginx Web服務(wù)器",
"description": "高性能HTTP和反向代理服務(wù)器"
},
{
"name": "mysql",
"display_name": "MySQL數(shù)據(jù)庫",
"description": "關(guān)系型數(shù)據(jù)庫管理系統(tǒng)"
}
]
}
命令行參數(shù)說明
-c, --config: 配置文件路徑-s, --service: 要檢查的服務(wù)名稱(可多次使用)-o, --output: 保存報告到指定文件-j, --json: 保存JSON報告到指定文件-m, --monitor: 持續(xù)監(jiān)控間隔(秒)--max-checks: 最大檢查次數(shù)--create-config: 創(chuàng)建示例配置文件--smtp-server: SMTP服務(wù)器地址--smtp-port: SMTP服務(wù)器端口(默認(rèn)587)--smtp-username: SMTP用戶名--smtp-password: SMTP密碼--smtp-from: 發(fā)件人郵箱--smtp-to: 收件人郵箱
使用示例
基本檢查:
python service_checker.py -c service_config.json
持續(xù)監(jiān)控:
python service_checker.py -c service_config.json -m 60 --max-checks 10 -o status.log
帶告警的檢查:
python service_checker.py -c service_config.json \ --smtp-server smtp.gmail.com \ --smtp-username admin@example.com \ --smtp-password app_password \ --smtp-to ops-team@example.com
總結(jié)
這個系統(tǒng)服務(wù)狀態(tài)檢查工具提供了一個跨平臺的服務(wù)監(jiān)控解決方案,能夠檢查Windows、Linux和macOS系統(tǒng)上的服務(wù)狀態(tài)。它支持配置文件管理、批量檢查、持續(xù)監(jiān)控和告警通知等功能,適用于服務(wù)器監(jiān)控、故障排查和運(yùn)維自動化等多種場景。通過這個工具,用戶可以及時了解關(guān)鍵服務(wù)的運(yùn)行狀態(tài),在服務(wù)異常時快速響應(yīng),確保系統(tǒng)的穩(wěn)定運(yùn)行。
以上就是Python系統(tǒng)監(jiān)控之跨平臺檢查系統(tǒng)服務(wù)運(yùn)行狀態(tài)的完整指南的詳細(xì)內(nèi)容,更多關(guān)于Python檢查系統(tǒng)服務(wù)運(yùn)行狀態(tài)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python 3.6 中使用pdfminer解析pdf文件的實(shí)現(xiàn)
這篇文章主要介紹了Python 3.6 中使用pdfminer解析pdf文件的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
matplotlib 對坐標(biāo)的控制,加圖例注釋的操作
這篇文章主要介紹了matplotlib 對坐標(biāo)的控制,加圖例注釋的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
Pytorch Tensor的統(tǒng)計屬性實(shí)例講解
今天小編就為大家分享一篇Pytorch Tensor的統(tǒng)計屬性實(shí)例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-12-12
python+appium+yaml移動端自動化測試框架實(shí)現(xiàn)詳解
這篇文章主要介紹了python+appium+yaml移動端自動化測試框架實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Python利用BeautifulSoup解析網(wǎng)頁內(nèi)容
當(dāng)今信息爆炸的時代,網(wǎng)絡(luò)上充斥著海量的數(shù)據(jù),而網(wǎng)絡(luò)爬蟲作為一種數(shù)據(jù)采集工具,扮演著至關(guān)重要的角色,BeautifulSoup 是一個Python庫,它可以從HTML或XML文件中提取數(shù)據(jù),本文介紹了Python如何利用BeautifulSoup解析網(wǎng)頁內(nèi)容,需要的朋友可以參考下2024-06-06
使用Python和百度語音識別生成視頻字幕的實(shí)現(xiàn)
這篇文章主要介紹了使用Python和百度語音識別生成視頻字幕,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04

