Skip to content

安全与事件可观测性 Schema

本文定义 Kairo 事件总线 → OpenTelemetry 集成的字段命名约定与基数约束。

状态: v0.9 起 schema 覆盖所有 KairoEventBus 域,不再仅限 security。原有 security.* 键早于 bus(见 ADR-018),为与现存 LoggingSecurityEventSink 消费者兼容,在信封 body 内原样保留。当 KairoEventOTelExporter 把信封桥接到 OpenTelemetry 时,会在外层额外套一层 kairo.<domain>.* 命名空间前缀。

属性命名空间

KairoEventOTelExporter 发出的每条 log record 都带有三个信封级键:

类型示例
kairo.event.idString (UUID)9c1b…-…-…
kairo.domainString (enum)securityexecutionevolutionteam
kairo.event.typeStringGUARDRAIL_DENYMODEL_TURNEXPERT_TEAM_ROUND

其余按域划分的属性被平展在 kairo.<domain>.<key> 下——exporter 把 KairoEvent.attributes() 的每个条目复制进该命名空间。取值统一转成 String;结构化 payload 必须由发布者在入 bus 前展平。

Severity 映射:

  • securityWARN
  • execution / evolution / teamINFO

LogRecord.severityText 取域名;LogRecord.body 取 event type;LogRecord.observedTimestamp 使用 KairoEvent.timestamp()

按域 Schema

kairo.security.*

用于 guardrail 生命周期事件。OTel exporter 始终开启(不被采样丢弃)。

字段类型说明示例
kairo.security.event.typeSecurityEventType enum安全决策分类GUARDRAIL_DENY
kairo.security.policy.nameString (有限集合)产出决策的策略content-filter
kairo.security.decision.actionALLOW / DENY / MODIFY / WARN策略输出DENY
kairo.security.decision.reasonString (最多 256 字符)人类可读原因PII detected in output
kairo.security.target.nameString (有限集合)被守护的工具或模型echoclaude-3
kairo.security.target.typeMODEL / TOOL / MCP_TOOL目标类型TOOL
kairo.security.agent.nameString (有限集合)拥有该 pipeline 的 Agentassistant
kairo.security.guardrail.phaseGuardrailPhase enumpipeline 切入点PRE_TOOL

kairo.execution.*

用于执行日志生命周期(模型回合、工具调用、压缩、迭代)。通过 kairo.observability.event-otel.sampling-ratio 采样。

字段类型说明示例
kairo.execution.modelString (有限集合)模型标识claude-opus-4-7
kairo.execution.toolString (有限集合)适用时的工具名bashread
kairo.execution.phaseEnum生命周期阶段MODEL_TURNTOOL_CALLCOMPACT
kairo.execution.iterationInteger单次运行内的迭代序号3
kairo.execution.tokens.inputInteger输入 token 数12540
kairo.execution.tokens.outputInteger输出 token 数812
kairo.execution.duration_msIntegerspan 耗时毫秒1824

kairo.evolution.*

用于自进化技能治理生命周期(proposal → review → apply)。

字段类型说明示例
kairo.evolution.skill.idString (有限集合)技能标识summarize-diff
kairo.evolution.phaseEnum治理阶段PROPOSEDREVIEWEDAPPLIEDROLLED_BACK
kairo.evolution.reviewerString (有限集合)审阅主体sre-ops
kairo.evolution.outcomeEnum审阅结论ACCEPTEDREJECTED

kairo.team.*

用于多 Agent 编排生命周期(Expert Team,v0.10+ 表面开始填充)。

字段类型说明示例
kairo.team.idString (有限集合)团队标识triage-team
kairo.team.roundInteger会话内回合序号2
kairo.team.roleString (有限集合)出场角色triageanalystreporter
kairo.team.expert.idString (有限集合)专家 Agent idlog-reader
kairo.team.transitionEnum状态转移ROUND_STARTROUND_ENDHANDOFFCONSENSUS

低基数约束

上述每个域的属性值都保持在可枚举的有限集合内:

  • 禁止把 request id、trace id、UUID 作为属性值kairo.event.id 是故意为之的例外,单事件单值)。
  • 禁止原始输入内容(prompt、工具参数、模型响应)——必须留在原始 bus payload 中,不导出。
  • 禁止无界的用户自定义字符串。

若属性本身高基数,必须在发布前桶化(例如耗时 → OTel SDK 侧 histogram;用户 id → 角色)。

属性脱敏

kairo.observability.event-otel.redact-attribute-patterns 是一个 regex 列表,匹配平铺键(命名空间拼接后)。命中时,值会在挂到 log record 之前被字面量 <redacted> 替换。常用起步配置:

yaml
kairo:
  observability:
    event-otel:
      redact-attribute-patterns:
        - ".*password.*"
        - ".*token.*"
        - ".*secret.*"

脱敏发生在 exporter 而非发布者——bus 仍会看到原始属性值,但外部观测后端看不到。

OTel 集成(v0.9)

kairo-spring-boot-starter-observability 会在以下条件满足时装配 KairoEventOTelExporter

  1. kairo.observability.event-otel.enabled=true(默认 false,与 v0.9 其他 starter 一致)。
  2. 存在 KairoEventBus bean(只要 kairo-spring-boot-starter-core 在 classpath 就总是成立)。
  3. 存在 LoggerProvider bean(应用自行接入 OTel SDK——可以用 opentelemetry-spring-boot-starter 或手写配置)。

默认 include-domains[security]。execution / team / evolution 域需要显式开启:

yaml
kairo:
  observability:
    event-otel:
      enabled: true
      include-domains: [security, execution, evolution]
      sampling-ratio: 0.2     # 非 security 域采样;security 总是全量

原有 LoggingSecurityEventSink 继续并行工作——它用遗留 security.* 键(无 kairo. 前缀)写结构化 SLF4J 条目,现有 dashboard 在团队迁移到 OTel 路径期间仍可正常运行。域 / 信封契约见 ADR-018,exporter 行为保证见 ADR-022。