04-运维 · 01 日志与监控
预计阅读:12 分钟 适用版本:公开稳定包 OpenClaw 2026.5.2;作者端已验证 2026.5.7 · 最后审核:2026-05-09 前置:04-运维/00-健康检查 目标:理清 OpenClaw 几十个日志文件的分类 / 读取顺序 / 轮转策略 / 告警接入
为什么日志需要专门一章
Section titled “为什么日志需要专门一章”长期运行后,~/.openclaw/logs/ 很容易累积成数十个日志文件、数十 MB 到数百 MB。不分层管理会出现:
- 找不到该看哪个 —— 飞书不回复时,
gateway.err.log还是daily-digest.launchd.err.log? - 磁盘爆 —— 没 rotate 的日志一个月涨到几百 MB
- 告警失效 —— ERROR 淹在正常输出里,没人发现
- 信息不对称 —— 你看日志 A,agent 只能看到日志 B
按”谁在写 × 记什么”两个维度分:
| 层 | 代表文件 | 谁写 | 看什么 |
|---|---|---|---|
| Gateway 主日志 | gateway.log / gateway.err.log | OpenClaw gateway | agent 对话 / 工具调用 / 错误 |
| Launchd 任务日志 | *.launchd.log / *.launchd.err.log | 你配的 cron 脚本 | 定时任务执行结果 |
| 维护脚本日志 | daily-maintenance.log / consolidation.log / backup.log | 运维脚本自己 | 具体运维动作 |
| 告警日志 | alerts.log / alert-notify.log | 告警分发脚本 | 发过哪些告警 |
| 审计日志 | audit.log / config-audit.jsonl | 配置变更钩子 | 谁什么时候改了什么配置 |
| 失败报告 | failure-report-YYYYMMDD-HHMMSS.txt | 自愈脚本触发时 | 详细事故快照 |
读日志的顺序
Section titled “读日志的顺序”不要从 gateway.log 开始(文件大、噪声多)。按这个顺序:
第 1 步:alerts.log 或 alert-notify.log → 最近一次告警发生了什么?
第 2 步:对应组件的独立日志(如 daily-digest.err.log) → 那个告警的来源脚本里出了什么?
第 3 步:gateway.err.log(过滤时间段) → 同时间段 gateway 本身有没有异常?
第 4 步:audit.log → 那段时间有配置改动吗?四步走完,90% 的故障能定位。
不轮转 = 系统自毁。作者的 rotate 策略:
| 文件 | rotate 策略 | 脚本 |
|---|---|---|
gateway.log | 按大小(10MB)切,保留 5 份 | logs-rotate.py |
gateway.err.log | 按大小(5MB)切,保留 10 份 | logs-rotate.py |
*.launchd.log | 按天切,保留 14 天 | rotate-logs.sh |
audit.log / config-audit.jsonl | 按周切,永久保留归档 | rotate-weekly-audit.py |
典型 rotate 脚本骨架
Section titled “典型 rotate 脚本骨架”#!/bin/bash# rotate-logs.sh —— 按天切割LOG_DIR="$HOME/.openclaw/logs"DATE=$(date '+%Y%m%d')
for f in "$LOG_DIR"/*.launchd.log; do [ -f "$f" ] || continue size=$(stat -f %z "$f") if [ "$size" -gt 1048576 ]; then # > 1MB 才切 mv "$f" "$LOG_DIR/archive/$(basename "$f").$DATE" touch "$f" # 新文件 fidone
# 删 14 天前的归档find "$LOG_DIR/archive/" -mtime +14 -delete作者用 launchd 每天凌晨 3 点跑一次。
-
redirect-to-same-file truncate:
grep 'pattern' file.log > file.log会先 truncate,grep 读空。正确:Terminal window grep 'pattern' file.log > file.tmp && mv file.tmp file.log -
rotate 时进程还在写:直接 mv 的话 gateway 的 fd 还指向老文件。正确做法是重启 gateway 或用
copytruncate风格:Terminal window cp gateway.log gateway.log.archive: > gateway.log # truncate 原文件(fd 仍有效) -
audit 日志不能 rotate:这些是合规证据。作者策略是 audit 只归档(移到
archive/+ 打 tar.gz),不删除。
监控:从”看日志”升级到”日志推过来”
Section titled “监控:从”看日志”升级到”日志推过来””被动看日志在生产系统里行不通。让日志主动告警的两种思路:
思路 1:规则匹配 + 通知
Section titled “思路 1:规则匹配 + 通知”每 N 分钟扫描关键日志,匹配告警规则 → 发飞书。
# 伪代码:每 5 分钟tail -1000 ~/.openclaw/logs/gateway.err.log \ | grep -E 'ERROR|FATAL|OutOfMemory|invalid signature' \ | while read line; do # 写入 alerts.log echo "[$(date)] $line" >> ~/.openclaw/logs/alerts.log # 发飞书卡片 bash ~/.openclaw/scripts/send-alert-card.sh "$line" done关键:规则要保守。早期容易把”正常 WARN”也告警,噪声大到没人看。宁愿漏报也不要骚扰警告。
思路 2:事件驱动(更好但更复杂)
Section titled “思路 2:事件驱动(更好但更复杂)”不扫日志,而是在脚本里主动写告警:
# daily-digest.py 里try: result = check_gateway_health()except Exception as e: write_alert(level='ERROR', source='daily-digest', msg=str(e)) raisewrite_alert 统一写 alerts.log + 触发飞书推送。
好处:源头可控、level 精确。
代价:每个脚本都要集成 write_alert 库。
告警分级(三级)
Section titled “告警分级(三级)”参考 04-运维/00-健康检查 的三档色:
| 级别 | 通道 | 示例 |
|---|---|---|
| 🔴 CRITICAL | 飞书 + 系统通知(osascript)+ 可能的短信 | Gateway 离线 > 10 分钟、credentials 权限被改 |
| 🟡 WARN | 飞书(淡色卡片) | fragments 400+、磁盘 > 5GB |
| 🟢 INFO | 写 alerts.log 不推送 | 正常心跳、daily-digest 生成完成 |
不要给自己发绿色通知。记录即可,积累起来用于”这周系统没有异常”的周审报告。
告警风暴抑制
Section titled “告警风暴抑制”现象:一个故障瞬间触发 50 条告警(每 5 分钟一次 × N 小时)。
抑制策略:
- 去重窗口:同一种告警 1 小时内最多发 1 次飞书
- 聚合:连续 N 条同类告警 → 升级成”该问题持续中 2 小时”
- 收口:问题恢复后发一条”已恢复”,关闭该事件
作者的 alert-notify.log 就记录了每次告警的 dedup key + 发送次数,防止风暴。
审计日志:不可省的合规层
Section titled “审计日志:不可省的合规层”audit.log 和 config-audit.jsonl 记录:
- 谁(哪个 agent)什么时候改了什么配置
- credentials 的读取记录(不是内容,是”被读了几次”)
- 派发操作的完整链(main → planner → minsu)
为什么重要:
- 出事故时能倒查”到底哪一步改坏的”
- 多 agent 系统里很容易搞不清”谁动了这个文件”
- 合规 / 安全审计需要
不能删。rotate 只归档,保留 6 个月以上。
JSONL 格式的优势
Section titled “JSONL 格式的优势”config-audit.jsonl 每行一条结构化事件:
{"ts":"2026-04-17T09:30:12+08:00","agent":"main","action":"config.write","target":"openclaw.json","diff_summary":"added feishu.enabled=false"}{"ts":"2026-04-17T09:30:15+08:00","agent":"main","action":"gateway.restart","trigger":"config.change"}用 jq 查很方便:
jq 'select(.agent == "main" and .ts > "2026-04-17T00:00:00")' config-audit.jsonl和 agent 记忆的关系
Section titled “和 agent 记忆的关系”日志 ≠ 记忆:
| 日志 | 记忆 |
|---|---|
| 系统写的,agent 不直接读 | agent 主动写,agent 主动读 |
| 事件流水,不解释 | 有摘要、有结论、有情感 |
| rotate 会丢 | 理论上永久(除非明确 forget) |
什么时候从日志提炼到记忆:
- 某个故障重复出现 → 把排障路径写进
memory/YYYY-MM-DD-<故障名>.md - 某个运维决策有争议 → 写入
shared/MEMORY.md - 发现了新的监控指标 → 更新
shared/AGENTS.md的健康检查章节
这一步作者用 reflector agent 定期自动做。
不要让 ~/.openclaw/logs/ 世界可读:
chmod 700 ~/.openclaw/logs# 单个敏感文件chmod 600 ~/.openclaw/logs/audit.logchmod 600 ~/.openclaw/logs/config-audit.jsonl为什么:某些日志会意外包含 appId / open_id / 部分响应内容,权限收严是底线。
监控仪表盘(如果你想做得更讲究)
Section titled “监控仪表盘(如果你想做得更讲究)”可选:把关键指标推到外部(你的设备 / 家里的 NAS / 云)。
| 方式 | 复杂度 | 适用 |
|---|---|---|
| daily-digest 卡片 | 低 | 大多数个人用户 |
| 自己写 HTML dashboard,定时生成 | 中 | 想看趋势图 |
| Grafana / Prometheus | 高 | 生产级 / 多机器 |
作者目前就用 daily-digest 卡片 + 每月手动看一次 audit log 趋势。足够。
| 检查项 | 怎么验 |
|---|---|
| 日志分层 | ls ~/.openclaw/logs/ | wc -l 应 > 20,各类都有 |
| rotate 正常 | ls ~/.openclaw/logs/archive/ 应有归档文件 |
| 告警路由 | 人为制造一条 ERROR,应在 5 分钟内收到飞书告警 |
| 审计日志格式 | jq '.' config-audit.jsonl | head 应不报错 |
| 告警去重 | 连续制造同类 ERROR 3 次,应只收 1 条告警 |
| 权限收严 | ls -l ~/.openclaw/logs/audit.log 应是 -rw------- |
- 02-升级流程 —— 升级时日志怎么看
- 03-备份与恢复 —— 日志的备份策略
- 05-排障/00-常见问题 —— 具体日志关键字和诊断路径
本章准确性保证 日志清单、rotate 脚本名、告警分级都基于作者
~/.openclaw/logs/与~/.openclaw/scripts/的真实文件抽象而来;具体日志数量会随安装包版本、启用的 agent 和定时任务变化。审计日志 JSONL 格式是作者在用的真实结构。