Files
assist/.kiro/skills/log-summary/scripts/log_summary.py
Jeason 7950cd8237 feat: 飞书机器人按租户路由 群组绑定租户 + 独立凭证 + 知识库隔离
1. 新增 resolve_tenant_by_chat_id() 根据飞书群 chat_id 查找绑定的租户
2. 新增 get_tenant_feishu_config() 获取租户级飞书凭证
3. FeishuService 支持传入自定义 app_id/app_secret(租户级别)
4. feishu_bot.py 收到消息时自动解析租户,使用租户凭证回复
5. feishu_longconn_service.py 同样按 chat_id 解析租户并传递 tenant_id
6. 租户管理 UI 新增飞书配置字段:App ID、App Secret、绑定群 Chat ID
7. 租户列表展示飞书绑定状态和群数量
8. 保存租户时同步更新飞书配置到 config JSON
2026-04-02 09:58:04 +08:00

116 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
简单日志汇总脚本
遍历 logs/ 目录下最近的若干个 dashboard.log 文件,统计 ERROR / WARNING / CRITICAL
并输出简要汇总信息,供 log-summary Skill 调用。
"""
import os
import re
from pathlib import Path
from typing import List, Tuple
LOG_ROOT = Path("logs")
LOG_FILENAME = "dashboard.log"
MAX_FILES = 5 # 最多分析最近 N 个日志文件
LEVEL_PATTERNS = {
"ERROR": re.compile(r"\bERROR\b"),
"WARNING": re.compile(r"\bWARNING\b"),
"CRITICAL": re.compile(r"\bCRITICAL\b"),
}
def find_log_files() -> List[Path]:
if not LOG_ROOT.exists():
return []
candidates: List[Tuple[float, Path]] = []
for root, dirs, files in os.walk(LOG_ROOT):
if LOG_FILENAME in files:
p = Path(root) / LOG_FILENAME
try:
mtime = p.stat().st_mtime
except OSError:
continue
candidates.append((mtime, p))
# 按修改时间从新到旧排序
candidates.sort(key=lambda x: x[0], reverse=True)
return [p for _, p in candidates[:MAX_FILES]]
def summarize_file(path: Path):
counts = {level: 0 for level in LEVEL_PATTERNS.keys()}
top_messages = {}
try:
with path.open("r", encoding="utf-8", errors="ignore") as f:
for line in f:
for level, pattern in LEVEL_PATTERNS.items():
if pattern.search(line):
counts[level] += 1
# 取日志消息部分做前缀(粗略)
msg = line.strip()
# 截断以防过长
msg = msg[:200]
top_messages[msg] = top_messages.get(msg, 0) + 1
break
except OSError as e:
print(f"[!] 读取日志失败 {path}: {e}")
return None
# 取 Top 5
top_list = sorted(top_messages.items(), key=lambda x: x[1], reverse=True)[:5]
return counts, top_list
def main():
log_files = find_log_files()
if not log_files:
print("未找到任何日志文件logs/*/dashboard.log")
return
print(f"共找到 {len(log_files)} 个最近的日志文件(最多 {MAX_FILES} 个):\n")
overall = {level: 0 for level in LEVEL_PATTERNS.keys()}
for idx, path in enumerate(log_files, start=1):
print(f"[{idx}] 日志文件: {path}")
result = summarize_file(path)
if result is None:
print(" 无法读取该日志文件。\n")
continue
counts, top_list = result
for level, c in counts.items():
overall[level] += c
print(
" 级别统计: "
+ ", ".join(f"{lvl}={counts[lvl]}" for lvl in LEVEL_PATTERNS.keys())
)
if top_list:
print(" Top 错误/警告消息:")
for msg, n in top_list:
print(f" [{n}次] {msg}")
else:
print(" 未发现 ERROR/WARNING/CRITICAL 级别日志。")
print()
print("总体统计:")
print(
" "
+ ", ".join(f"{lvl}={overall[lvl]}" for lvl in LEVEL_PATTERNS.keys())
)
if __name__ == "__main__":
main()