168 lines
4.9 KiB
Python
168 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
日志记录器模块
|
||
负责记录网络监控的历史数据和异常事件
|
||
"""
|
||
|
||
import os
|
||
import json
|
||
from datetime import datetime
|
||
from typing import List, Dict, Any
|
||
from pathlib import Path
|
||
|
||
|
||
class Logger:
|
||
"""日志记录器类"""
|
||
|
||
def __init__(self, log_dir: str = "logs", max_log_files: int = 10):
|
||
"""
|
||
初始化日志记录器
|
||
|
||
Args:
|
||
log_dir: 日志文件存储目录
|
||
max_log_files: 最大保留的日志文件数量
|
||
"""
|
||
self.log_dir = Path(log_dir)
|
||
self.max_log_files = max_log_files
|
||
self.current_session_data: List[Dict[str, Any]] = []
|
||
self.session_start_time = datetime.now()
|
||
|
||
# 创建日志目录
|
||
self.log_dir.mkdir(parents=True, exist_ok=True)
|
||
|
||
# 清理旧日志文件
|
||
self._cleanup_old_logs()
|
||
|
||
def _get_log_filename(self) -> str:
|
||
"""生成日志文件名"""
|
||
timestamp = self.session_start_time.strftime("%Y%m%d_%H%M%S")
|
||
return f"network_monitor_{timestamp}.log"
|
||
|
||
def _cleanup_old_logs(self):
|
||
"""清理旧的日志文件,保留最近的max_log_files个"""
|
||
log_files = sorted(
|
||
self.log_dir.glob("network_monitor_*.log"),
|
||
key=lambda x: x.stat().st_mtime,
|
||
reverse=True
|
||
)
|
||
|
||
# 删除超出数量限制的旧日志文件
|
||
for old_log in log_files[self.max_log_files:]:
|
||
old_log.unlink()
|
||
|
||
def log_event(self, event_type: str, message: str, **kwargs):
|
||
"""
|
||
记录事件
|
||
|
||
Args:
|
||
event_type: 事件类型(ping, status_change, error等)
|
||
message: 事件描述
|
||
**kwargs: 额外的键值对数据
|
||
"""
|
||
event = {
|
||
"timestamp": datetime.now().isoformat(),
|
||
"type": event_type,
|
||
"message": message,
|
||
**kwargs
|
||
}
|
||
self.current_session_data.append(event)
|
||
|
||
def log_ping(self, success: bool, latency: float = 0.0):
|
||
"""
|
||
记录ping结果
|
||
|
||
Args:
|
||
success: ping是否成功
|
||
latency: 延迟时间(毫秒)
|
||
"""
|
||
self.log_event(
|
||
"ping",
|
||
"Ping操作完成" if success else "Ping操作失败",
|
||
success=success,
|
||
latency_ms=latency
|
||
)
|
||
|
||
def log_status_change(self, status: str, duration: float = None):
|
||
"""
|
||
记录状态变化
|
||
|
||
Args:
|
||
status: 状态(connected, disconnected)
|
||
duration: 持续时间(秒)
|
||
"""
|
||
message = f"网络状态变化: {status}"
|
||
if duration is not None:
|
||
message += f" (持续{duration:.1f}秒)"
|
||
|
||
self.log_event(
|
||
"status_change",
|
||
message,
|
||
status=status,
|
||
duration_seconds=duration
|
||
)
|
||
|
||
def log_error(self, error_type: str, error_message: str):
|
||
"""
|
||
记录错误
|
||
|
||
Args:
|
||
error_type: 错误类型
|
||
error_message: 错误信息
|
||
"""
|
||
self.log_event(
|
||
"error",
|
||
f"{error_type}: {error_message}",
|
||
error_type=error_type
|
||
)
|
||
|
||
def log_shutdown(self, reason: str):
|
||
"""
|
||
记录关机事件
|
||
|
||
Args:
|
||
reason: 关机原因
|
||
"""
|
||
self.log_event(
|
||
"shutdown",
|
||
f"系统关机: {reason}",
|
||
reason=reason
|
||
)
|
||
|
||
def save_session(self):
|
||
"""保存当前会话的日志到文件"""
|
||
log_file = self.log_dir / self._get_log_filename()
|
||
|
||
session_summary = {
|
||
"session_start": self.session_start_time.isoformat(),
|
||
"session_end": datetime.now().isoformat(),
|
||
"total_events": len(self.current_session_data),
|
||
"events": self.current_session_data
|
||
}
|
||
|
||
with open(log_file, 'w', encoding='utf-8') as f:
|
||
json.dump(session_summary, f, ensure_ascii=False, indent=2)
|
||
|
||
return log_file
|
||
|
||
def get_statistics(self) -> Dict[str, Any]:
|
||
"""
|
||
获取当前会话的统计信息
|
||
|
||
Returns:
|
||
统计数据字典
|
||
"""
|
||
total_pings = sum(1 for event in self.current_session_data if event["type"] == "ping")
|
||
successful_pings = sum(
|
||
1 for event in self.current_session_data
|
||
if event["type"] == "ping" and event["success"]
|
||
)
|
||
|
||
return {
|
||
"total_pings": total_pings,
|
||
"successful_pings": successful_pings,
|
||
"failed_pings": total_pings - successful_pings,
|
||
"success_rate": f"{(successful_pings / total_pings * 100):.2f}%" if total_pings > 0 else "0%",
|
||
"session_duration": (datetime.now() - self.session_start_time).total_seconds()
|
||
}
|