feat: 添加 Dashboard 完整日志监控系统 v1.1.0
✨ 新增功能 - 完整的日志记录系统(6 种日志级别) - 日志配置功能(可通过 config.json 控制) - 性能监控装饰器和请求日志中间件 - 7 个管理工具脚本 - 完整的文档和使用指南 🛠️ 管理工具 - start-with-log.sh: 启动脚本(带日志) - stop-dashboard.sh: 停止脚本 - view-logs.sh: 日志查看器 - monitor-logs.sh: 实时监控工具(支持多种过滤器) - analyze-logs.sh: 日志分析工具(自动生成报告) - demo-logging.sh: 功能演示脚本 - test-logging-config.sh: 配置测试工具 📊 日志特性 - 支持 INFO/SUCCESS/WARN/ERROR/DEBUG/PERF 6 种级别 - 自动记录启动过程、API 请求、性能统计 - 缓存命中情况追踪 - 分步性能监控 - 智能过滤器 ⚙️ 配置功能 - 可控制是否启用日志(默认:true) - 可设置日志级别(默认:INFO) - 可控制文件/控制台输出 - 支持动态配置(重启生效) 📚 文档 - LOGGING_GUIDE.md: 完整使用指南 - LOGGING_CONFIG.md: 配置说明文档 - LOGGING_CONFIG_QUICK.md: 快速配置指南 - 多个中文说明文档 🔒 安全 - 添加 .gitignore 排除敏感信息 - config.json(含 Token)不提交 - 日志文件不提交 - 示例配置使用占位符 ✅ 测试 - 语法检查通过 - 功能完整性验证 - 配置控制测试通过 - 文档完整性检查 详见 CHANGELOG_v1.1.0.md Made-with: Cursor
This commit is contained in:
388
scripts/poll-tasks.sh
Normal file
388
scripts/poll-tasks.sh
Normal file
@@ -0,0 +1,388 @@
|
||||
#!/bin/bash
|
||||
# GitHub 任务轮询 — 迭代循环模式
|
||||
# 每次轮询只处理 checklist 中的一项,直到全部完成
|
||||
|
||||
REPO="$GITHUB_REPO"
|
||||
BOT="$BOT_NAME"
|
||||
ROLE="$BOT_ROLE"
|
||||
CODE_REPO_DIR="/home/node/code-repo"
|
||||
SKILLS_REPO_DIR="/home/node/skills-repo"
|
||||
WORKSPACE="/home/node/.openclaw/workspace"
|
||||
SKILLS_DIR="/home/node/.openclaw/skills"
|
||||
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "[$TIMESTAMP] $BOT 开始轮询任务..."
|
||||
|
||||
health=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:18789/healthz 2>/dev/null)
|
||||
if [ "$health" != "200" ]; then
|
||||
echo "⚠️ Gateway 未就绪 (HTTP $health), 跳过本轮"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── 同步技能仓的新技能 ──
|
||||
if [ -d "$SKILLS_REPO_DIR/.git" ]; then
|
||||
cd "$SKILLS_REPO_DIR" && git pull --rebase 2>/dev/null
|
||||
for f in "$SKILLS_REPO_DIR"/*.md; do
|
||||
[ -f "$f" ] && cp "$f" "$SKILLS_DIR/" 2>/dev/null
|
||||
done
|
||||
fi
|
||||
|
||||
# ── 1. 先找 in-progress 的任务(上次没做完的) ──
|
||||
issue_json=$(gh issue list -R "$REPO" -l "status:in-progress" -l "role:${BOT}" \
|
||||
--json number,title,body -q '.[0]' 2>/dev/null)
|
||||
|
||||
# ── 2. 没有 in-progress 就找 pending 的 ──
|
||||
if [ -z "$issue_json" ] || [ "$issue_json" = "null" ]; then
|
||||
issue_json=$(gh issue list -R "$REPO" -l "status:pending" -l "role:${BOT}" \
|
||||
--json number,title,body -q '.[0]' 2>/dev/null)
|
||||
|
||||
if [ -z "$issue_json" ] || [ "$issue_json" = "null" ]; then
|
||||
echo "📭 没有待处理任务"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
number=$(echo "$issue_json" | jq -r '.number')
|
||||
gh issue edit "$number" -R "$REPO" \
|
||||
--remove-label "status:pending" \
|
||||
--add-label "status:in-progress" 2>/dev/null
|
||||
echo "📋 领取新任务 #$number"
|
||||
else
|
||||
echo "🔄 继续处理进行中任务"
|
||||
fi
|
||||
|
||||
number=$(echo "$issue_json" | jq -r '.number')
|
||||
title=$(echo "$issue_json" | jq -r '.title')
|
||||
body=$(echo "$issue_json" | jq -r '.body')
|
||||
|
||||
echo "📋 任务 #$number: $title"
|
||||
|
||||
# ── 3. 确定当前阶段 ──
|
||||
current_phase="unknown"
|
||||
if echo "$body" | grep -qi 'phase:design'; then
|
||||
current_phase="design"
|
||||
elif echo "$body" | grep -qi 'phase:coding'; then
|
||||
current_phase="coding"
|
||||
elif echo "$body" | grep -qi 'phase:review'; then
|
||||
current_phase="review"
|
||||
fi
|
||||
|
||||
# ── 3b. 扫描 body 中所有 checklist(兼容有编号和无编号格式) ──
|
||||
next_item=""
|
||||
next_item_num=0
|
||||
section_item_num=0
|
||||
total_items=0
|
||||
done_items=0
|
||||
global_count=0
|
||||
|
||||
while IFS= read -r line; do
|
||||
# 兼容两种 checkbox 格式:
|
||||
# - [ ] 1. 任务描述 (有编号)
|
||||
# - [ ] 任务描述 (无编号)
|
||||
if echo "$line" | grep -qE '^\- \[[ x]\] '; then
|
||||
global_count=$((global_count + 1))
|
||||
total_items=$((total_items + 1))
|
||||
if echo "$line" | grep -qE '^\- \[x\]'; then
|
||||
done_items=$((done_items + 1))
|
||||
elif [ -z "$next_item" ]; then
|
||||
next_item=$(echo "$line" | sed 's/^- \[ \] \([0-9]*\.\s*\)\?//')
|
||||
next_item_num=$global_count
|
||||
section_item_num=$total_items
|
||||
fi
|
||||
fi
|
||||
done <<< "$body"
|
||||
|
||||
if [ $total_items -eq 0 ]; then
|
||||
echo "⚠️ Issue body 中没有 checklist (- [ ] / - [x]),跳过本轮"
|
||||
echo "💡 请大龙虾在 Issue body 中添加 checklist 格式的任务清单"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$next_item" ] && [ $total_items -gt 0 ]; then
|
||||
echo "✅ 当前阶段所有项目已完成 ($done_items/$total_items)"
|
||||
|
||||
phase_label="设计"
|
||||
[ "$current_phase" = "coding" ] && phase_label="编码"
|
||||
[ "$current_phase" = "review" ] && phase_label="测试"
|
||||
|
||||
echo "📌 ${phase_label}阶段全部完成,交接给大龙虾"
|
||||
|
||||
# 移除当前 worker 标签,加上 role:dalongxia,让大龙虾接管
|
||||
gh issue edit "$number" -R "$REPO" \
|
||||
--remove-label "role:${BOT}" \
|
||||
--add-label "role:dalongxia" 2>/dev/null
|
||||
|
||||
tmphandoff=$(mktemp /tmp/issue-handoff-XXXXXX.md)
|
||||
cat > "$tmphandoff" << HANDOFF_EOF
|
||||
🦞 **${phase_label}阶段全部完成** ($done_items/$total_items) — 交接给大龙虾
|
||||
|
||||
**执行者**: ${BOT}
|
||||
**完成阶段**: ${current_phase}
|
||||
**完成项数**: ${done_items}/${total_items}
|
||||
|
||||
请大龙虾(项目经理):
|
||||
1. 审查本阶段成果
|
||||
2. 分析整体项目进度
|
||||
3. 决定下一步安排(编写下阶段清单、指派执行者)
|
||||
HANDOFF_EOF
|
||||
gh issue comment "$number" -R "$REPO" --body-file "$tmphandoff" 2>/dev/null
|
||||
rm -f "$tmphandoff"
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "🎯 处理第 $section_item_num/$total_items 项: $next_item"
|
||||
|
||||
tmpstart=$(mktemp /tmp/issue-start-XXXXXX.md)
|
||||
cat > "$tmpstart" << START_EOF
|
||||
🔄 **${BOT}** 开始处理第 **$section_item_num/$total_items** 项:
|
||||
|
||||
> $next_item
|
||||
|
||||
⏰ $TIMESTAMP
|
||||
START_EOF
|
||||
gh issue comment "$number" -R "$REPO" --body-file "$tmpstart" 2>/dev/null
|
||||
rm -f "$tmpstart"
|
||||
|
||||
# ── 4. 构建 prompt 给 bot ──
|
||||
phase_instruction=""
|
||||
case "$current_phase" in
|
||||
design)
|
||||
phase_instruction="你当前处于【设计阶段】。请对以下需求进行详细的技术设计:包括数据模型、API 接口设计、技术方案、架构说明。输出要具体、可执行。"
|
||||
;;
|
||||
coding)
|
||||
phase_instruction="你当前处于【编码阶段】。请按照设计方案完成以下编码任务。代码必须完整、可运行、有注释。所有代码文件写到工作目录。"
|
||||
;;
|
||||
review)
|
||||
phase_instruction="你当前处于【测试/审查阶段】。请检查以下测试条目,验证功能是否正确,输出测试报告。如果发现问题,详细说明问题位置和修复建议。"
|
||||
;;
|
||||
*)
|
||||
phase_instruction="请认真完成以下任务。"
|
||||
;;
|
||||
esac
|
||||
|
||||
task_prompt="你是 ${BOT},角色是 ${ROLE}。
|
||||
|
||||
## 当前任务
|
||||
项目: ${title} (Issue #${number})
|
||||
当前阶段: ${current_phase}
|
||||
当前进度: ${done_items}/${total_items} 已完成
|
||||
|
||||
## 本次要处理的项目(第 ${section_item_num} 项)
|
||||
${next_item}
|
||||
|
||||
## 工作指引
|
||||
${phase_instruction}
|
||||
|
||||
## 项目完整背景
|
||||
${body}
|
||||
|
||||
## 重要规则
|
||||
1. 你只需处理上面【第 ${section_item_num} 项】,不要做其他项
|
||||
2. 完成后给出完整的交付物
|
||||
3. 如果遇到问题无法解决,说明具体卡在哪里
|
||||
4. 如果学到了新技能,在 /home/node/.openclaw/skills/ 创建 .md 记录"
|
||||
|
||||
echo "🧠 发送任务到 AI..."
|
||||
start_time=$(date +%s)
|
||||
|
||||
result=$(openclaw agent \
|
||||
--message "$task_prompt" \
|
||||
--session-id "github-task-$number-item-$next_item_num" \
|
||||
--thinking medium \
|
||||
--timeout 300 \
|
||||
--json 2>&1) || true
|
||||
|
||||
end_time=$(date +%s)
|
||||
duration=$(( end_time - start_time ))
|
||||
|
||||
response=$(echo "$result" | jq -r '.response // empty' 2>/dev/null)
|
||||
if [ -z "$response" ]; then
|
||||
response=$(echo "$result" | jq -r '.text // empty' 2>/dev/null)
|
||||
fi
|
||||
if [ -z "$response" ]; then
|
||||
response=$(echo "$result" | jq -r '.content // empty' 2>/dev/null)
|
||||
fi
|
||||
if [ -z "$response" ]; then
|
||||
response="$result"
|
||||
fi
|
||||
|
||||
# ── 5. 代码推送 ──
|
||||
commit_url=""
|
||||
if [ -d "$CODE_REPO_DIR/.git" ]; then
|
||||
task_dir="$CODE_REPO_DIR/task-${number}"
|
||||
mkdir -p "$task_dir"
|
||||
|
||||
has_code=false
|
||||
for f in "$WORKSPACE"/*.py "$WORKSPACE"/*.js "$WORKSPACE"/*.ts "$WORKSPACE"/*.html \
|
||||
"$WORKSPACE"/*.css "$WORKSPACE"/*.json "$WORKSPACE"/*.go "$WORKSPACE"/*.rs \
|
||||
"$WORKSPACE"/*.java "$WORKSPACE"/*.swift "$WORKSPACE"/*.sh "$WORKSPACE"/*.md \
|
||||
"$WORKSPACE"/*.yaml "$WORKSPACE"/*.yml "$WORKSPACE"/*.toml "$WORKSPACE"/*.sql \
|
||||
"$WORKSPACE"/*.jsx "$WORKSPACE"/*.tsx "$WORKSPACE"/*.vue "$WORKSPACE"/*.wxml \
|
||||
"$WORKSPACE"/*.wxss; do
|
||||
if [ -f "$f" ]; then
|
||||
cp "$f" "$task_dir/" 2>/dev/null
|
||||
has_code=true
|
||||
fi
|
||||
done
|
||||
|
||||
for d in "$WORKSPACE"/*/; do
|
||||
if [ -d "$d" ] && [ "$(basename "$d")" != "." ]; then
|
||||
dname=$(basename "$d")
|
||||
case "$dname" in
|
||||
node_modules|.git|__pycache__|.openclaw|.cache|plugins) continue ;;
|
||||
esac
|
||||
cp -r "$d" "$task_dir/" 2>/dev/null
|
||||
has_code=true
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$has_code" = true ]; then
|
||||
cd "$CODE_REPO_DIR"
|
||||
git add -A 2>/dev/null
|
||||
commit_msg="task-${number} item-${next_item_num}: ${next_item}
|
||||
|
||||
执行者: ${BOT} (${ROLE})
|
||||
进度: ${next_item_num}/${total_items}
|
||||
耗时: ${duration}s"
|
||||
git commit -m "$commit_msg" 2>/dev/null
|
||||
git push origin main 2>/dev/null && echo "📦 代码已推送"
|
||||
commit_hash=$(git rev-parse --short HEAD 2>/dev/null)
|
||||
commit_url="https://github.com/${GITHUB_OWNER}/${CODE_REPO}/commit/${commit_hash}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── 6. 技能推送 ──
|
||||
skills_url=""
|
||||
if [ -d "$SKILLS_REPO_DIR/.git" ]; then
|
||||
has_new_skills=false
|
||||
for f in "$SKILLS_DIR"/*.md; do
|
||||
if [ -f "$f" ]; then
|
||||
fname=$(basename "$f")
|
||||
if [ "$fname" = "github-task-worker.md" ]; then continue; fi
|
||||
if [ ! -f "$SKILLS_REPO_DIR/$fname" ] || ! diff -q "$f" "$SKILLS_REPO_DIR/$fname" >/dev/null 2>&1; then
|
||||
cp "$f" "$SKILLS_REPO_DIR/" 2>/dev/null
|
||||
has_new_skills=true
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$has_new_skills" = true ]; then
|
||||
cd "$SKILLS_REPO_DIR"
|
||||
git add -A 2>/dev/null
|
||||
git commit -m "skill: 新增/更新技能 (task-${number} item-${next_item_num})" 2>/dev/null
|
||||
git push origin main 2>/dev/null && echo "🧠 技能已推送"
|
||||
skill_hash=$(git rev-parse --short HEAD 2>/dev/null)
|
||||
skills_url="https://github.com/${GITHUB_OWNER}/${SKILLS_REPO}/commit/${skill_hash}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── 7. 更新 Issue body:勾选已完成项 + 更新当前阶段进度 ──
|
||||
new_done=$((done_items + 1))
|
||||
|
||||
# 用全局 item_num 定位要勾选的行(兼容有编号和无编号格式)
|
||||
updated_body=$(echo "$body" | awk -v item_num="$next_item_num" '
|
||||
BEGIN { count = 0 }
|
||||
/^- \[[ x]\] / {
|
||||
count++
|
||||
if (count == item_num) {
|
||||
sub(/^- \[ \]/, "- [x]")
|
||||
}
|
||||
}
|
||||
{ print }
|
||||
')
|
||||
|
||||
# 更新进度计数(兼容多种格式)
|
||||
updated_body=$(echo "$updated_body" | sed "s/进度: [0-9]*\/[0-9]*/进度: ${new_done}\/${total_items}/")
|
||||
if [ "$current_phase" = "design" ]; then
|
||||
updated_body=$(echo "$updated_body" | sed "s/设计: [0-9]*\/[0-9]*/设计: ${new_done}\/${total_items}/")
|
||||
elif [ "$current_phase" = "coding" ]; then
|
||||
updated_body=$(echo "$updated_body" | sed "s/编码: [0-9]*\/[0-9]*/编码: ${new_done}\/${total_items}/")
|
||||
elif [ "$current_phase" = "review" ]; then
|
||||
updated_body=$(echo "$updated_body" | sed "s/测试: [0-9]*\/[0-9]*/测试: ${new_done}\/${total_items}/")
|
||||
fi
|
||||
|
||||
tmpbody=$(mktemp /tmp/issue-body-XXXXXX.md)
|
||||
printf '%s' "$updated_body" > "$tmpbody"
|
||||
gh issue edit "$number" -R "$REPO" --body-file "$tmpbody" 2>/dev/null
|
||||
edit_rc=$?
|
||||
rm -f "$tmpbody"
|
||||
if [ $edit_rc -ne 0 ]; then
|
||||
echo "⚠️ Issue body 更新失败 (rc=$edit_rc)"
|
||||
fi
|
||||
echo "📝 已勾选第 $section_item_num 项,进度: $new_done/$total_items"
|
||||
|
||||
# ── 8. 评论交付结果 ──
|
||||
max_len=60000
|
||||
if [ ${#response} -gt $max_len ]; then
|
||||
response="${response:0:$max_len}
|
||||
|
||||
...(输出过长,已截断)"
|
||||
fi
|
||||
|
||||
finish_time=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
extra_section=""
|
||||
if [ -n "$commit_url" ]; then
|
||||
extra_section="
|
||||
**📦 代码已提交**: [查看 commit](${commit_url})"
|
||||
fi
|
||||
if [ -n "$skills_url" ]; then
|
||||
extra_section="${extra_section}
|
||||
**🧠 技能已更新**: [查看 commit](${skills_url})"
|
||||
fi
|
||||
|
||||
tmpcomment=$(mktemp /tmp/issue-comment-XXXXXX.md)
|
||||
cat > "$tmpcomment" << COMMENT_EOF
|
||||
## ✅ 第 ${section_item_num}/${total_items} 项完成
|
||||
|
||||
**执行者**: ${BOT} (${ROLE})
|
||||
**完成项**: ${next_item}
|
||||
**进度**: ${new_done}/${total_items}
|
||||
**耗时**: ${duration} 秒
|
||||
**完成时间**: ${finish_time}${extra_section}
|
||||
|
||||
---
|
||||
|
||||
${response}
|
||||
COMMENT_EOF
|
||||
gh issue comment "$number" -R "$REPO" --body-file "$tmpcomment" 2>/dev/null
|
||||
comment_rc=$?
|
||||
rm -f "$tmpcomment"
|
||||
if [ $comment_rc -ne 0 ]; then
|
||||
echo "⚠️ 完成评论发布失败 (rc=$comment_rc)"
|
||||
fi
|
||||
|
||||
# ── 9. 判断是否全部完成 → 交接给大龙虾 ──
|
||||
if [ $new_done -ge $total_items ]; then
|
||||
echo "🎉 当前阶段所有项目已完成!交接给大龙虾"
|
||||
|
||||
phase_label="设计"
|
||||
[ "$current_phase" = "coding" ] && phase_label="编码"
|
||||
[ "$current_phase" = "review" ] && phase_label="测试"
|
||||
|
||||
# 移除当前 worker 标签,加上 role:dalongxia
|
||||
gh issue edit "$number" -R "$REPO" \
|
||||
--remove-label "role:${BOT}" \
|
||||
--add-label "role:dalongxia" 2>/dev/null
|
||||
|
||||
tmphandoff=$(mktemp /tmp/issue-handoff-XXXXXX.md)
|
||||
cat > "$tmphandoff" << HANDOFF_EOF
|
||||
🦞 **${phase_label}阶段全部完成** ($total_items/$total_items) — 交接给大龙虾
|
||||
|
||||
**执行者**: ${BOT}
|
||||
**完成阶段**: ${current_phase}
|
||||
**完成项数**: ${total_items}/${total_items}
|
||||
|
||||
请大龙虾(项目经理):
|
||||
1. 审查本阶段成果
|
||||
2. 分析整体项目进度
|
||||
3. 决定下一步安排(编写下阶段清单、指派执行者)
|
||||
HANDOFF_EOF
|
||||
gh issue comment "$number" -R "$REPO" --body-file "$tmphandoff" 2>/dev/null
|
||||
rm -f "$tmphandoff"
|
||||
else
|
||||
echo "📌 还剩 $((total_items - new_done)) 项未完成,等待下次轮询"
|
||||
fi
|
||||
|
||||
echo "✅ 第 $section_item_num/$total_items 项处理完成 (耗时 ${duration}s)"
|
||||
Reference in New Issue
Block a user