离线监控审计项目与自测
项目目标
在不连接监控平台、云账号或真实密钥的条件下,完成一条可验证的“遥测契约 → 指标 → SLO/错误预算 → 行动”链路。项目只用Python 3标准库:
- 严格校验结构化事件、Trace、Metric label、Collector与遥测治理契约;
- 验证教学用W3C
traceparent、父子Span和事件—Trace关联; - 计算RED、USE、p95、SLI、短/长窗口坏事件比例与错误预算燃烧率;
- 同时检查质量、安全、费用、Agent步数/token和观测完整性;
- 输出
OK、TICKET或PAGE、完整SHA-256监控证据、声明的摘要格式与仅供展示的短指纹; - 为非
OK窗口生成不含原文、仅供人工分诊的回归候选; - 用45项离线测试覆盖正常、异常、非法输入、release绑定、完整摘要、摘要格式、业务事件时效与CLI退出码。
项目文件均使用vault限定链接,避免同名文件歧义:
- monitor_audit.py:契约验证、指标计算和决策CLI;
- telemetry_windows.json:版本化教学策略、SLO及两个窗口;
- test_monitor_audit.py:标准库
unittest测试。
环境准备
主要环境是Windows 11、PowerShell 7和当前稳定Python 3。先学习venv + pip的标准流程;本项目没有第三方依赖,因此无需安装包。以下代码块按顺序从同时包含 docs/ 与 .website/ 的项目根目录开始运行。为避免在vault中生成.venv,把虚拟环境放到系统临时目录:
$projectDir = (Resolve-Path -LiteralPath 'docs\运行监控\03-项目与自测\examples').Path # 把示例目录解析为绝对路径,避免当前目录影响命令。
$venvDir = Join-Path $env:TEMP "ai-agent-engineer-monitoring-venv" # 虚拟环境放到系统临时目录,不写进 vault。
python -m venv $venvDir # 创建隔离的标准库 Python 环境。
& (Join-Path $venvDir "Scripts\Activate.ps1") # 激活该环境,使后续 python 使用隔离解释器。
Push-Location -LiteralPath $projectDir # 进入脚本与 fixture 所在目录,结尾会恢复。若本机策略不允许激活脚本,可直接使用& (Join-Path $venvDir "Scripts\python.exe") ...。本项目无需网络或API key,也不会写报告文件;不要将虚拟环境复制进知识库。
输入契约
顶层JSON分为policy、slo和scenarios。读取器先拒绝重复JSON字段、非标准数值、原始无效 UTF-8 字节和不能作为严格 UTF-8 标量序列编码的 Unicode surrogate,验证器再使用精确字段集合:缺字段、未知字段、错误类型、非法枚举、非有限数、无法表示为有限 float 的数字、重复ID和未排序时间都会失败,避免后出现的同名字段静默覆盖前值、完整摘要计算时泄露未受控编码异常,也避免悄悄忽略拼写错误。slo.good_statuses还必须是事件status枚举的子集;否则一个拼错但非空的“好状态”会让全部事件被错误计为坏事件。
每个 scenario 还用带时区的window_end固定观察终点,window_minutes据此反推出起点;所有事件必须落在这段窗口内。event_data_age_seconds则是最后一条业务事件距该终点的时龄,和 Collector 的最后导出时龄分开:Collector 仍可成功导出一个已经停滞的业务流。超过policy.max_event_age_seconds会产生PAGE,而不是把旧事件当成当前短窗口。window_end是离线 fixture 的声明时间,不是可信授时服务。
每个scenario还必须有release_evidence:release_id、release_manifest_sha256、candidate_gate_evidence_sha256和candidate_gate_evidence_digest_format均为严格字段,其中两个摘要必须是完整的 64 个小写十六进制字符(256 位 SHA-256 摘要),后一个格式字段必须是本仓库当前支持的版本化教学 profile。所有事件的release必须与release_id一致。此fixture的两套release证据是独立教学样例,不声称能与LLMOps项目的固定值直接互换;生产系统应在同一发布清单上端到端验证语义、字节表示与摘要。
evaluate_scenario()还在每个Decision中返回evidence_digest_format;非OK的regression_handoff会分别携带上游candidate_gate_evidence_digest_format和本窗口的monitor_evidence_digest_format。三处都使用python-json-sorted-utf8-v1这一受控的本地 Python 教学格式,并以固定 golden vector 约束字节表示;未知格式会被拒绝。这个约束只说明接收方应如何复算,不能证明 release evidence 的来源、制品完整性或批准真实性;跨语言哈希/签名仍需交换经验证的字节,或使用并互操作测试明确规范(例如 RFC 8785 JCS)。
事件与Agent信号
每个事件包括:
request_id、带时区时间、service、release和受控intent;- 技术
status、latency_ms、trace_id; - provider、model snapshot、模型/工具调用数、Agent步数、输入/输出token;
- 可为
true/false/null的质量标签,null明确表示真值未知; - 安全检查状态、违规结果和估算费用。
脚本会拒绝“未执行安全检查却宣称发现违规”等矛盾。provider/model字段是本地契约示例,不声称对应任何供应商当前SDK字段。
Trace与传播
每条Trace包含人工构造的教学ID和Span树。验证器检查:
- W3C版本
00形状、32 个小写十六进制字符且非全零的Trace ID、16 个小写十六进制字符且非全零的父Span ID及00/01标志; traceparent中的Trace ID与记录一致;- 恰有一个根Span、Span ID唯一、父Span真实存在且无环;
- 根Span的service、release、status和duration与事件可关联。
这些ID不来自真实用户或生产系统。traceparent只用于传播关联,不能作为认证凭据。
遥测与Collector治理
metric_label_keys必须来自有限allowlist,request_id、完整发布摘要与gate摘要等高基数值会被拒绝。它们只可在受控Trace或审计Log中用于交接。遥测策略检查原始内容采集是否关闭、脱敏检查和保留期;Collector信号覆盖accepted、refused、sent、failed、queue和最后导出时龄。资源信号用USE检查CPU利用率、队列饱和和资源错误。
指标与行动口径
| 口径 | 本项目定义 | 解释边界 |
|---|---|---|
| RED Rate | 声明窗口内事件数 ÷ window_minutes | 教学事件率,不是流量预测 |
| RED Errors | status == error比例 | 技术失败,不等于任务质量 |
| RED Duration | 全部教学事件的nearest-rank p95 | 不代表特定监控平台算法 |
| SLI好事件 | status合格且延迟不超过SLO目标 | 事件定义和延迟目标已版本化 |
| 坏事件比例 | SLI合格事件以外的事件占比 | 单一观察窗口的直接测量量 |
| 燃烧率 | 坏事件比例 ÷ (1 - SLO目标) | 1x表示按允许预算匀速消耗,而非“剩余预算” |
| 业务事件时龄 | window_end − 最新事件时间 | 与 Collector 导出时龄分别检查;过大表示业务流可能停滞 |
| Trace完整率 | 具有可验证关联Trace的事件比例 | 缺失表示证据不足,不表示请求不存在 |
| 质量通过率 | 已标签事件中的通过比例 | 必须与标签覆盖率并列 |
| 安全违规率 | 已检查事件中的违规比例 | 必须与安全检查覆盖率并列 |
| 成本/Agent结构 | 每请求估算成本、步数、token均值 | 是教学估算,不是真实账单 |
短窗口从声明的window_end倒推5分钟,长窗口覆盖完整60分钟;因此“最后一条事件”不能偷偷重定义两个窗口。项目故意不输出error_budget_remaining_ratio:剩余预算需要完整SLO合规窗口的已用预算、人口和排除规则,不能从此处60分钟教学窗口推出。决策优先级为OK < TICKET < PAGE:持续的短/长窗口高速燃烧、安全/隐私策略失败、Collector失明、业务事件陈旧或Trace完整率不足可升级到PAGE;延迟、标签、质量、成本、Agent结构和USE调查线可生成TICKET。阈值属于local-monitor-policy-v3教学策略,不是Google、Prometheus或OpenTelemetry推荐的通用数值。
运行场景
先运行健康窗口:
$env:PYTHONDONTWRITEBYTECODE = "1" # 禁止生成 __pycache__,保持教学目录无缓存。
python .\monitor_audit.py --scenario stable-window # 运行证据充分的健康窗口。
if ($LASTEXITCODE -ne 0) { throw "stable-window未按预期返回0" } # 健康场景应以 OK/退出码 0 完成。预期首行为OK: stable-window,短/长燃烧率为0.00/0.00,并显示event_age=60s。再运行故障窗口:
python .\monitor_audit.py --scenario incident-window # 运行包含 SLO、安全和 Collector 问题的事故窗口。
if ($LASTEXITCODE -ne 1) { throw "incident-window未按预期返回1" } # PAGE 是受控动作,因此返回 1 而非崩溃。预期首行为PAGE: incident-window,本地样例的短/长燃烧率为5.00/2.50,随后列出SLO、安全、Collector、Trace、质量、成本和资源等判定理由,并输出regression_candidate=needs_human_triage。该候选只有release证据与有限Trace引用,raw_content_included=false;它不是冻结数据集的自动写入。
evaluate_scenario()返回的Decision.evidence_sha256和Decision.evidence_digest_format是完整运行摘要及其字节 profile;仅在非OK时,regression_handoff把同一值以monitor_evidence_sha256和monitor_evidence_digest_format带到待人工分诊候选,同时保留它接收的 candidate gate 格式。CLI故意只打印16字符evidence_fingerprint,适合人读而不足以担当跨系统交接;真实集成应在受控记录/API中保存完整值、格式、来源验证与批准边界。
CLI退出码契约:
0:所选场景为OK;1:至少一个场景需要TICKET或PAGE;2:文件、JSON或数据契约错误。
这让脚本可用于离线检查,但真实PAGE仍需所有者、runbook、路由、抑制和端到端通知验证。
运行测试与语法检查
下面四组测试分别覆盖正常解释器、禁用断言、将 warning 视为错误,以及两项解释器开关的组合。测试不依赖生产代码中的assert:
python -m unittest -v test_monitor_audit # 正常解释器模式执行全部单元测试。
if ($LASTEXITCODE -ne 0) { throw "normal tests failed" } # 普通模式失败时立即中断验证。
python -O -m unittest -v test_monitor_audit # 验证生产校验不依赖 -O 移除的 bare assert。
if ($LASTEXITCODE -ne 0) { throw "optimized tests failed" } # 优化模式也应得到相同的回归结果。
python -W error -m unittest -v test_monitor_audit # 将 warning 升级为失败,避免兼容性问题被忽略。
if ($LASTEXITCODE -ne 0) { throw "warnings-as-errors tests failed" } # 严格告警模式必须通过。
python -O -W error -m unittest -v test_monitor_audit # 组合优化模式与“警告即错误”进行最严格复跑。
if ($LASTEXITCODE -ne 0) { throw "optimized warnings-as-errors tests failed" } # 四种模式均通过才完成本地验证。再做不写.pyc的最小语法检查:
python -c "from pathlib import Path; [compile(p.read_text(encoding='utf-8'), str(p), 'exec') for p in map(Path, ('monitor_audit.py', 'test_monitor_audit.py'))]" # 在内存中编译实现与测试,检查语法而不写 .pyc。
if ($LASTEXITCODE -ne 0) { throw "syntax check failed" } # 语法失败不能被后续目录恢复掩盖。
Pop-Location # 恢复执行本项目之前的终端目录。测试会覆盖严格schema、观察窗口边界、业务事件时龄、非有限数、无法表示为有限 float 的数字、原始无效 UTF-8、UTF-8 不可编码 surrogate、固定摘要 golden vector、Trace Context、父子Span、环、事件关联、高基数label、Collector与安全矛盾、release evidence、完整SHA-256、人工分诊候选、决策优先级和CLI退出码。通过测试只能证明本地契约与实现一致,不能证明真实监控后端或通知链路可用。
动手练习与扩展
- 新增
ticket-window,让长窗口超标而短窗口未超PAGE线,断言结果为TICKET; - 新增一个全部质量标签为
null的合法窗口,验证输出明确写“任务质量未知”而不是质量为零; - 为异步工具Span增加link教学字段,先写失败测试,再扩展精确schema与环检测;
- 将决策输出序列化为stdout JSON,保留策略/SLO版本和证据指纹,但不要覆盖输入或生成历史产物;
- 将健康窗口末条事件提前两分钟而保持Collector新鲜,确认业务事件陈旧仍会PAGE;解释为什么两种时龄不能互相替代。
- 为每条PAGE理由建立离线runbook映射,并测试缺少owner、runbook或恢复条件时不能进入真实通知路由。
自测题
- 为什么HTTP成功且质量标签缺失时,不能把请求记为质量成功?
- 为什么Trace采样率下降与Metric label基数上升是两个不同问题?
- 为什么短窗口和长窗口同时越线,比单个瞬时阈值更适合PAGE?
- 为什么Collector导出时龄过高时,其余“正常”指标也不可信?
- 为什么
traceparent格式正确仍不能证明请求已授权? - 为什么 Collector 导出新鲜仍不足以证明业务事件流是当前的?
- 为什么incident窗口退出码
1在测试中是成功验证,而不是脚本崩溃?
掌握检查
- 能解释JSON契约中的每个分母、未知值和版本字段;
- 能从RED症状下钻到USE资源、Trace和结构化事件;
- 能手算SLI、错误预算和短/长窗口燃烧率;
- 能区分质量、安全、成本、Collector健康与观测完整性;
- 能运行45项测试,并理解
-O、-W error及其组合验证的风险; - 能解释燃烧率、剩余错误预算、完整证据摘要和展示指纹的不同边界;
- 能说明所有ID、阈值和模型字段只是离线教学契约;
- 能把真实系统仍需验证的采集、传播、后端、通知、隐私和合规边界列清。
项目边界与下一步
本项目证明的是:输入契约、关联、指标口径和本地决策可被确定性验证。当前slo只是target + latency_objective_ms + good_statuses的Layer A教学契约,尚未把服务人口、排除规则、完整合规窗口、数据源与变更审批固化为可审计的SLO对象;因此既不能把样例窗口的燃烧率当作生产SLO合规证据,也不能计算生产剩余错误预算。window_end与时龄检查只证明 fixture 内的时间关系,不代表可信授时、真实流量完整性或端到端采集正确。回归候选同样只是受限审计产物,必须按 离线到线上证据交接与回归闭环 经人工分诊、脱敏、去重和复现后才可接纳。它也没有连接真实SDK、Collector、监控后端、供应商计费、通知链路或用户真值,没有进行Obsidian阅读视图验证。实战中应先在沙箱接入 仪器化、Collector 与关联 的流水线,再用 事件响应与复盘 演练从症状到遏制和恢复的完整链路。
参考资料
- W3C Trace Context(W3C Recommendation,访问于2026-07-22)
- OpenTelemetry Collector internal telemetry(访问于2026-07-22)
- OpenTelemetry Sampling(访问于2026-07-22)
- Google SRE: Service Level Objectives(访问于2026-07-22)
- Google SRE Workbook: Alerting on SLOs(访问于2026-07-22;数值阈值未直接复制)
- Prometheus Histograms and summaries(访问于2026-07-22;项目使用自定义nearest-rank,不模拟Prometheus查询)