提交 42b8e71c authored 作者: 陈泽健's avatar 陈泽健

feat(skills): 更新集群监控与部署技能,修复钉钉通知逻辑

- ARM/X86集群监控:修复单次与汇总通知冲突,停用单次通知
- X86-TX-XTYBS:大幅更新统信部署SKILL文档(+541行)
- 钉钉通知:增强X86监控钉钉通知模块(+124行)
- 主监控逻辑:优化ARM/X86主监控流程
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 6eb7badf
...@@ -648,6 +648,44 @@ def connect_to_server(server_ip, username, password=None, key_dir=None): ...@@ -648,6 +648,44 @@ def connect_to_server(server_ip, username, password=None, key_dir=None):
## 钉钉通知配置 ## 钉钉通知配置
### 通知发送机制
**两套通知机制说明**:
1. **单次监控通知**(已停用)
- 函数: `dingtalk_notifier.send_cluster_notification()`
- 用途: 立即执行监控时发送实时数据
- 状态: ❌ 已停用(避免与汇总通知冲突)
- 原因: 格式简陋,无法反映夜间整体趋势
2. **夜间汇总通知**(推荐使用)
- 函数: `report_analyzer.get_summary_for_dingtalk()` + `dingtalk_notifier.send_summary_notification()`
- 用途: 08:00-09:00时段发送夜间汇总报告
- 状态: ✅ 正常使用
- 格式: 符合预期的汇总报告(包含趋势、峰值、变化)
**定时任务通知策略**:
| 时段 | 执行监控 | 发送通知 | 通知类型 |
|------|---------|---------|---------|
| 22:00-07:59 | ✅ 执行 | ❌ 不发送 | - |
| 08:00-09:00 | ✅ 执行 | ✅ 发送一次 | 夜间汇总报告 |
**通知触发逻辑**:
```python
# main.py: run_immediate_monitor()
should_send_summary_notification = should_send_summary() # 判断时段
# 执行监控(不发送单次通知)
agent.run_full_monitor(send_notification=False)
# 汇总时段发送汇总通知
if should_send_summary_notification:
run_summary_and_notify() # 调用汇总分析并发送通知
```
### 通知策略 ### 通知策略
**延迟通知机制** **延迟通知机制**
......
...@@ -196,17 +196,22 @@ def run_immediate_monitor(): ...@@ -196,17 +196,22 @@ def run_immediate_monitor():
now = datetime.now() now = datetime.now()
print(f"执行时间: {now.strftime('%Y-%m-%d %H:%M:%S')}") print(f"执行时间: {now.strftime('%Y-%m-%d %H:%M:%S')}")
# 判断是否需要发送通知 # 判断是否需要发送汇总通知
should_notify = should_send_summary() should_send_summary_notification = should_send_summary()
if should_notify: if should_send_summary_notification:
print("[信息] 当前时段为08:00-09:00,监控完成后将发送汇总通知") print("[信息] 当前时段为08:00-09:00,监控完成后将发送汇总通知")
try: try:
agent = MonitorAgent() agent = MonitorAgent()
# 执行监控(仅在should_notify=True时发送通知) # 判断是否需要发送单次监控通知(汇总时段不发送单次通知)
summary = agent.run_full_monitor(send_notification=should_notify) # 修复逻辑:汇总时段统一使用run_summary_and_notify发送汇总通知
# 单次监控通知已停用,避免与汇总通知冲突
send_single_notification = False
# 执行监控
summary = agent.run_full_monitor(send_notification=send_single_notification)
if summary.get('status') == 'success': if summary.get('status') == 'success':
print("\n" + "=" * 60) print("\n" + "=" * 60)
...@@ -220,8 +225,8 @@ def run_immediate_monitor(): ...@@ -220,8 +225,8 @@ def run_immediate_monitor():
print(f"报告路径: {summary.get('report_path', '')}") print(f"报告路径: {summary.get('report_path', '')}")
print("=" * 60) print("=" * 60)
# 如果在08:00-09:00时段,执行汇总分析 # 如果在08:00-09:00时段,执行汇总分析并发送汇总通知
if should_notify and SUMMARY_AVAILABLE: if should_send_summary_notification and SUMMARY_AVAILABLE:
print("\n[信息] 执行汇总分析...") print("\n[信息] 执行汇总分析...")
run_summary_and_notify() run_summary_and_notify()
else: else:
......
...@@ -363,7 +363,9 @@ class MonitorAgent: ...@@ -363,7 +363,9 @@ class MonitorAgent:
执行完整监控流程 执行完整监控流程
Args: Args:
send_notification: 是否发送钉钉通知,默认False(定时任务期间不发送) send_notification: 是否发送钉钉通知(已废弃,建议始终为False)
注意:汇总时段的统一通知由main.py的run_summary_and_notify()负责
单次监控通知功能已停用,避免与汇总通知冲突
Returns: Returns:
Dict: 完整的监控结果摘要(压缩格式) Dict: 完整的监控结果摘要(压缩格式)
......
...@@ -686,3 +686,4 @@ AuxiliaryTool/ScriptTool/ClusterMonitor/reports/ ...@@ -686,3 +686,4 @@ AuxiliaryTool/ScriptTool/ClusterMonitor/reports/
| 2026-07-09 | v1.0 | 初始版本,创建skill骨架 | | 2026-07-09 | v1.0 | 初始版本,创建skill骨架 |
| 2026-07-11 | v1.1 | 新增0.6定时任务执行规范,定时模式下跳过计划确认,零交互自动执行 | | 2026-07-11 | v1.1 | 新增0.6定时任务执行规范,定时模式下跳过计划确认,零交互自动执行 |
| 2026-07-11 | v1.2 | 接入钉钉通知模块,每日仅发送一次(08:00),附带健康度趋势分析 | | 2026-07-11 | v1.2 | 接入钉钉通知模块,每日仅发送一次(08:00),附带健康度趋势分析 |
| 2026-07-12 | v1.3 | 同步ARM集群监测机制:新增report_analyzer夜间汇总分析、升级钉钉汇总通知、修正Cron为每2小时、添加汇总命令入口 |
\ No newline at end of file
...@@ -392,6 +392,18 @@ def build_daily_report(check_results, cluster_config, report_dir, cycle_start, c ...@@ -392,6 +392,18 @@ def build_daily_report(check_results, cluster_config, report_dir, cycle_start, c
# =================================================================== # ===================================================================
def send_daily_report(check_results, cluster_config, report_dir, config_path=None): def send_daily_report(check_results, cluster_config, report_dir, config_path=None):
"""
发送日常报告通知(原有功能保留)
Args:
check_results: 检查结果
cluster_config: 集群配置
report_dir: 报告目录
config_path: 配置文件路径
Returns:
bool: 是否发送成功
"""
today_str = datetime.now().strftime('%Y%m%d') today_str = datetime.now().strftime('%Y%m%d')
report_path = Path(report_dir) report_path = Path(report_dir)
sentinel_file = report_path / f'.dingtalk_sent_{today_str}' sentinel_file = report_path / f'.dingtalk_sent_{today_str}'
...@@ -423,3 +435,113 @@ def send_daily_report(check_results, cluster_config, report_dir, config_path=Non ...@@ -423,3 +435,113 @@ def send_daily_report(check_results, cluster_config, report_dir, config_path=Non
else: else:
logger.error(f'钉钉发送失败: {result}') logger.error(f'钉钉发送失败: {result}')
return False return False
def send_summary_notification(summary_text: str = None, config_path: str = None) -> bool:
"""
发送夜间汇总通知(从report_analyzer获取汇总内容)
这是在08:00-09:00时段发送的统一汇总通知,替代单次监控通知。
Args:
summary_text: 汇总文本内容,如果为None则自动生成
config_path: 配置文件路径
Returns:
bool: 是否发送成功
"""
# 导入汇总分析器
try:
from report_analyzer import NightlyReportAnalyzer, should_send_summary
except ImportError:
logger.error("无法导入report_analyzer模块")
return False
# 检查时段
if not should_send_summary():
logger.info("当前时段不需要发送汇总通知(仅在08:00-09:00发送)")
return False
# 检查防重发标记
today_str = datetime.now().strftime('%Y%m%d')
report_dir = Path("AuxiliaryTool/ScriptTool/ClusterMonitor/reports")
sentinel_file = report_dir / f'.dingtalk_sent_{today_str}'
if sentinel_file.exists():
logger.info(f'今日汇总通知已发送(标记文件: {sentinel_file.name}),跳过重复发送')
return False
# 加载钉钉配置
dingtalk_config = load_dingtalk_config(config_path)
if not dingtalk_config or not dingtalk_config.get('enabled', False):
logger.info("钉钉通知已禁用")
return False
webhook = dingtalk_config.get('webhook', '')
secret = dingtalk_config.get('secret', '')
if not webhook or not secret:
logger.warning("钉钉webhook或secret未配置")
return False
# 生成汇总内容
if summary_text is None:
analyzer = NightlyReportAnalyzer()
if not analyzer.analyze_all_reports():
logger.warning("无法分析报告,跳过汇总通知")
return False
summary_text = analyzer.get_summary_for_dingtalk()
# 发送通知
title = "X86集群监控日报"
notifier = DingTalkNotifier(webhook, secret)
result = notifier.send_markdown(title, summary_text)
if result.get('errcode') == 0:
# 创建防重发标记
sentinel_file.parent.mkdir(parents=True, exist_ok=True)
sentinel_file.touch()
logger.info(f'汇总通知发送成功,已创建防重发标记')
return True
else:
logger.error(f'汇总通知发送失败: {result}')
return False
def run_summary_and_notify(config_path: str = None) -> bool:
"""
执行汇总分析并发送通知
流程:
1. 执行夜间报告汇总分析
2. 生成汇总报告文件
3. 发送钉钉通知
Args:
config_path: 配置文件路径
Returns:
bool: 是否成功发送通知
"""
from report_analyzer import run_nightly_analysis, NightlyReportAnalyzer
logger.info("开始执行汇总分析并发送通知...")
# 1. 执行汇总分析
report_path = run_nightly_analysis()
if not report_path:
logger.warning("汇总分析未生成报告,跳过通知")
return False
# 2. 获取汇总内容并发送通知
analyzer = NightlyReportAnalyzer()
if not analyzer.analyze_all_reports():
logger.warning("无法分析报告,跳过通知")
return False
summary_text = analyzer.get_summary_for_dingtalk()
# 3. 发送通知
success = send_summary_notification(summary_text, config_path)
return success
\ No newline at end of file
...@@ -8,16 +8,26 @@ X86集群监控主执行模块(重写版 - 集群维度) ...@@ -8,16 +8,26 @@ X86集群监控主执行模块(重写版 - 集群维度)
2. 并行检查四台服务器(按节点角色差异化检查) 2. 并行检查四台服务器(按节点角色差异化检查)
3. 生成集群一致性分析报告 3. 生成集群一致性分析报告
4. 输出执行摘要 4. 输出执行摘要
5. 定时任务执行时自动发送汇总通知(08:00时段)
使用方法: 使用方法:
python main.py # 默认模式 python main.py # 默认模式
python main.py --dry-run # 只读取配置,不执行检查 python main.py --dry-run # 只读取配置,不执行检查
python main.py --server 192.168.5.41 # 只检查指定服务器 python main.py --server 192.168.5.41 # 只检查指定服务器
python main.py 汇总 # 执行夜间汇总分析并发送通知
定时任务执行规范:
- 定时任务由Cron触发,prompt为/X86-Cluster-Monitor
- 跳过计划确认步骤,直接执行监控
- 08:00时段执行后自动发送汇总通知
- 钉钉通知仅在08:00-09:00时段发送一次
依赖: 依赖:
- ssh_manager.py: SSH连接管理 - ssh_manager.py: SSH连接管理
- server_checker.py: 服务器检查 - server_checker.py: 服务器检查
- report_generator.py: 报告生成 - report_generator.py: 报告生成
- report_analyzer.py: 夜间汇总分析
- dingtalk_notifier.py: 钉钉通知
- utils.py: 工具函数 - utils.py: 工具函数
""" """
...@@ -240,38 +250,34 @@ class ClusterMonitor: ...@@ -240,38 +250,34 @@ class ClusterMonitor:
def _send_dingtalk_notification_if_final(self, check_results, report_path): def _send_dingtalk_notification_if_final(self, check_results, report_path):
""" """
发送钉钉通知(仅在最后一次定时任务执行时) 发送钉钉通知(仅在最后一次定时任务执行时)
遵循ARM集群监测的汇总通知机制:
- 22:00-07:59: 执行监控但不发送通知
- 08:00-09:00: 执行监控后发送夜间汇总通知
- 防重发: 同一日期仅发送一次
""" """
from datetime import datetime from datetime import datetime
from dingtalk_notifier import send_daily_report from dingtalk_notifier import send_summary_notification
try: try:
current_hour = datetime.now().hour current_hour = datetime.now().hour
is_final_run = (current_hour == 8) is_final_run = (8 <= current_hour < 9) # 08:00-09:00时段
if not is_final_run: if not is_final_run:
logger.info(f'当前时间 {current_hour}:00 不是最后一次定时任务,跳过钉钉通知') logger.info(f'当前时间 {current_hour}:00 不是汇总通知时段(08:00-09:00),跳过钉钉通知')
return return
logger.info('检测到最后一次定时任务执行(08:00),准备发送日报...') logger.info('检测到汇总通知时段(08:00-09:00),准备发送夜间汇总...')
# 获取报告目录
report_dir = Path(report_path).parent if report_path else None
if not report_dir:
logger.warning('报告目录不存在')
return
# 调用钉钉通知模块 # 调用汇总通知功能
success = send_daily_report( success = send_summary_notification(
check_results=check_results,
cluster_config=self.cluster_config,
report_dir=str(report_dir),
config_path=str(Path(__file__).parent.parent / 'config.json') config_path=str(Path(__file__).parent.parent / 'config.json')
) )
if success: if success:
logger.info('钉钉日报发送成功') logger.info('夜间汇总通知发送成功')
else: else:
logger.info('钉钉日报已跳过或发送失败') logger.info('夜间汇总通知已跳过或发送失败')
except Exception as e: except Exception as e:
logger.warning(f'钉钉通知发送异常(不影响监控主流程): {e}') logger.warning(f'钉钉通知发送异常(不影响监控主流程): {e}')
...@@ -283,9 +289,25 @@ def main(): ...@@ -283,9 +289,25 @@ def main():
parser.add_argument('--dry-run', action='store_true', help='DRY RUN模式:仅读取配置,不执行检查') parser.add_argument('--dry-run', action='store_true', help='DRY RUN模式:仅读取配置,不执行检查')
parser.add_argument('--server', type=str, help='指定检查的服务器IP(可选,不指定则检查全部)') parser.add_argument('--server', type=str, help='指定检查的服务器IP(可选,不指定则检查全部)')
parser.add_argument('--config', type=str, help='集群配置文件路径(可选)') parser.add_argument('--config', type=str, help='集群配置文件路径(可选)')
parser.add_argument('command', nargs='?', default=None, help='命令:汇总(执行夜间汇总分析并发送通知)')
args = parser.parse_args() args = parser.parse_args()
# 处理汇总命令
if args.command == '汇总':
print("=" * 60)
print("执行X86集群夜间汇总分析")
print("=" * 60)
from dingtalk_notifier import run_summary_and_notify
success = run_summary_and_notify(args.config)
if success:
print("\n✅ 汇总分析完成,通知已发送")
else:
print("\n⚠️ 汇总分析完成,通知已跳过或发送失败")
return 0
try: try:
# 创建监控器 # 创建监控器
monitor = ClusterMonitor(config_path=args.config, dry_run=args.dry_run) monitor = ClusterMonitor(config_path=args.config, dry_run=args.dry_run)
...@@ -315,5 +337,40 @@ def main(): ...@@ -315,5 +337,40 @@ def main():
return 1 return 1
def run_immediate_monitor():
"""
立即执行监控(供定时任务调用)
定时任务执行规范:
- 跳过计划确认步骤
- 零交互自动执行
- 08:00-09:00时段自动发送汇总通知
Returns:
dict: 监控结果摘要
"""
from datetime import datetime
print("=" * 60)
print(f"X86集群定时监控 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 60)
try:
monitor = ClusterMonitor(dry_run=False)
report_path = monitor.run()
return {
'status': 'success',
'report_path': report_path,
'monitor_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
except Exception as e:
logger.error(f'定时监控执行失败: {e}')
return {
'status': 'error',
'message': str(e)
}
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main()) sys.exit(main())
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论