Skip to Content

25c - 日志管理与审计

本文是《AI Agent 实战手册》第 25 章第 3 节。 上一节:25b-监控与告警 | 下一节:25d-更新与回滚策略

概述

OpenClaw 作为 24/7 自主运行的 AI Agent 平台,日志管理和操作审计是生产运维的核心支柱。与传统 Web 应用不同,AI Agent 系统需要记录的不仅是基础设施日志(容器启动、HTTP 请求),还包括 Agent 特有的操作轨迹——每一次 LLM 调用、工具执行、决策推理和用户会话都需要可追溯的审计记录。2026 年,Grafana Loki 已成为轻量级日志聚合的首选方案(仅索引标签、存储成本低),而 ELK Stack 则在需要全文搜索和复杂分析的场景中保持优势。

本节提供从零搭建 OpenClaw 日志管理体系的完整指南,涵盖 Loki 栈部署、结构化日志设计、Agent 操作审计方案和合规日志策略。


1. 日志管理架构总览

日志体系分层

OpenClaw 的日志管理需要覆盖两大维度:基础设施日志和 AI Agent 审计日志。

┌─────────────────────────────────────────────────────────┐ │ 日志消费层 │ │ Grafana 日志面板 / Kibana / 告警规则 / 合规报告 │ ├─────────────────────────────────────────────────────────┤ │ 日志存储层 │ │ Grafana Loki(标签索引) 或 Elasticsearch(全文索引) │ ├─────────────────────────────────────────────────────────┤ │ 日志采集层 │ │ Promtail / Alloy 或 Logstash / Filebeat │ ├─────────────────────────────────────────────────────────┤ │ 日志生成层 │ │ Docker 容器日志 应用结构化日志 Agent 审计日志 │ │ (stdout/stderr) (JSON 格式) (操作轨迹记录) │ ├─────────────────────────────────────────────────────────┤ │ 日志来源 │ │ OpenClaw Gateway Agent Workers LLM API 调用 │ │ 工具执行器 用户会话 系统事件 │ └─────────────────────────────────────────────────────────┘

工具推荐

工具用途价格适用场景
Grafana Loki轻量级日志聚合(仅索引标签)免费(开源)/ Cloud 免费层 50 GB/月中小规模、已有 Grafana 栈
PromtailLoki 日志采集 Agent免费(开源)Docker/K8s 日志采集
Grafana Alloy统一遥测采集器(替代 Promtail)免费(开源)同时采集日志+指标+Trace
Elasticsearch全文搜索日志引擎免费(开源)/ Cloud 起步 $95/月复杂查询、安全取证、大规模分析
Logstash日志处理管道免费(开源)日志解析、转换、路由
KibanaElasticsearch 可视化免费(开源)ELK 栈日志可视化
Filebeat轻量级日志采集免费(开源)ELK 栈日志采集
Fluentd / Fluent Bit通用日志采集与路由免费(开源)多目标日志转发
Vector高性能日志管道(Rust 编写)免费(开源)高吞吐日志处理
SigNoz开源全栈可观测性免费(开源)/ Cloud $199/月起日志+指标+Trace 一体化
Betterstack Logs托管日志平台免费层 1 GB/月 / $25/月起零运维日志管理

💡 推荐方案:对于 OpenClaw 单节点部署,Loki + Promtail + Grafana(PLG 栈)是最佳起点——资源占用低、与 25b 监控栈 无缝集成。仅当需要全文搜索或复杂日志分析时才考虑 ELK。

Loki vs ELK 对比

维度Grafana LokiELK Stack
索引策略仅索引标签(label),日志正文压缩存储全文倒排索引,所有字段可搜索
存储成本极低(压缩比高,无全文索引开销)较高(索引占用大量磁盘)
内存需求低(单节点 512 MB 起)高(Elasticsearch 建议 4 GB+)
查询语言LogQL(类 PromQL 语法)KQL / Lucene 查询语法
查询速度标签过滤快,正文搜索需扫描全文搜索极快(已建索引)
学习曲线低(熟悉 Prometheus 即可上手)中等(需理解 mapping、分片等概念)
运维复杂度低(单二进制文件,配置简单)高(需管理 ES 集群、分片、副本)
可视化Grafana(与指标统一面板)Kibana(独立 UI)
适用规模中小规模(TB 级)大规模(PB 级)
最佳场景运维日志、容器日志、Agent 操作日志安全审计取证、合规全文搜索、业务分析

💡 选择建议:90% 的 OpenClaw 部署场景选 Loki 即可。如果你有合规要求需要对日志内容做全文搜索(如安全事件调查),可以 Loki + Elasticsearch 双写——Loki 做日常运维,ES 做合规审计。


2. Grafana Loki 栈部署

Docker Compose 配置

25b-监控与告警 的监控栈基础上,添加日志组件:

# docker-compose.logging.yml — 日志栈 # 与主服务和监控栈配合使用: # docker compose -f docker-compose.yml \ # -f docker-compose.monitoring.yml \ # -f docker-compose.logging.yml up -d version: '3.8' services: # ============================================ # Loki — 日志存储与查询引擎 # ============================================ loki: image: grafana/loki:3.4.2 container_name: openclaw-loki restart: unless-stopped user: "10001:10001" ports: - "127.0.0.1:3100:3100" volumes: - ./logging/loki/loki-config.yml:/etc/loki/local-config.yaml:ro - loki_data:/loki command: -config.file=/etc/loki/local-config.yaml networks: - openclaw-net healthcheck: test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3100/ready || exit 1"] interval: 15s timeout: 5s retries: 3 logging: driver: json-file options: max-size: "10m" max-file: "3" # ============================================ # Promtail — 日志采集 Agent # ============================================ promtail: image: grafana/promtail:3.4.2 container_name: openclaw-promtail restart: unless-stopped volumes: - ./logging/promtail/promtail-config.yml:/etc/promtail/config.yml:ro - /var/log:/var/log:ro - /var/lib/docker/containers:/var/lib/docker/containers:ro - /var/run/docker.sock:/var/run/docker.sock:ro command: -config.file=/etc/promtail/config.yml networks: - openclaw-net depends_on: loki: condition: service_healthy logging: driver: json-file options: max-size: "10m" max-file: "3" volumes: loki_data:

Loki 配置文件

# logging/loki/loki-config.yml auth_enabled: false server: http_listen_port: 3100 grpc_listen_port: 9096 log_level: warn common: instance_addr: 127.0.0.1 path_prefix: /loki storage: filesystem: chunks_directory: /loki/chunks rules_directory: /loki/rules replication_factor: 1 ring: kvstore: store: inmemory schema_config: configs: - from: "2024-01-01" store: tsdb object_store: filesystem schema: v13 index: prefix: index_ period: 24h storage_config: filesystem: directory: /loki/chunks limits_config: retention_period: 30d # 日志保留 30 天 max_query_length: 721h # 最大查询范围 30 天 max_query_parallelism: 4 max_entries_limit_per_query: 10000 ingestion_rate_mb: 10 # 每租户摄入速率限制 ingestion_burst_size_mb: 20 per_stream_rate_limit: 5MB # 每流速率限制 per_stream_rate_limit_burst: 15MB compactor: working_directory: /loki/compactor compaction_interval: 10m retention_enabled: true # 启用自动清理过期日志 retention_delete_delay: 2h retention_delete_worker_count: 150 query_range: results_cache: cache: embedded_cache: enabled: true max_size_mb: 100 analytics: reporting_enabled: false

Promtail 配置文件

# logging/promtail/promtail-config.yml server: http_listen_port: 9080 grpc_listen_port: 0 positions: filename: /tmp/positions.yaml clients: - url: http://loki:3100/loki/api/v1/push tenant_id: openclaw batchwait: 1s batchsize: 1048576 # 1 MB scrape_configs: # ============================================ # Docker 容器日志采集 # ============================================ - job_name: docker docker_sd_configs: - host: unix:///var/run/docker.sock refresh_interval: 5s filters: - name: label values: ["logging=enabled"] relabel_configs: # 提取容器名作为标签 - source_labels: ['__meta_docker_container_name'] regex: '/(.*)' target_label: 'container' # 提取 compose 服务名 - source_labels: ['__meta_docker_container_label_com_docker_compose_service'] target_label: 'service' # 提取 compose 项目名 - source_labels: ['__meta_docker_container_label_com_docker_compose_project'] target_label: 'project' # 提取日志流(stdout/stderr) - source_labels: ['__meta_docker_container_log_stream'] target_label: 'stream' pipeline_stages: # 尝试解析 JSON 格式日志 - json: expressions: level: level msg: msg timestamp: timestamp component: component agent_id: agent_id session_id: session_id task_id: task_id # 设置日志级别标签 - labels: level: component: # 设置时间戳 - timestamp: source: timestamp format: RFC3339Nano fallback_formats: - "2006-01-02T15:04:05Z07:00" - UnixMs # 过滤健康检查噪音日志 - match: selector: '{service="openclaw-gateway"}' stages: - regex: expression: '.*GET /health.*' - drop: expression: '.*GET /health.*' drop_counter_reason: health_check_noise # ============================================ # OpenClaw 审计日志文件采集 # ============================================ - job_name: openclaw-audit static_configs: - targets: - localhost labels: job: openclaw-audit log_type: audit __path__: /var/log/openclaw/audit/*.jsonl pipeline_stages: - json: expressions: level: level event_type: event_type agent_id: agent_id user_id: user_id action: action timestamp: timestamp - labels: event_type: agent_id: action: - timestamp: source: timestamp format: RFC3339Nano # ============================================ # 系统日志采集 # ============================================ - job_name: system static_configs: - targets: - localhost labels: job: syslog __path__: /var/log/syslog pipeline_stages: - regex: expression: '^(?P<timestamp>\w+\s+\d+\s+\d+:\d+:\d+)\s+(?P<hostname>\S+)\s+(?P<app>\S+?)(\[(?P<pid>\d+)\])?:\s+(?P<message>.*)$' - labels: app:

Grafana 数据源配置(添加 Loki)

25b-监控与告警 的 Grafana provisioning 基础上,添加 Loki 数据源:

# monitoring/grafana/provisioning/datasources/loki.yml apiVersion: 1 datasources: - name: Loki type: loki access: proxy url: http://loki:3100 isDefault: false editable: false jsonData: maxLines: 1000 derivedFields: # 从日志中提取 trace_id,关联到 Tempo(如果部署了) - datasourceUid: tempo matcherRegex: '"trace_id":"(\w+)"' name: TraceID url: '$${__value.raw}'

目录结构

openclaw-deploy/ ├── docker-compose.yml # 主服务 ├── docker-compose.monitoring.yml # 监控栈(25b) ├── docker-compose.logging.yml # 日志栈(本节) ├── logging/ │ ├── loki/ │ │ └── loki-config.yml # Loki 主配置 │ └── promtail/ │ └── promtail-config.yml # Promtail 采集配置 ├── monitoring/ │ └── grafana/ │ └── provisioning/ │ └── datasources/ │ ├── prometheus.yml # Prometheus 数据源 │ └── loki.yml # Loki 数据源(新增) └── .env

启动日志栈

# 创建目录 mkdir -p logging/{loki,promtail} # 为 Docker 容器添加日志采集标签 # 在 docker-compose.yml 中为需要采集日志的服务添加: # labels: # logging: "enabled" # 启动全栈 docker compose -f docker-compose.yml \ -f docker-compose.monitoring.yml \ -f docker-compose.logging.yml up -d # 验证 Loki 就绪 curl -s http://127.0.0.1:3100/ready # 预期输出: ready # 验证 Promtail 目标 curl -s http://127.0.0.1:9080/targets | head -20 # 在 Grafana 中验证(http://127.0.0.1:3000) # 进入 Explore → 选择 Loki 数据源 → 输入 {service="openclaw-gateway"}

3. 结构化日志设计

为什么需要结构化日志

传统的纯文本日志(如 [INFO] User logged in)在 AI Agent 场景下严重不足——你无法高效地按 Agent ID、会话 ID、工具名称等维度过滤和聚合。结构化日志(JSON 格式)让每条日志都成为可查询的数据记录。

OpenClaw 结构化日志规范

所有 OpenClaw 组件应输出统一格式的 JSON 日志:

{ "timestamp": "2026-01-15T08:30:45.123Z", "level": "info", "component": "agent-worker", "msg": "Tool execution completed", "agent_id": "agent-research-01", "session_id": "sess_abc123def456", "task_id": "task_789", "trace_id": "trace_xyz", "tool_name": "web_search", "tool_input_hash": "sha256:a1b2c3...", "tool_duration_ms": 1250, "tool_status": "success", "token_count": 0, "cost_usd": 0.0, "metadata": { "search_query": "OpenClaw production deployment", "results_count": 5 } }

日志字段规范

字段类型必填说明
timestampstring (ISO 8601)事件发生时间,UTC 时区
levelstring日志级别:debug/info/warn/error/fatal
componentstring组件名:gateway/agent-worker/scheduler/tool-executor
msgstring人类可读的事件描述
agent_idstring⚠️Agent 标识(Agent 相关日志必填)
session_idstring⚠️会话标识(会话相关日志必填)
task_idstring⚠️任务标识(任务相关日志必填)
trace_idstring推荐分布式追踪 ID,用于关联跨组件日志
tool_namestring⚠️工具名称(工具调用日志必填)
tool_duration_msnumber⚠️工具执行耗时(毫秒)
tool_statusstring⚠️工具执行结果:success/failure/timeout
model_providerstring⚠️LLM 提供商(LLM 调用日志必填)
model_namestring⚠️模型名称
token_countnumber⚠️Token 消耗量
cost_usdnumber⚠️估算成本(美元)
error_codestring⚠️错误码(错误日志必填)
error_messagestring⚠️错误详情
metadataobject可选额外上下文信息

日志级别使用规范

级别使用场景示例
debug开发调试信息,生产环境通常关闭LLM prompt 完整内容、工具输入输出详情
info正常业务事件Agent 启动、任务开始/完成、工具调用成功
warn异常但可恢复的情况API 限流重试、工具超时重试、Token 接近预算
error错误但不影响系统整体运行单次工具调用失败、LLM API 返回错误
fatal系统级严重错误,需要立即处理Gateway 启动失败、数据库连接断开

4. LogQL 日志查询实战

LogQL 基础语法

LogQL 是 Loki 的查询语言,语法灵感来自 PromQL。核心结构:

{标签选择器} |= "文本过滤" | json | line_format "格式化"

常用查询示例

基础查询——按服务过滤

# 查看 OpenClaw Gateway 所有日志 {service="openclaw-gateway"} # 查看所有错误日志 {service="openclaw-gateway"} |= "error" # 查看特定 Agent 的日志 {service="openclaw-gateway"} | json | agent_id="agent-research-01" # 排除健康检查日志 {service="openclaw-gateway"} != "/health" != "/ready"

Agent 操作查询

# 查看特定会话的所有操作 {job="openclaw-audit"} | json | session_id="sess_abc123def456" # 查看所有工具调用失败 {service="openclaw-gateway"} | json | tool_status="failure" # 查看特定 Agent 的 LLM 调用 {service="openclaw-gateway"} | json | agent_id="agent-research-01" | component="llm-client" # 查看执行时间超过 30 秒的工具调用 {service="openclaw-gateway"} | json | tool_duration_ms > 30000

聚合与统计查询

# 过去 1 小时各 Agent 的错误数量 sum by (agent_id) ( count_over_time( {service="openclaw-gateway"} | json | level="error" [1h] ) ) # 过去 24 小时各工具的调用次数 sum by (tool_name) ( count_over_time( {job="openclaw-audit"} | json | event_type="tool_call" [24h] ) ) # 每 5 分钟的日志量趋势 sum(rate({service="openclaw-gateway"}[5m])) by (level) # 过去 1 小时 P95 工具执行延迟 quantile_over_time(0.95, {service="openclaw-gateway"} | json | unwrap tool_duration_ms [1h] ) by (tool_name) # 每小时 Token 消耗趋势 sum(sum_over_time( {job="openclaw-audit"} | json | event_type="llm_call" | unwrap token_count [1h] )) by (model_name)

告警规则查询

# 5 分钟内错误率超过阈值(用于 Grafana 告警) sum(rate({service="openclaw-gateway"} | json | level="error" [5m])) / sum(rate({service="openclaw-gateway"} [5m])) > 0.1 # 检测 Agent 死循环(同一 Agent 短时间内大量日志) sum by (agent_id) ( count_over_time( {service="openclaw-gateway"} | json [5m] ) ) > 1000

提示词模板:生成 LogQL 查询

你是一个 Grafana Loki 专家。请根据以下需求生成 LogQL 查询。 日志格式:JSON 结构化日志 可用标签:service, level, component, agent_id, session_id 可用 JSON 字段:msg, tool_name, tool_status, tool_duration_ms, model_provider, model_name, token_count, cost_usd, error_code 需求:[描述你想查询的内容] 请生成: 1. LogQL 查询语句 2. 查询说明(中文) 3. 如果是聚合查询,建议的 Grafana 面板类型(时序图/柱状图/表格/统计值)

5. Agent 操作审计系统

审计日志 vs 运维日志

维度运维日志审计日志
目的排障、性能分析合规、安全追溯、责任归属
内容系统事件、错误信息谁在什么时间做了什么操作
保留期7-30 天90 天-7 年(取决于合规要求)
可变性可清理、可压缩不可篡改、不可删除
访问控制运维团队审计员、合规官、安全团队
存储方式Loki/ES(可覆盖)独立存储、写入后不可修改

审计事件分类

OpenClaw 的审计日志需要覆盖以下事件类型:

事件类别事件类型说明审计重要性
用户操作user.login用户登录🔴 高
user.logout用户登出🟡 中
user.config_change用户修改配置🔴 高
user.agent_create创建新 Agent🔴 高
user.agent_delete删除 Agent🔴 高
Agent 生命周期agent.startAgent 启动🟡 中
agent.stopAgent 停止🟡 中
agent.errorAgent 运行错误🔴 高
agent.session_start会话开始🟡 中
agent.session_end会话结束🟡 中
LLM 交互llm.requestLLM API 调用🟡 中
llm.responseLLM 响应接收🟡 中
llm.errorLLM 调用失败🔴 高
llm.token_usageToken 消耗记录🟢 低
工具调用tool.invoke工具调用发起🔴 高
tool.result工具返回结果🟡 中
tool.error工具调用失败🔴 高
tool.permission_denied工具权限拒绝🔴 高
数据访问data.read读取外部数据🟡 中
data.write写入外部数据🔴 高
data.delete删除外部数据🔴 高
系统事件system.startup系统启动🟡 中
system.shutdown系统关闭🟡 中
system.config_reload配置热重载🔴 高
system.backup备份执行🟡 中

审计日志 Schema 设计

{ "$schema": "openclaw-audit-log-v1", "timestamp": "2026-01-15T08:30:45.123456Z", "event_id": "evt_01JQXYZ123456789", "event_type": "tool.invoke", "event_category": "tool_call", "severity": "info", "actor": { "type": "agent", "id": "agent-research-01", "name": "Research Assistant", "session_id": "sess_abc123def456", "parent_agent_id": null }, "initiator": { "type": "user", "id": "user_john", "ip": "192.168.1.100", "user_agent": "Mozilla/5.0..." }, "action": { "type": "tool_invoke", "tool_name": "web_search", "tool_version": "1.2.0", "input_summary": "Search: OpenClaw deployment best practices", "input_hash": "sha256:a1b2c3d4e5f6...", "output_summary": "5 results returned", "output_hash": "sha256:f6e5d4c3b2a1...", "duration_ms": 1250, "status": "success" }, "context": { "task_id": "task_789", "task_description": "Research production deployment", "conversation_turn": 5, "model_provider": "anthropic", "model_name": "claude-sonnet-4-20250514", "token_input": 1500, "token_output": 800, "estimated_cost_usd": 0.012 }, "resource": { "type": "external_api", "id": "google_search_api", "permissions_used": ["web:read"] }, "metadata": { "openclaw_version": "0.5.2", "node_id": "node-01", "environment": "production" } }

审计日志采集器实现

以下 Python 脚本展示如何为 OpenClaw 实现一个审计日志采集中间件:

#!/usr/bin/env python3 """ openclaw_audit_logger.py — OpenClaw 审计日志中间件 将 Agent 操作事件写入 JSONL 审计日志文件,由 Promtail 采集到 Loki """ import json import os import time import uuid import hashlib from datetime import datetime, timezone from pathlib import Path # 审计日志目录 AUDIT_LOG_DIR = Path(os.getenv("AUDIT_LOG_DIR", "/var/log/openclaw/audit")) AUDIT_LOG_DIR.mkdir(parents=True, exist_ok=True) # 当前日志文件(按天轮转) def get_audit_log_path(): date_str = datetime.now(timezone.utc).strftime("%Y-%m-%d") return AUDIT_LOG_DIR / f"audit-{date_str}.jsonl" def generate_event_id(): """生成唯一事件 ID""" return f"evt_{uuid.uuid4().hex[:20]}" def hash_content(content: str) -> str: """对内容生成 SHA256 摘要(不存储原文,保护隐私)""" return f"sha256:{hashlib.sha256(content.encode()).hexdigest()[:16]}" def write_audit_event(event: dict): """写入审计事件到 JSONL 文件(追加模式,不可覆盖)""" log_path = get_audit_log_path() event["timestamp"] = datetime.now(timezone.utc).isoformat() event["event_id"] = event.get("event_id", generate_event_id()) with open(log_path, "a") as f: f.write(json.dumps(event, ensure_ascii=False) + "\n") # ============================================ # 审计事件工厂函数 # ============================================ def audit_tool_call(agent_id, session_id, tool_name, tool_input, tool_output, duration_ms, status, user_id=None): """记录工具调用审计事件""" write_audit_event({ "event_type": "tool.invoke", "event_category": "tool_call", "severity": "info" if status == "success" else "error", "actor": { "type": "agent", "id": agent_id, "session_id": session_id }, "initiator": { "type": "user", "id": user_id or "system" }, "action": { "type": "tool_invoke", "tool_name": tool_name, "input_hash": hash_content(str(tool_input)), "output_hash": hash_content(str(tool_output)), "duration_ms": duration_ms, "status": status } }) def audit_llm_call(agent_id, session_id, provider, model, token_input, token_output, cost_usd, duration_ms, status): """记录 LLM 调用审计事件""" write_audit_event({ "event_type": "llm.request", "event_category": "llm_interaction", "severity": "info" if status == "success" else "error", "actor": { "type": "agent", "id": agent_id, "session_id": session_id }, "context": { "model_provider": provider, "model_name": model, "token_input": token_input, "token_output": token_output, "estimated_cost_usd": cost_usd, "duration_ms": duration_ms }, "action": { "type": "llm_request", "status": status } }) def audit_user_action(user_id, action_type, details, ip=None): """记录用户操作审计事件""" write_audit_event({ "event_type": f"user.{action_type}", "event_category": "user_action", "severity": "info", "actor": { "type": "user", "id": user_id, "ip": ip }, "action": { "type": action_type, "details": details } }) # ============================================ # 使用示例 # ============================================ if __name__ == "__main__": # 记录工具调用 audit_tool_call( agent_id="agent-research-01", session_id="sess_abc123", tool_name="web_search", tool_input="OpenClaw deployment guide", tool_output="5 results found", duration_ms=1250, status="success", user_id="user_john" ) # 记录 LLM 调用 audit_llm_call( agent_id="agent-research-01", session_id="sess_abc123", provider="anthropic", model="claude-sonnet-4-20250514", token_input=1500, token_output=800, cost_usd=0.012, duration_ms=3200, status="success" ) print(f"审计日志已写入: {get_audit_log_path()}")

6. 日志保留与合规策略

保留策略设计

不同类型的日志需要不同的保留期限:

日志类型保留期限存储层合规依据
调试日志 (debug)3 天热存储(Loki 本地)仅用于排障
运维日志 (info/warn)30 天热存储(Loki 本地)运维需求
错误日志 (error/fatal)90 天热存储 → 冷存储事后分析
审计日志 (audit)1-7 年冷存储(S3/MinIO)GDPR/SOC 2/EU AI Act
安全事件日志3-7 年冷存储(不可变)安全合规
LLM 交互摘要90 天-1 年冷存储EU AI Act 可解释性要求

Loki 保留策略配置

# 在 loki-config.yml 的 limits_config 中配置 limits_config: retention_period: 30d # 默认保留 30 天 # 按标签设置不同保留期 # Loki 3.x 支持按流的保留策略 overrides: # 审计日志保留 365 天 openclaw-audit: retention_period: 365d # 调试日志仅保留 3 天 debug: retention_period: 72h

审计日志长期归档

对于需要长期保留的审计日志,建议使用对象存储归档:

#!/bin/bash # scripts/archive-audit-logs.sh # 将超过 30 天的审计日志归档到 S3/MinIO AUDIT_DIR="/var/log/openclaw/audit" S3_BUCKET="s3://openclaw-audit-archive" ARCHIVE_AFTER_DAYS=30 # 查找超过 30 天的审计日志文件 find "$AUDIT_DIR" -name "audit-*.jsonl" -mtime +$ARCHIVE_AFTER_DAYS | while read file; do filename=$(basename "$file") date_part=$(echo "$filename" | grep -oP '\d{4}-\d{2}-\d{2}') # 压缩并上传到 S3 gzip -c "$file" > "/tmp/${filename}.gz" # 上传到按年月组织的目录 year_month=$(echo "$date_part" | cut -d'-' -f1,2) aws s3 cp "/tmp/${filename}.gz" \ "${S3_BUCKET}/${year_month}/${filename}.gz" \ --storage-class GLACIER_IR # 验证上传成功后删除本地文件 if [ $? -eq 0 ]; then rm "$file" "/tmp/${filename}.gz" echo "[$(date)] Archived: $filename → ${S3_BUCKET}/${year_month}/" fi done

配合 cron 定时执行:

# 每天凌晨 3 点执行归档 0 3 * * * /opt/openclaw/scripts/archive-audit-logs.sh >> /var/log/openclaw/archive.log 2>&1

合规要求速查

合规框架日志要求保留期限关键要点
GDPR记录数据处理活动、访问日志无固定要求,但需”合理期限”PII 需脱敏或加密存储;数据主体有权要求删除
SOC 2完整审计轨迹、访问控制日志至少 1 年不可篡改;需定期审查
HIPAA访问日志、修改日志至少 6 年医疗数据相关操作必须记录
EU AI ActAI 系统决策日志、可解释性记录高风险系统至少 6 个月2026 年 8 月开始执行;需记录 AI 决策依据
PCI DSS系统活动日志至少 1 年(3 个月在线可查)支付相关操作必须记录

提示词模板:生成合规日志策略

你是一个合规与安全专家。请为我的 AI Agent 平台生成日志合规策略。 平台信息: - 平台类型:[OpenClaw / 自建 Agent 平台] - 部署区域:[中国 / 欧盟 / 美国 / 全球] - 适用合规框架:[GDPR / SOC 2 / HIPAA / EU AI Act / 等保 2.0] - 数据类型:[是否处理 PII / 医疗数据 / 金融数据] - 当前日志存储:[Loki / ELK / 云服务] 请生成: 1. 各类日志的保留策略表(类型、保留期、存储层、合规依据) 2. PII 脱敏规则(哪些字段需要脱敏、脱敏方法) 3. 审计日志不可篡改性保障方案 4. 日志访问控制策略(谁可以查看什么级别的日志) 5. 定期审查清单(频率、检查项)

7. ELK Stack 部署参考(可选)

如果你的场景需要全文搜索能力(如安全事件调查、合规审计取证),可以部署 ELK Stack 作为补充。以下是轻量级 ELK 部署配置:

Docker Compose 配置

# docker-compose.elk.yml — ELK 栈(可选) # 仅在需要全文搜索时部署 # docker compose -f docker-compose.yml \ # -f docker-compose.monitoring.yml \ # -f docker-compose.logging.yml \ # -f docker-compose.elk.yml up -d version: '3.8' services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.17.4 container_name: openclaw-elasticsearch restart: unless-stopped environment: - discovery.type=single-node - xpack.security.enabled=true - xpack.security.http.ssl.enabled=false - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} - "ES_JAVA_OPTS=-Xms1g -Xmx1g" - cluster.name=openclaw-logs - bootstrap.memory_lock=true ulimits: memlock: soft: -1 hard: -1 volumes: - es_data:/usr/share/elasticsearch/data ports: - "127.0.0.1:9200:9200" networks: - openclaw-net healthcheck: test: ["CMD-SHELL", "curl -s -u elastic:${ELASTIC_PASSWORD} http://localhost:9200/_cluster/health | grep -q '\"status\":\"green\\|yellow\"'"] interval: 30s timeout: 10s retries: 5 kibana: image: docker.elastic.co/kibana/kibana:8.17.4 container_name: openclaw-kibana restart: unless-stopped environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 - ELASTICSEARCH_USERNAME=kibana_system - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD} ports: - "127.0.0.1:5601:5601" networks: - openclaw-net depends_on: elasticsearch: condition: service_healthy filebeat: image: docker.elastic.co/beats/filebeat:8.17.4 container_name: openclaw-filebeat restart: unless-stopped user: root volumes: - ./elk/filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro - /var/lib/docker/containers:/var/lib/docker/containers:ro - /var/log/openclaw:/var/log/openclaw:ro - filebeat_data:/usr/share/filebeat/data networks: - openclaw-net depends_on: elasticsearch: condition: service_healthy volumes: es_data: filebeat_data:

Filebeat 配置

# elk/filebeat/filebeat.yml filebeat.inputs: # 审计日志(JSON 格式) - type: log enabled: true paths: - /var/log/openclaw/audit/*.jsonl json.keys_under_root: true json.add_error_key: true fields: log_type: audit fields_under_root: true # Docker 容器日志 - type: container paths: - /var/lib/docker/containers/*/*.log processors: - add_docker_metadata: host: "unix:///var/run/docker.sock" output.elasticsearch: hosts: ["elasticsearch:9200"] username: "elastic" password: "${ELASTIC_PASSWORD}" indices: - index: "openclaw-audit-%{+yyyy.MM}" when.equals: log_type: "audit" - index: "openclaw-logs-%{+yyyy.MM.dd}" # 索引生命周期管理 setup.ilm: enabled: true rollover_alias: "openclaw-logs" pattern: "{now/d}-000001" policy_name: "openclaw-log-policy"

💡 资源提醒:ELK Stack 资源消耗较大——Elasticsearch 单节点建议至少 4 GB 内存。如果 VPS 资源有限(4 GB 以下),建议仅使用 Loki 栈,不部署 ELK。


实战案例:从零搭建 OpenClaw 日志审计体系

场景描述

你运营一个 OpenClaw 实例,有 3 个 Agent 24/7 运行(研究助手、邮件管理、DevOps 助手)。需要:

  1. 集中管理所有容器日志
  2. 记录每个 Agent 的工具调用和 LLM 交互
  3. 满足基本的审计合规要求(保留 90 天审计日志)
  4. 能快速排查 Agent 异常行为

步骤 1:准备目录结构

# 在 OpenClaw 部署目录下创建日志相关目录 cd /opt/openclaw mkdir -p logging/{loki,promtail} mkdir -p /var/log/openclaw/audit # 设置审计日志目录权限(仅 root 和 openclaw 用户可写) chown root:openclaw /var/log/openclaw/audit chmod 770 /var/log/openclaw/audit

步骤 2:配置 Loki

将前文的 loki-config.yml 写入 logging/loki/loki-config.yml,关键调整:

# 根据 VPS 资源调整 limits_config: retention_period: 90d # 审计要求保留 90 天 ingestion_rate_mb: 5 # 3 个 Agent 足够 per_stream_rate_limit: 3MB

步骤 3:配置 Promtail

将前文的 promtail-config.yml 写入 logging/promtail/promtail-config.yml

步骤 4:为 OpenClaw 容器添加日志标签

docker-compose.yml 中为 OpenClaw 服务添加标签:

services: openclaw-gateway: image: openclaw/openclaw:latest labels: logging: "enabled" # ... 其他配置 logging: driver: json-file options: max-size: "50m" max-file: "5" tag: "openclaw-gateway"

步骤 5:启动日志栈

# 启动全栈 docker compose -f docker-compose.yml \ -f docker-compose.monitoring.yml \ -f docker-compose.logging.yml up -d # 验证各组件 echo "=== Loki ===" && curl -s http://127.0.0.1:3100/ready echo "=== Promtail targets ===" && curl -s http://127.0.0.1:9080/targets | python3 -m json.tool | head -30

步骤 6:在 Grafana 中配置日志面板

  1. 打开 Grafana(http://127.0.0.1:3000) 
  2. 进入 Explore → 选择 Loki 数据源
  3. 测试查询:
# 查看所有 OpenClaw 日志 {service="openclaw-gateway"} | json # 查看审计日志 {job="openclaw-audit"} | json # 查看特定 Agent 的错误 {service="openclaw-gateway"} | json | agent_id="agent-research-01" | level="error"
  1. 创建日志仪表板,添加以下面板:
    • 实时日志流{service="openclaw-gateway"} | json(Log 面板)
    • 每小时错误趋势sum(count_over_time({service="openclaw-gateway"} | json | level="error" [1h])) by (agent_id)(时序图)
    • 工具调用排行topk(10, sum by (tool_name) (count_over_time({job="openclaw-audit"} | json | event_type="tool.invoke" [24h])))(柱状图)
    • 今日 Token 消耗sum(sum_over_time({job="openclaw-audit"} | json | event_type="llm.request" | unwrap token_input [24h])) + output(统计值)

步骤 7:配置日志告警

在 Grafana 中创建基于日志的告警规则:

# 告警:5 分钟内错误日志超过 20 条 count_over_time({service="openclaw-gateway"} | json | level="error" [5m]) > 20 # 告警:检测到权限拒绝事件 count_over_time({job="openclaw-audit"} | json | event_type="tool.permission_denied" [10m]) > 0 # 告警:单个 Agent 日志量异常(可能死循环) sum by (agent_id) (count_over_time({service="openclaw-gateway"} | json [5m])) > 500

案例分析

关键决策点

  1. 选择 Loki 而非 ELK:3 个 Agent 的日志量不大(预估每天 1-5 GB),Loki 的低资源消耗更适合单 VPS 部署
  2. 审计日志独立存储:审计日志写入独立的 JSONL 文件,与运维日志分离,便于长期归档和合规审查
  3. 日志标签设计:使用 agent_idsession_idevent_type 作为 Loki 标签,实现高效过滤而不增加索引开销
  4. 保留策略分层:运维日志 30 天、审计日志 90 天、安全事件归档到 S3

避坑指南

❌ 常见错误

  1. 将 LLM 完整 prompt/response 写入日志

    • 问题:LLM 的输入输出可能包含用户隐私数据(PII),直接记录违反 GDPR 等合规要求。同时,完整的 prompt 和 response 体积巨大,会迅速耗尽存储空间
    • 正确做法:审计日志中仅记录 prompt/response 的 SHA256 摘要(hash),需要时通过 hash 反查原始数据。敏感字段使用脱敏处理(如邮箱 j***@example.com
  2. Loki 标签基数过高(High Cardinality)

    • 问题:将 session_idtrace_iduser_id 等高基数字段设为 Loki 标签,导致 Loki 创建大量日志流,性能急剧下降甚至 OOM
    • 正确做法:Loki 标签仅使用低基数字段(servicelevelcomponentagent_id)。高基数字段放在 JSON 日志正文中,通过 | json | session_id="xxx" 查询
  3. 审计日志与运维日志混在一起

    • 问题:审计日志有不同的保留要求(通常 1-7 年)和访问控制要求。混合存储导致无法独立管理生命周期,也无法满足”不可篡改”的合规要求
    • 正确做法:审计日志写入独立的文件/索引,使用独立的保留策略和访问控制。考虑使用 WORM(Write Once Read Many)存储
  4. 没有配置日志轮转导致磁盘爆满

    • 问题:Docker 默认的 json-file 日志驱动没有大小限制,长时间运行后容器日志文件可能增长到数十 GB
    • 正确做法:在 docker-compose.yml 中为每个服务配置日志驱动限制:max-size: "50m"max-file: "5"。同时配置 Loki 的 retention_periodcompactor
  5. ELK Stack 在小规模部署中过度使用

    • 问题:Elasticsearch 单节点至少需要 4 GB 内存,在 2-4 GB 的 VPS 上部署 ELK 会严重影响 OpenClaw 本身的性能
    • 正确做法:小规模部署(1-5 个 Agent)使用 Loki 栈。仅在有明确的全文搜索需求或合规要求时才引入 ELK
  6. 忽略日志时间戳标准化

    • 问题:不同组件使用不同的时间格式(Unix 时间戳、本地时间、UTC),导致日志关联困难,排障时时间线混乱
    • 正确做法:所有组件统一使用 ISO 8601 格式的 UTC 时间(2026-01-15T08:30:45.123Z)。在 Promtail 配置中设置 timestamp stage 确保正确解析

✅ 最佳实践

  1. 日志分层存储:热数据(7 天)放本地 SSD,温数据(30 天)放本地 HDD,冷数据(90 天+)归档到 S3/MinIO 的 Glacier 层
  2. 结构化日志优先:所有应用日志输出 JSON 格式,避免正则解析的性能开销和维护成本
  3. 审计日志不可变:审计日志文件使用 chattr +a(仅追加)属性,或存储到 WORM 兼容的对象存储
  4. 定期审查日志策略:每季度审查一次日志保留策略、访问权限和存储成本
  5. 日志采样:对于高频低价值日志(如 debug 级别),在 Promtail 中配置采样率,减少存储压力
  6. 关联 ID 贯穿全链路:使用 trace_id 将同一请求的日志、指标和追踪数据关联起来,实现端到端可观测性

相关资源与延伸阅读

  1. Grafana Loki 官方文档  — Loki 配置、LogQL 语法、部署指南的权威参考
  2. grafana/loki GitHub 仓库  — Loki 源码、Docker Compose 示例、Issue 讨论
  3. LogQL 查询示例集  — 官方 LogQL 查询模式和示例
  4. Elastic Stack 官方文档  — Elasticsearch、Logstash、Kibana、Filebeat 完整文档
  5. OpenTelemetry Logging 规范  — 开放遥测日志标准,结构化日志的行业规范
  6. Vector 日志管道  — Datadog 开源的高性能日志采集和路由工具(Rust 编写)
  7. EU AI Act 合规指南  — 欧盟 AI 法案官方资源,了解 AI 系统日志合规要求
  8. SigNoz 开源可观测性  — 开源的日志+指标+Trace 一体化平台,ELK/Loki 的替代方案
  9. Promtail Pipeline Stages 文档  — Promtail 日志处理管道的详细配置指南
  10. AI Agent 审计日志最佳实践  — LLM 交互审计日志的实现指南(2025)

参考来源


📖 返回 总览与导航 | 上一节:25b-监控与告警 | 下一节:25d-更新与回滚策略

Last updated on