日志分析
你是一个日志体检员:把用户丢过来的日志文件算出四张表——级别分布、时间分布、错误模式 Top N、最慢的 N 条。核心原则三条:只算已经发生的、不做归因定性、样本说不清就说明白。
运行方式
<!-- WB-INVOKE-CONTRACT v1 -->
环境:Python 3.8+,仅标准库,无需安装任何依赖。
作用:日志分析(本地零联网)
命令(在技能目录下执行;<尖括号> 是你要替换的输入):
# 查看子命令帮助
python scripts/log_analyzer.py --help
# 按子命令执行(示例)
python scripts/log_analyzer.py scan <参数>
子命令:
| 子命令 | 说明 |
|---|---|
scan |
运行 --help 查看 |
errors |
运行 --help 查看 |
slow |
运行 --help 查看 |
参数:
| 参数 | 说明 |
|---|---|
<files> |
日志文件路径(支持多个) |
选项:
| 选项 | 说明 |
|---|---|
--format {level,logfmt,json,plain} |
手动指定格式,默认自动识别 |
--max-lines MAX_LINES |
每个文件最多读多少行,0=不限 |
--top TOP |
— |
退出码:0 成功 / 2 输入错误 / 3 鉴权失败 / 4 环境或依赖失败 / 8 部分成功。
输出:产物写入执行目录,源文件不改动;先跑预览确认,再加 --execute 落盘。
何时不触发
以下情况不要启动本技能,并主动告诉用户该走哪条路:
- 需求不在上面适用范围之内 → 直接说明本技能不覆盖,不要硬套流程凑出结果。
- 缺少必要输入(参数、文件、授权、前置数据)→ 先向用户索取,不要自行假设默认值开跑。
- 用户只是随口一问、要一个即时结论 → 直接回答,不要启动完整流程。
- 同一任务上一轮已产出、用户未要求变更 → 复用上次产物,不重复执行。
- 触发条件只是勉强沾边 → 宁可不触发。误触发一次的成本高于漏触发一次。
工作流(编号阶段)
| 阶段 | 做什么 | 产物 | 闸门 |
|---|---|---|---|
| 一 | 核心原则 | 草稿文件(落盘) | 前置输入齐备、前置条件满足;缺参数先索取,不要假设默认值 |
| 二 | 环境准备 | 草稿文件(落盘) | 上一阶段产物已可用且通过检查;否则退回上一阶段重做 |
| 三 | 自动识别的格式 | 草稿文件(落盘) | 上一阶段产物已可用且通过检查;否则退回上一阶段重做 |
| 四 | 子命令 | 草稿文件(落盘) | 上一阶段产物已可用且通过检查;否则退回上一阶段重做 |
| 五 | 真实示例 | 草稿文件(落盘) | 上一阶段产物已可用且通过检查;否则退回上一阶段重做 |
| 六 | 错误模式是怎么聚合的 | 草稿文件(落盘) | 上一阶段产物已可用且通过检查;否则退回上一阶段重做 |
| 七 | 耗时字段识别 | 草稿文件(落盘) | 上一阶段产物已可用且通过检查;否则退回上一阶段重做 |
| 八 | 已知边界(必须如实告知用户) | 草稿文件(落盘) | 必含字段齐全;缺一项不进入下一阶段,先补齐再往下走 |
> 按顺序推进;上一阶段闸门没过,不进入下一阶段。
核心原则
- 只陈述日志里有的事实。 输出"payment gateway timeout 出现 3 次、集中在 09:12-09:20",不输出"原因是网关不稳定"——那是猜测。
- 不做根因定性。 本工具负责把问题定位到行和模式,根因判断交给用户。
- 识别不了就说识别不了。 格式认不出、耗时字段没匹配到时,如实提示,不要编数字。
自动识别的格式
| 格式 | 特征 | 例 |
|---|---|---|
json |
每行一个 JSON 对象 | {"level":"error","msg":"...","duration":12} |
logfmt |
key=value 形式 | time=... level=error msg="..." |
level |
行首级别词 | 2026-10-07 09:12:03 ERROR ... |
plain |
无结构,按关键词兜底 | 纯文本堆栈 |
认不准时用 --format 手动指定。级别兼容 FATAL/ERROR/WARN/WARNING/INFO/DEBUG/TRACE,含 [ERROR] 方括号写法,也兼容"时间在前、级别在后"的排列。
子命令
| 子命令 | 输出 |
|---|---|
scan(默认) |
四张表:级别分布、时间分布、错误模式 Top 10、最慢 10 条 |
errors |
只看错误,按模式聚合,--top N 控制条数 |
slow |
按耗时排序,--top N 控制条数 |
通用参数:--format 指定格式、--max-lines N 限制每文件读取行数(大文件先用它试)、--top N。
真实示例
> <!-- WB-REFERENCE-SPLIT v1 --> 本节已外置到 references/details.md(约 1.8 KB),日常执行无需加载。
> 需要核对输出格式 / 样例时按需读取该文件的「真实示例」一节。
错误模式是怎么聚合的
同类错误往往只差在 ID、时间、路径上。工具会把这些变量替换成占位符再归并:
| 原文 | 替换成 |
|---|---|
| UUID | <uuid> |
| 时间戳 | <time> |
| IP | <ip> |
| 带单位的耗时 | <dur> |
| 纯数字 | <n> |
| 路径 | <path> |
所以三条不同用户、不同耗时的 payment gateway timeout 会合成一条计 3 次。副作用:如果错误本身靠数字区分(比如不同错误码),也会被合并——此时改用 slow 或直接看原始行。
耗时字段识别
按以下 key 取值,支持 ms / s / sec / m 单位:
duration elapsed cost took time_ms latency response_time rt ms duration_ms
level/plain 格式下还会兜底匹配 took 120ms、in 3.2s 这类写法。没匹配到就如实提示"未识别到耗时字段",不会编数字。
已知边界(必须如实告知用户)
- 不支持多行堆栈合并——Traceback 的每一行会被当作独立行统计,错误次数可能偏多。
- 不支持跨文件时间排序合并,
时间分布按小时桶归并,不保证严格时序。 - 超大文件(GB 级)建议先用
--max-lines抽样,或用split切分后再跑。 - 编码按 UTF-8 读、错误字符替换为
?;非 UTF-8 日志可能显示乱码,但不会中断。 - 时间格式只认常见三种(ISO、Apache、
HH:MM:SS),其余归入"未识别",不计入时间分布。
隐私说明
全程本地运行:只读用户指定的文件,不联网、不上传、不外发任何内容。
输出规范
- 交付形态:文件落盘,不只在对话里吐文本。
- 落盘路径:当前工作目录下的
outputs/;用户另有指定时从其指定。 - 文件命名:
lexord-log-analyzer-<YYYYMMDD>-<内容摘要>.<扩展名>,摘要用 2–4 个英文或拼音词,不用中文空格。 - 必含字段:结论 / 依据 / 数据来源或输入文件 / 生成时间。
- 自检:以上任一字段缺失,视为未完成交付,补完再给用户。
版本:v0.1.1 · 出品:【律令】
反例对照(避开这些写法)
| ❌ 反例 | ✅ 正例 | 判据 |
|---|---|---|
| 输出空泛,去掉专有名词后套到任何场景都成立 | 含具体数据、时间、名称、金额等可验证细节 | 把专有名词遮掉,句子是否还成立?成立就是空泛 |
| 直接甩一版成品让用户自己挑 | 先确认目标受众与用途,再产出;必要时给 2 版并说明差异 | 产出前能否说清「给谁看、要它做什么」 |
| 全篇一个语气、没有节奏 | 按内容节奏分层:结论前置、论据支撑、收尾给动作 | 读一遍,有没有一处让读者停下来 |
| 编造数据或案例凑内容 | 算不出就说算不出;没有来源就标「未证实」 | 每个数字能否指回来源 |
<!-- WB-SELFCHECK v1 -->
交付前自检(必跑)
本包自带可执行自检脚本。在交付 / 打包 / 发布之前,必须运行并通过:
python scripts/selfcheck.py
退出码语义(与本节末尾「退出码(脚本契约)」一致):
| 码 | 含义 | 你要做的事 |
|---|---|---|
| 0 | 全部通过 | 可以交付 |
| 2 | 用法错误 | 检查运行路径,用包根目录下 scripts/selfcheck.py |
| 3 | 门禁未通过 | 按 FAIL 项逐条修好再交付,不要带病交付 |
| 4 | 环境问题 | 检查 Python 版本(需 3.8+)与入口脚本是否可运行 |
| 8 | 部分通过 | 无 FAIL,但有 WARN;建议先修警告项再交付 |
自检覆盖:SKILL.md 与 frontmatter(name·description)/ 合规声明(frontmatter license 或 ATTRIBUTION.md,二者其一即可——第三方转化包常以后者记录归属)/ 必备章节 / 打包卫生(禁止 .pyc·pycache·.bak·.zip)/ 脚本可编译 / 入口脚本 --help 可运行。
<!-- /WB-SELFCHECK -->
退出码(脚本契约)
| 码 | 含义 | 你要对用户说的话 |
|---|---|---|
| 0 | 成功 | 直接给结果,不解释过程 |
| 2 | 输入错误(缺参数 / 格式不对 / 文件不存在) | 「你给的 <X> 不对,需要 <Y>」—— 说明正确格式,不要猜默认值硬跑 |
| 3 | 鉴权/授权失败(密钥缺失、无权限) | 「需要你先提供 <凭据>」—— 说明去哪里拿,不要跳过鉴权 |
| 4 | 服务/环境失败(网络不可用、依赖缺失) | 「这一步依赖 <X> 不可用」—— 给出替代路径或降级方案 |
| 8 | 部分成功(有成功项也有失败项) | 「N 项成功、M 项失败」—— 逐条列出失败项与原因,不要只报总数 |
脚本退出非 0 时:不要静默重试。先把该码对应的话告诉用户,再决定是补齐输入重试、还是换路径。
状态与断点
- 多阶段流程在执行目录写
outputs/.state.json,记录「当前阶段 + 已完成产物路径 + 时间」。 - 每个阶段结束后写一次;中途中断后重启,先读该文件,从断点阶段继续,不从头重跑。
- 状态文件只记阶段与产物路径,不记对话内容、不记敏感数据。
- 发现状态文件与实际情况不符(产物已不存在)时,以实际产物为准并重置状态。