将系统信息收集功能改为 Django 命令的实现方案,该命令将系统信息写入 system.ini 文件,然后 BeaconHealthCheckView 从该文件读取系统信息
下面是将系统信息收集功能改为 Django 命令的实现方案,该命令将系统信息写入 system.ini 文件,然后 BeaconHealthCheckView 从该文件读取系统信息:
### 1. 创建 Django 管理命令
在您的应用目录中创建 `management/commands/write_system_info.py` 文件:
```python
# apps/audit_logs/management/commands/write_system_info.py
import os
import platform
import time
import configparser
import logging
from django.core.management.base import BaseCommand
logger = logging.getLogger(__name__)
class Command(BaseCommand):
help = 'Writes system information to system.ini file'
def handle(self, *args, **options):
try:
system_info = self.collect_system_info()
self.write_to_ini(system_info)
self.stdout.write(self.style.SUCCESS('Successfully wrote system info to system.ini'))
except Exception as e:
logger.error(f"Failed to write system info: {str(e)}")
self.stderr.write(self.style.ERROR(f'Error: {str(e)}'))
def collect_system_info(self):
"""收集系统信息"""
return {
'os': platform.system(),
'os_release': platform.release(),
'os_version': platform.version(),
'architecture': platform.machine(),
'processor': platform.processor(),
'python_version': platform.python_version(),
'django_version': self.get_django_version(),
'drf_version': self.get_drf_version(),
'hostname': platform.node(),
'uptime': self.get_system_uptime()
}
def get_django_version(self):
"""获取Django版本"""
try:
import django
return django.get_version()
except ImportError:
return "unknown"
def get_drf_version(self):
"""获取DRF版本"""
try:
import rest_framework
return rest_framework.__version__
except ImportError:
return "unknown"
def get_system_uptime(self):
"""获取系统运行时间"""
try:
import psutil
boot_time = psutil.boot_time()
uptime_seconds = time.time() - boot_time
hours, remainder = divmod(uptime_seconds, 3600)
minutes, seconds = divmod(remainder, 60)
return f"{int(hours)}h {int(minutes)}m {int(seconds)}s"
except (ImportError, AttributeError):
return "unknown"
def write_to_ini(self, system_info):
"""将系统信息写入INI文件"""
config = configparser.ConfigParser()
config['System'] = system_info
# 确定文件路径(项目根目录)
from django.conf import settings
file_path = os.path.join(settings.BASE_DIR, 'system.ini')
with open(file_path, 'w') as configfile:
config.write(configfile)
```
### 2. 修改 BeaconHealthCheckView 从文件读取系统信息
```python
# apps/audit_logs/beacon/views.py
import os
import configparser
from django.conf import settings
class BeaconHealthCheckView(APIView):
# ... 其他代码保持不变 ...
SYSTEM_INFO_FILE = os.path.join(settings.BASE_DIR, 'system.ini')
def get_system_info(self):
"""从system.ini文件读取系统平台信息"""
try:
# 检查文件是否存在
if not os.path.exists(self.SYSTEM_INFO_FILE):
logger.warning("system.ini file not found, using default system info")
return self.default_system_info()
# 读取INI文件
config = configparser.ConfigParser()
config.read(self.SYSTEM_INFO_FILE)
if not config.has_section('System'):
logger.error("Invalid system.ini format, missing [System] section")
return self.default_system_info()
return dict(config['System'])
except Exception as e:
logger.error(f"Error reading system info from file: {str(e)}")
return self.default_system_info()
def default_system_info(self):
"""当文件不可用时返回默认系统信息"""
return {
'os': 'Unknown',
'os_release': 'Unknown',
'os_version': 'Unknown',
'architecture': 'Unknown',
'processor': 'Unknown',
'python_version': 'Unknown',
'django_version': 'Unknown',
'drf_version': 'Unknown',
'hostname': 'Unknown',
'uptime': 'Unknown',
'error': 'System info file not available'
}
# 移除原有的系统信息收集方法
# 保留其他健康检查方法...
```
### 3. 配置自动运行命令
为了确保系统信息在应用启动时是最新的,可以在 `apps.py` 中添加自动运行命令的逻辑:
```python
# apps/audit_logs/apps.py
import os
from django.apps import AppConfig
from django.core.management import call_command
class AuditLogsConfig(AppConfig):
name = 'apps.audit_logs'
def ready(self):
"""应用启动时自动运行命令"""
if os.environ.get('RUN_MAIN') == 'true': # 确保只在主进程运行
try:
# 检查文件是否存在,如果不存在则创建
from django.conf import settings
system_info_file = os.path.join(settings.BASE_DIR, 'system.ini')
if not os.path.exists(system_info_file):
self.stdout.write("Creating system.ini file...")
call_command('write_system_info')
# 定期更新系统信息(可选)
self.schedule_system_info_update()
except Exception as e:
import logging
logger = logging.getLogger(__name__)
logger.error(f"Failed to initialize system info: {str(e)}")
def schedule_system_info_update(self):
"""安排定期更新系统信息"""
try:
from apscheduler.schedulers.background import BackgroundScheduler
from django_apscheduler.jobstores import DjangoJobStore
# 创建调度器
scheduler = BackgroundScheduler()
scheduler.add_jobstore(DjangoJobStore(), 'default')
# 添加每日更新任务
if not scheduler.get_job('system_info_update'):
scheduler.add_job(
self.update_system_info,
'cron',
hour=3, # 每天凌晨3点更新
id='system_info_update',
replace_existing=True
)
scheduler.start()
except ImportError:
# 如果APScheduler不可用,忽略
pass
except Exception as e:
import logging
logger = logging.getLogger(__name__)
logger.error(f"Failed to schedule system info update: {str(e)}")
def update_system_info(self):
"""更新系统信息文件"""
from django.core.management import call_command
call_command('write_system_info')
```
### 4. 使用说明
1. **手动运行命令**:
```bash
python manage.py write_system_info
```
2. **自动运行**:
- 应用启动时会自动检查并创建 `system.ini` 文件
- 配置了每天凌晨3点自动更新系统信息(需要安装 `django-apscheduler`)
3. **文件位置**:
- 系统信息文件位于项目根目录下的 `system.ini` 文件
- 文件内容示例:
```
[System]
os = Linux
os_release = 5.15.0-86-generic
os_version = #96-Ubuntu SMP Wed Sep 20 08:23:49 UTC 2023
architecture = x86_64
processor = x86_64
python_version = 3.10.12
django_version = 4.2.5
drf_version = 3.14.0
hostname = production-server
uptime = 15h 30m 45s
```
### 5. 依赖安装
如果需要定时更新功能,安装依赖:
```bash
pip install django-apscheduler
```
然后在 `settings.py` 中添加:
```python
INSTALLED_APPS = [
# ...
'django_apscheduler',
]
```
### 优势
1. **性能提升**:
- 健康检查端点不再需要实时收集系统信息
- 直接从文件读取,速度更快
- 减少了平台模块的导入开销
2. **资源优化**:
- 系统信息收集只在需要时进行(启动时或定时更新)
- 避免了每次健康检查请求都调用 `psutil` 等资源密集型操作
3. **可靠性**:
- 即使系统信息收集失败,健康检查端点也能提供默认值
- 错误隔离,系统信息问题不会影响其他健康检查
4. **可维护性**:
- 系统信息收集逻辑集中在一个命令中
- 文件格式易于阅读和调试
- 更新策略可配置(定时更新)
这个实现方案将系统信息收集与健康检查端点分离,显著提升了性能,同时保持了系统信息的准确性和可用性。