监控与可观测性:结构化日志、健康检查与告警配置
第41章 监控与可观测性:结构化日志、健康检查与告警配置
41.1 AI Agent 的可观测性挑战
传统软件的行为基本可以预测:给定相同输入,输出稳定一致。然而 AI Agent 的运行方式根本不同——它的决策由大语言模型驱动,同一条指令在不同时间、不同上下文中可能走向完全不同的工具调用路径。这种非确定性使得传统的监控思路在 Agent 场景下严重失效。
41.1.1 为什么 AI Agent 更难监控
路径爆炸:一个简单的"帮我整理邮件"指令可能触发 3 到 20 个工具调用,具体路径取决于当前邮箱状态、模型版本、上下文窗口长度。你无法像传统 API 那样只监控一个固定的调用链。
错误的语义模糊性:当工具返回 HTTP 200 但内容是"找不到相关数据",Agent 可能正常处理,也可能进入无限重试。传统的错误率指标无法捕捉这类语义层面的失败。
时间尺度跨越:一个 Session 可能持续 30 秒(简单查询),也可能持续 4 小时(复杂重构任务)。固定时间窗口的监控指标在这里意义有限。
资源消耗不可预测:LLM 调用的 Token 消耗与 Context Compaction 频率直接影响成本和延迟,而这些在任务开始前难以估计。
工具副作用不可逆:Agent 删除文件、发送邮件、部署服务的操作是单向的。监控必须能在问题发生前发出告警,而不仅仅是事后记录。
41.1.2 OpenClaw 的可观测性设计哲学
OpenClaw 采用结构化日志优先的设计:所有运行时事件以 JSON 格式输出,每个字段都有固定语义,便于机器解析和聚合。健康检查端点提供实时状态快照,而非依赖日志的延迟聚合。告警规则基于业务语义(连续失败、Session 异常),而非简单的技术阈值(CPU > 80%)。
这三个层次共同构成了一套适合 AI Agent 的可观测性体系:日志(发生了什么)、健康检查(现在状态如何)、告警(需要立即响应什么)。
41.2 logging 配置详解
OpenClaw 的日志行为通过 openclaw.json 的 logging 节点控制。
41.2.1 完整配置结构
{
"logging": {
"level": "info",
"format": "json",
"output": {
"console": {
"enabled": true,
"colorize": false
},
"file": {
"enabled": true,
"path": "~/.openclaw/logs/openclaw.log",
"rotation": {
"maxSize": "100MB",
"maxFiles": 7,
"compress": true
}
},
"syslog": {
"enabled": false,
"facility": "local0",
"host": "127.0.0.1",
"port": 514
}
},
"fields": {
"service": "openclaw",
"environment": "production",
"version": "${OPENCLAW_VERSION}"
},
"sampling": {
"enabled": false,
"rate": 0.1,
"excludeLevels": ["error", "warn"]
}
}
}
41.2.2 日志级别选择
| 级别 | 适用场景 | 日志量估算 |
|---|---|---|
debug |
本地开发、问题排查 | 极高(每工具调用 10-50 条) |
info |
生产默认,记录关键事件 | 中等(每工具调用 3-8 条) |
warn |
只关注潜在问题 | 低(仅异常情况) |
error |
只记录失败 | 极低(仅告警用途) |
生产环境建议:默认使用 info 级别。在排查特定 Session 时,可通过以下命令临时切换,无需重启 Gateway:
# 临时升级到 debug 级别(重启后恢复)
openclaw config set logging.level debug
# 仅对特定 Agent 开启 debug
openclaw config set logging.agentFilter "my-agent-id:debug"
# 恢复默认
openclaw config set logging.level info
41.2.3 输出路径规划
生产推荐目录结构:
~/.openclaw/logs/
├── openclaw.log # 当前日志文件(滚动写入)
├── openclaw.2026-04-25.gz # 压缩归档(自动生成)
├── openclaw.2026-04-24.gz
└── gateway-access.log # Gateway HTTP 访问日志(独立)
日志轮转参数说明:
maxSize: "100MB"— 单文件超过 100MB 触发轮转,适合高频 Agent 部署。个人用户可降至20MBmaxFiles: 7— 保留 7 天,满足大多数事后审计需求。合规场景可延长至 30compress: true— 归档文件使用 gzip 压缩,节省约 70% 磁盘空间
41.2.4 结构化日志字段示例
一条典型的工具调用日志记录如下:
{
"timestamp": "2026-04-26T09:23:41.882Z",
"level": "info",
"event": "tool_call_completed",
"agentId": "agent_7f3k2m",
"sessionId": "sess_9a1b3c",
"tool": "bash",
"duration": 342,
"tokenUsage": {
"input": 1204,
"output": 387
},
"exitCode": 0,
"error": null,
"service": "openclaw",
"environment": "production",
"version": "2026.4.22"
}
一条 Session 启动日志:
{
"timestamp": "2026-04-26T09:23:40.001Z",
"level": "info",
"event": "session_started",
"agentId": "agent_7f3k2m",
"sessionId": "sess_9a1b3c",
"trigger": "cron",
"model": "claude-opus-4-5",
"thinkingMode": "standard",
"maxTokenBudget": 50000,
"parentSessionId": null,
"service": "openclaw"
}
一条工具失败日志:
{
"timestamp": "2026-04-26T09:24:11.543Z",
"level": "error",
"event": "tool_call_failed",
"agentId": "agent_7f3k2m",
"sessionId": "sess_9a1b3c",
"tool": "web_fetch",
"duration": 30001,
"error": {
"code": "TIMEOUT",
"message": "Request exceeded 30s timeout",
"retryCount": 2,
"willRetry": false
},
"service": "openclaw"
}
41.3 健康检查端点解析
Gateway 在本地暴露健康检查端点,用于快速判断服务状态。
41.3.1 端点地址
http://127.0.0.1:18789/health
默认仅监听本地回环地址,不对外网暴露。如需在 CI/CD 或监控系统中远程访问,需在配置中显式开启:
{
"gateway": {
"health": {
"host": "0.0.0.0",
"port": 18789,
"auth": {
"enabled": true,
"token": "${HEALTH_CHECK_TOKEN}"
}
}
}
}
41.3.2 响应字段完整解析
{
"status": "healthy",
"version": "2026.4.22",
"uptime": 86432,
"gateway": {
"status": "running",
"pid": 12847,
"port": 18789,
"connections": {
"active": 3,
"idle": 12,
"total": 58204
}
},
"sessions": {
"active": 2,
"queued": 0,
"completed24h": 147,
"failed24h": 3,
"successRate24h": 0.9796
},
"models": {
"current": "claude-opus-4-5",
"available": ["claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5"],
"lastModelCallMs": 1843
},
"resources": {
"memoryUsedMB": 412,
"memoryLimitMB": 2048,
"cpuPercent": 12.4,
"diskAvailableGB": 48.3
},
"tools": {
"registered": 28,
"errorsLastHour": 1,
"errorRate1h": 0.012
},
"compaction": {
"count24h": 7,
"lastCompactionAt": "2026-04-26T08:41:12Z"
},
"timestamp": "2026-04-26T09:30:00Z"
}
字段监控价值说明:
status:顶层健康状态,值为healthy/degraded/unhealthy。降级(degraded)表示部分功能受损但 Gateway 仍在运行sessions.successRate24h:过去 24 小时 Session 成功率,低于 0.95 时应触发告警sessions.failed24h:绝对失败数,与成功率结合判断(低流量时失败率可能虚高)resources.memoryUsedMB / memoryLimitMB:内存使用比例,超过 85% 建议重启或调整内存上限tools.errorRate1h:最近一小时工具错误率,超过 0.05(5%)应调查compaction.count24h:Context Compaction 次数,高频触发(>20/天)说明任务规模与 Token 预算不匹配models.lastModelCallMs:最后一次 LLM 调用的响应时间,可用于检测 API 降速
41.3.3 使用 curl 进行健康检查
# 基础检查
curl -s http://127.0.0.1:18789/health | jq '.status'
# 检查 Session 成功率
curl -s http://127.0.0.1:18789/health | jq '.sessions.successRate24h'
# 检查内存使用
curl -s http://127.0.0.1:18789/health | \
jq '(.resources.memoryUsedMB / .resources.memoryLimitMB * 100 | round | tostring) + "% memory used"'
# 用于 Kubernetes readiness probe
curl -sf http://127.0.0.1:18789/health && echo "READY" || echo "NOT READY"
41.4 关键日志字段的监控价值
41.4.1 字段索引与含义
| 字段 | 类型 | 监控价值 |
|---|---|---|
timestamp |
ISO 8601 字符串 | 精确到毫秒,用于延迟计算和时序关联 |
level |
枚举 | 过滤严重事件,error 级别应立即关注 |
agentId |
字符串 | 跨 Session 追踪同一 Agent 的行为模式 |
sessionId |
字符串 | 将单次任务的所有日志归组,根因分析的核心维度 |
tool |
字符串 | 识别高错误率工具,定位配置或权限问题 |
duration |
整数(毫秒) | P99 延迟分析,检测工具性能退化 |
error.code |
字符串 | 错误分类(TIMEOUT/AUTH_FAIL/RATE_LIMIT 等) |
error.retryCount |
整数 | 高重试次数说明上游不稳定 |
tokenUsage.input |
整数 | Context 增长速度,预判 Compaction 触发点 |
tokenUsage.output |
整数 | 模型输出量,与质量评估相关 |
41.4.2 字段组合查询示例
使用 jq 从日志文件中提取有价值的分析维度:
# 按工具统计错误率
cat ~/.openclaw/logs/openclaw.log | \
jq -r 'select(.event == "tool_call_failed") | .tool' | \
sort | uniq -c | sort -rn
# 查找最慢的工具调用(超过 10 秒)
cat ~/.openclaw/logs/openclaw.log | \
jq 'select(.duration > 10000) | {tool, duration, sessionId}' | \
jq -s 'sort_by(-.duration) | .[0:10]'
# 计算特定 Session 的总 Token 消耗
SESSION_ID="sess_9a1b3c"
cat ~/.openclaw/logs/openclaw.log | \
jq --arg sid "$SESSION_ID" \
'select(.sessionId == $sid and .tokenUsage != null) | .tokenUsage.input + .tokenUsage.output' | \
paste -sd+ | bc
# 找出连续失败的 Session
cat ~/.openclaw/logs/openclaw.log | \
jq -r 'select(.event == "session_failed") | .sessionId' | \
awk 'seen[$0]++ {print $0 " appeared " seen[$0] " times"}' | head -10
41.5 10个关键指标及阈值参考
41.5.1 指标定义
| 指标名称 | 计算方式 | 警告阈值 | 严重阈值 | 说明 |
|---|---|---|---|---|
| Session 成功率 | 成功数/总数(24h滑动窗口) | < 0.95 | < 0.90 | 核心业务健康度 |
| 工具错误率 | 工具失败数/工具调用总数(1h) | > 0.03 | > 0.08 | 工具层稳定性 |
| P99 工具延迟 | 99% 分位 duration 值 | > 5000ms | > 15000ms | 工具调用性能 |
| Compaction 频率 | count/24h 每个 Agent | > 10 | > 25 | Token 预算匹配度 |
| LLM 响应时间 | 最后一次 modelCallMs | > 3000ms | > 8000ms | API 健康状态 |
| Token 每 Session | 平均 tokenUsage.input+output | > 40000 | > 80000 | 成本控制 |
| 内存使用比例 | usedMB/limitMB | > 0.75 | > 0.90 | 资源容量规划 |
| Gateway 重启次数 | event=gateway_restart(24h) | > 1 | > 3 | 稳定性指标 |
| 活跃连接数 | connections.active | > 50 | > 100 | 并发容量 |
| 高重试工具调用 | retryCount > 2 的比例 | > 0.05 | > 0.15 | 上游依赖稳定性 |
41.5.2 指标的业务解读
Session 成功率是最重要的业务指标。低于 95% 通常意味着某个常用工具存在配置问题,或 LLM 无法正确理解 SKILL.md 中的指令。优先排查最近变更了什么。
Compaction 频率是隐藏的性能信号。每次 Compaction 都会截断上下文,可能导致 Agent 遗忘之前的操作结果,从而产生重复工作或逻辑错误。频率过高说明任务设计时没有充分考虑 Token 预算。
Token 每 Session 平均值与 LLM API 成本直接挂钩。超过 8 万 Token 的 Session 意味着可能存在无效的上下文膨胀,例如将完整的大文件内容注入 Context 而非使用工具按需读取。
41.6 与 Prometheus / Grafana 集成
OpenClaw 的结构化日志是集成现有监控栈的天然接口。推荐使用 prometheus-json-exporter 桥接健康检查端点,并使用 Loki 或 Vector 处理结构化日志。
41.6.1 prometheus-json-exporter 配置
安装:
# macOS
brew install prometheus-json-exporter
# 或使用 Docker
docker run -d -p 7979:7979 \
-v $(pwd)/json_exporter.yml:/etc/json_exporter/config.yml \
prometheuscommunity/json-exporter \
--config.file /etc/json_exporter/config.yml
json_exporter.yml 配置(采集 OpenClaw 健康检查端点):
modules:
openclaw:
metrics:
- name: openclaw_session_success_rate
type: gauge
help: "Session success rate over last 24 hours"
path: "{ .sessions.successRate24h }"
- name: openclaw_session_active
type: gauge
help: "Currently active sessions"
path: "{ .sessions.active }"
- name: openclaw_tool_error_rate_1h
type: gauge
help: "Tool error rate in the last hour"
path: "{ .tools.errorRate1h }"
- name: openclaw_memory_used_mb
type: gauge
help: "Gateway memory used in MB"
path: "{ .resources.memoryUsedMB }"
- name: openclaw_memory_limit_mb
type: gauge
help: "Gateway memory limit in MB"
path: "{ .resources.memoryLimitMB }"
- name: openclaw_compaction_count_24h
type: gauge
help: "Context compaction events in last 24 hours"
path: "{ .compaction.count24h }"
- name: openclaw_last_model_call_ms
type: gauge
help: "Last LLM API call latency in milliseconds"
path: "{ .models.lastModelCallMs }"
- name: openclaw_gateway_uptime_seconds
type: counter
help: "Gateway uptime in seconds"
path: "{ .uptime }"
在 Prometheus scrape_configs 中添加:
scrape_configs:
- job_name: 'openclaw'
metrics_path: /probe
params:
module: [openclaw]
target: ['http://127.0.0.1:18789/health']
static_configs:
- targets: ['localhost:7979']
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- target_label: __address__
replacement: 'localhost:7979'
41.6.2 Vector 日志采集配置
使用 Vector 将 OpenClaw 的 JSON 日志采集到 Loki 或 Elasticsearch:
# vector.toml
[sources.openclaw_logs]
type = "file"
include = ["~/.openclaw/logs/openclaw.log"]
read_from = "beginning"
[transforms.parse_openclaw]
type = "remap"
inputs = ["openclaw_logs"]
source = '''
. = parse_json!(string!(.message))
.source = "openclaw"
'''
[transforms.filter_errors]
type = "filter"
inputs = ["parse_openclaw"]
condition = '.level == "error" || .level == "warn"'
[sinks.loki]
type = "loki"
inputs = ["parse_openclaw"]
endpoint = "http://localhost:3100"
labels.job = "openclaw"
labels.level = "{{ level }}"
labels.agent_id = "{{ agentId }}"
encoding.codec = "json"
[sinks.error_alerts]
type = "http"
inputs = ["filter_errors"]
uri = "http://alertmanager:9093/api/v1/alerts"
encoding.codec = "json"
41.6.3 Grafana Dashboard 核心面板
推荐的 Dashboard 布局(4行布局):
行1:总览(Session 成功率 / 活跃 Session / 工具错误率 / Gateway 运行时间)
行2:性能(LLM 响应延迟趋势 / P99 工具延迟 / Token 消耗热图)
行3:资源(内存使用率 / Compaction 频率趋势 / 连接数)
行4:错误详情(错误日志流 / 按工具的错误分布 / 高重试调用)
关键 PromQL 查询:
# Session 成功率(低于 0.95 高亮显示)
openclaw_session_success_rate < 0.95
# 内存使用比例
openclaw_memory_used_mb / openclaw_memory_limit_mb
# 工具错误率变化趋势(5分钟平均)
avg_over_time(openclaw_tool_error_rate_1h[5m])
# Gateway 是否在线(1=在线,0=离线)
up{job="openclaw"}
41.7 告警规则设计
41.7.1 Prometheus AlertManager 规则
# openclaw_alerts.yml
groups:
- name: openclaw_critical
rules:
- alert: OpenClawGatewayDown
expr: up{job="openclaw"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "OpenClaw Gateway 不可达"
description: "健康检查端点已连续 1 分钟无响应,请立即检查 Gateway 进程状态。"
- alert: OpenClawSessionSuccessRateLow
expr: openclaw_session_success_rate < 0.90
for: 5m
labels:
severity: critical
annotations:
summary: "Session 成功率严重下降(当前: {{ $value | humanize }})"
description: "过去 24 小时 Session 成功率低于 90%,可能存在系统性故障。"
- alert: OpenClawMemoryOverLimit
expr: (openclaw_memory_used_mb / openclaw_memory_limit_mb) > 0.90
for: 3m
labels:
severity: critical
annotations:
summary: "Gateway 内存使用超过 90%"
description: "当前内存使用 {{ $value | humanizePercentage }},OOM 风险极高,建议立即重启或扩容。"
- name: openclaw_warning
rules:
- alert: OpenClawToolErrorRateHigh
expr: openclaw_tool_error_rate_1h > 0.05
for: 10m
labels:
severity: warning
annotations:
summary: "工具错误率过高({{ $value | humanizePercentage }})"
description: "最近 1 小时工具调用错误率超过 5%,请检查相关工具配置和权限。"
- alert: OpenClawCompactionFrequencyHigh
expr: openclaw_compaction_count_24h > 20
for: 0m
labels:
severity: warning
annotations:
summary: "Context Compaction 频率过高({{ $value }} 次/天)"
description: "每日 Compaction 超过 20 次可能导致上下文丢失和任务逻辑错误。建议优化 Token 预算配置。"
- alert: OpenClawLLMLatencyHigh
expr: openclaw_last_model_call_ms > 5000
for: 5m
labels:
severity: warning
annotations:
summary: "LLM API 响应延迟过高({{ $value }}ms)"
description: "最后一次 LLM 调用耗时超过 5 秒,可能是 API 限速或网络问题。"
- alert: OpenClawSessionSuccessRateDegraded
expr: openclaw_session_success_rate < 0.95
for: 10m
labels:
severity: warning
annotations:
summary: "Session 成功率下降(当前: {{ $value | humanize }})"
description: "成功率低于 95%,建议检查最近的失败 Session 日志。"
41.7.2 告警通知渠道配置
# alertmanager.yml
route:
group_by: ['alertname', 'severity']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'default'
routes:
- match:
severity: critical
receiver: 'pagerduty-critical'
repeat_interval: 30m
- match:
severity: warning
receiver: 'slack-warnings'
receivers:
- name: 'pagerduty-critical'
pagerduty_configs:
- routing_key: '${PAGERDUTY_KEY}'
description: '{{ .CommonAnnotations.summary }}'
- name: 'slack-warnings'
slack_configs:
- api_url: '${SLACK_WEBHOOK_URL}'
channel: '#openclaw-alerts'
title: '[{{ .Status | toUpper }}] {{ .CommonAnnotations.summary }}'
text: '{{ .CommonAnnotations.description }}'
41.8 openclaw doctor 命令
openclaw doctor 是内置的诊断工具,在告警触发或怀疑配置有误时应第一时间运行。
41.8.1 doctor 检查项清单
openclaw gateway doctor
典型输出:
OpenClaw Diagnostic Report — 2026-04-26 09:30:00
[✓] Gateway process running (PID: 12847)
[✓] Gateway port 18789 accessible
[✓] Health check responding (status: healthy)
[✓] Configuration file valid (openclaw.json)
[✓] Model API reachable (claude-opus-4-5, latency: 1843ms)
[✓] Log directory writable (~/.openclaw/logs)
[✗] Disk space low: 2.1 GB available (threshold: 5 GB)
[✓] All registered tools (28) responding to ping
[!] Tool 'web_fetch' error rate 8.2% in last hour (threshold: 5%)
[✓] No active sessions in error state
[✓] Memory usage 20.1% (412/2048 MB)
[✓] Context compaction count: 7/day (threshold: 20)
Summary: 1 error, 1 warning
Action required: Free disk space; investigate web_fetch errors
41.8.2 常用 doctor 子命令
# 仅检查 Gateway 连接
openclaw gateway doctor --check connectivity
# 检查所有工具的配置完整性
openclaw gateway doctor --check tools
# 输出机器可读的 JSON 格式
openclaw gateway doctor --format json
# 详细模式(输出每个检查项的原始数据)
openclaw gateway doctor --verbose
# 检查特定 Agent 的配置
openclaw gateway doctor --agent my-agent-id
41.9 调试技巧
41.9.1 日志级别临时调整
无需重启 Gateway 即可动态调整日志级别:
# 调整到 debug 级别,捕获完整工具调用细节
openclaw config set logging.level debug
# 实时跟踪日志
tail -f ~/.openclaw/logs/openclaw.log | jq '.'
# 过滤特定 Session 的日志
tail -f ~/.openclaw/logs/openclaw.log | \
jq 'select(.sessionId == "sess_9a1b3c")'
# 只显示错误和警告
tail -f ~/.openclaw/logs/openclaw.log | \
jq 'select(.level == "error" or .level == "warn")'
# 完成调试后恢复 info 级别
openclaw config set logging.level info
41.9.2 RPC 手动测试
Gateway 暴露 RPC 端点,可用于手动测试工具响应:
# 测试工具列表
curl -X POST http://127.0.0.1:18789/rpc \
-H "Content-Type: application/json" \
-d '{"method": "tools/list", "id": 1}'
# 手动调用工具(测试 bash 工具)
curl -X POST http://127.0.0.1:18789/rpc \
-H "Content-Type: application/json" \
-d '{
"method": "tools/call",
"params": {
"name": "bash",
"arguments": {"command": "echo hello"}
},
"id": 2
}'
# 检查当前 Session 状态
curl -s http://127.0.0.1:18789/sessions | jq '.'
41.9.3 sandbox 模式调试
使用 openclaw sandbox explain 在沙盒中分析工具调用路径,不触发真实副作用:
# 在沙盒中运行 Agent 并解释决策
openclaw sandbox explain \
--agent my-agent-id \
--message "整理今天的邮件" \
--show-tool-calls \
--show-reasoning
41.10 生产问题诊断流程
41.10.1 标准诊断 SOP
当收到告警时,按以下顺序执行诊断:
Step 1:确认 Gateway 在线
curl -sf http://127.0.0.1:18789/health | jq '.status'
# 若无响应:openclaw gateway status
# 若 Gateway 已停止:openclaw gateway dashboard 查看历史
Step 2:运行 doctor
openclaw gateway doctor --format json > /tmp/doctor_$(date +%s).json
cat /tmp/doctor_*.json | jq '.issues'
Step 3:查看失败 Session 的日志
# 找出最近失败的 Session ID
cat ~/.openclaw/logs/openclaw.log | \
jq 'select(.event == "session_failed") | {sessionId, timestamp, error}' | \
tail -5
# 提取完整 Session 日志
SESSION_ID="sess_xxxx"
cat ~/.openclaw/logs/openclaw.log | \
jq --arg sid "$SESSION_ID" 'select(.sessionId == $sid)'
Step 4:定位根因工具
# 找出错误最多的工具
cat ~/.openclaw/logs/openclaw.log | \
jq 'select(.event == "tool_call_failed") | .tool' | \
sort | uniq -c | sort -rn | head -5
Step 5:验证修复
# 手动测试问题工具
openclaw sandbox explain --message "测试 <工具名> 是否正常" --show-tool-calls
# 重新运行 doctor 确认问题解决
openclaw gateway doctor
41.10.2 常见问题速查
| 症状 | 最可能原因 | 快速验证命令 |
|---|---|---|
| Gateway 无法启动 | 端口冲突或配置文件错误 | openclaw gateway doctor --check config |
| Session 全部超时 | LLM API Key 失效或网络问题 | openclaw models list |
| 工具调用权限错误 | SKILL.md 权限声明不完整 | openclaw security audit |
| 内存持续增长 | 大文件内容被注入 Context | 检查 tokenUsage 趋势 |
| Compaction 频繁 | Token 预算设置过低 | 调整 maxTokenBudget 参数 |
下一章将通过 10 个真实案例,展示如何在不同业务场景下部署和使用 OpenClaw。