关于 analyze-logs
通过分析本地保存的 evlog 宽事件日志来排查应用行为的技能,可帮助开发者检查错误、慢请求、请求记录及行为模式,并可使用 CLI 或直接读取日志文件。
主要功能
- 01使用 evlog CLI 查询日志
- 02按时间、状态、路径或字段筛选
- 03检查错误和慢请求
- 04按请求 ID 跟踪事件
- 05读取文件系统及内存日志
适用场景
- 01排查近期应用错误
- 02查找缓慢的端点和请求
- 03检查指定请求 ID 的活动
- 04比较不同路由的错误模式
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ evloghq/ evlog --skill analyze-logs安装后在 Claude Code 中输入/analyze-logs确认已加载。
详细介绍
分析应用日志
读取并分析本地 .evlog/logs/ 目录中的结构化宽事件日志,以调试错误、调查性能问题并了解应用行为。
适用场景
- 用户要求调试错误、调查 Bug 或了解某项功能为何失败
- 用户询问请求模式、响应缓慢的端点或错误率
- 用户询问应用“发生了什么”或“现在是什么情况”
- 用户要求分析日志、检查近期错误或查看应用行为
- 用户提及他们遇到的特定错误消息或状态码
查找日志
优先尝试 CLI;它会读取两种文件布局、所有日期的文件,并且知道项目的日志写入器将日志写到哪里。优先使用项目安装的副本(pnpm evlog,或适用于其包管理器的等效命令)。按需获取的封装命令(npx、bunx、npm exec)会在项目尚未安装 @evlog/cli 时安装它,而运行的版本并未由锁文件固定。发生这种情况前,请先询问。
pnpm evlog logs --json # the last 50 events
pnpm evlog logs errors --since 1h --json # what failed
pnpm evlog logs slow --over 1s --json # what was slow, worst first
pnpm evlog logs "$REQUEST_ID" --json # one request, every event with that id
pnpm evlog logs stats --json # per route: count, errors, p50, p95; by status and level
pnpm evlog logs --where 'payment.amount>5000' --where audit.outcome=failure --json
--json 输出的是一个信封对象(包含 sources、view、matched、events;stats 则包含 stats);筛选选项包括 --since、--until、--level、--path、--status(500 或 5xx)、可用于任意点分字段的 --where field=value|field>n|field~regex|field|!field(可重复指定)、--limit、用于指定非默认目录的 --dir,以及用于通过 HTTP 访问暴露 readMemoryLogs() 的内存日志写入器中的应用的 --url。从 monorepo 根目录运行时,它会读取所有应用的 .evlog/logs 并为每条事件添加标签。文档:https://www.evlog.dev/cli/logs。如果 CLI 不可用或用户拒绝使用,请按下文直接读取文件。
evlog 的文件系统日志写入器会将日志写入按日期组织的 .jsonl 文件。
格式检测:日志写入器支持两种模式:
- NDJSON(默认,
pretty: false):每行一个紧凑的 JSON 对象。逐行解析。 - Pretty(
pretty: true):每条事件使用多行缩进 JSON。可以读取整个文件并按顶层对象拆分(例如,JSON.parse('[' + content.replace(/\}\n\{/g, '},{') + ']')),也可以使用流式 JSON 解析器。
始终检查文件的前几个字节以检测格式:如果第二个字符是换行符或 ",则为 NDJSON;如果是空格,或换行符后跟空格,则为 pretty 格式。
搜索顺序。 检查相对于项目根目录的以下位置:
.evlog/logs/(默认)- 应用目录中的任何
.evlog/logs/(monorepo:apps/*/.evlog/logs/)
使用 glob 查找日志文件:
.evlog/logs/*.jsonl
*/.evlog/logs/*.jsonl
apps/*/.evlog/logs/*.jsonl
文件以日期命名:2026-03-14.jsonl。从最新的文件开始。
以编程方式读取:无需手动解析,可以使用 evlog 提供的读取器编写小脚本:evlog/fs 中的 readFsLogs() 和 tailFsLogs() 是异步生成器,可处理两种格式、日期排序和筛选。如果项目已安装 evlog,且分析所需操作不止快速 grep,请优先使用它们。
内存日志写入器替代方案:某些应用会使用 Memory 适配器(evlog/memory),而非(或同时使用)FS 日志写入器,并通过仅限开发环境的 HTTP 端点使用 readMemoryLogs() 暴露近期事件。如果 .evlog/logs/ 为空,但应用接入了 createMemoryDrain(),请改为查询该端点。
如果没有找到日志
在接入新的日志写入器前,可以尝试 npx evlog doctor --json,它会检查是否安装了 evlog,以及是否已存在本地 .evlog/logs 日志写入器(只读)。此步骤可选;如果 CLI 不可用,请跳过。
文件系统日志写入器可能未启用。对于 Nuxt、Nitro、Next.js、TanStack Start、Hono、Express 或 Fastify,最快的方法是使用 CLI;它会检测框架并一次性接入 fs 日志写入器(其默认开发日志写入器):
npx evlog init --dry-run --yes # preview first
npx evlog init --yes --drain fs # apply
运行前请先询问。对于其他框架(或用户拒绝时),请指导用户手动设置:
import { defineEvlog } from 'evlog'
import { createFsDrain } from 'evlog/fs'
// Nuxt / Nitro: evlog.config.ts at the app root, which the module loads
export default defineEvlog({ drain: createFsDrain() })
// Hono / Express / Elysia: pass in middleware options
app.use(evlog({ drain: createFsDrain() }))
// Fastify: pass in plugin options
await app.register(evlog, { drain: createFsDrain() })
// NestJS: pass in module options
EvlogModule.forRoot({ drain: createFsDrain() })
// Standalone: pass to initLogger
initLogger({ drain: createFsDrain() })
设置完成后,用户需要触发一些请求以生成日志,然后重新分析。
日志格式
每一行都是一个独立的 JSON 对象(宽事件)。主要字段:
| 字段 | 类型 | 说明 |
|---|---|---|
timestamp | string | ISO 8601 时间戳 |
level | string | info、warn、error、debug |
service | string | 服务名称 |
environment | string | development、production 等 |
method | string | HTTP 方法(GET、POST 等) |
path | string | 请求路径(/api/checkout) |
status | number | HTTP 响应状态码 |
duration | string | 请求耗时,使用便于阅读的格式("234ms") |
durationMs | number | 请求耗时,单位为毫秒。请使用此字段进行筛选和排序 |
requestId | string | 唯一请求标识符 |
error | object | 错误详情:name、message、stack、statusCode、data |
error.data.why | string | 对出错原因的易读说明 |
error.data.fix | string | 针对错误的修复建议 |
source | string | 浏览器日志为 client;服务器日志中不存在此字段 |
userAgent | object | 解析后的浏览器/操作系统/设备信息 |
所有其他字段均为通过 log.set() 添加的应用专属上下文(例如 user、cart、payment)。
如何分析
步骤 1:读取最新的日志文件
读取最新的 .jsonl 文件。每一行都是一个 JSON 事件。分别解析每一行。
步骤 2:找出相关事件
根据用户的问题进行筛选:
- 错误:
"level"为"error"或"fatal"、status >= 500,或事件中包含error对象;这也是evlog logs errors的匹配规则。单独出现 4xx 状态码不算客户端错误,但如果 4xx 事件还带有另外两个信号之一,也会匹配;读取status或传入--status 4xx可查看所有此类事件 - 特定端点:按
path匹配 - 慢请求:按
durationMs筛选(例如durationMs > 500) - 特定用户/操作:按应用专属字段匹配
- 客户端问题:按
"source":"client"筛选 - 时间范围:比较
timestamp值
步骤 3:分析并说明
针对每个相关事件:
- 发生了什么:概述
path、method、status、level - 失败原因(错误):查看
error.message、error.data.why和堆栈跟踪 - 如何修复:查看
error.data.fix中的修复建议 - 上下文:检查应用专属字段,了解业务背景(用户信息、付款详情等)
- 模式:查找重复出现的错误、性能下降或相关故障
分析模式
查找所有错误
Filter: level === "error"
Group by: error.message or path
Look for: recurring patterns, common failure modes
查找慢请求
Filter: durationMs > 1000
Sort by: durationMs descending
Look for: specific endpoints, time-of-day patterns
跟踪特定请求
Filter: requestId === "the-request-id"
Result: single wide event with all context for that request
按端点统计错误率
Group events by: path
Count: total events vs error events per path
Look for: endpoints with high error ratios
客户端与服务器错误
Split by: source === "client" vs no source field
Compare: error patterns between client and server
Look for: client errors that don't have corresponding server errors (network issues)
重要说明
- 每一行都是一个完整、独立的事件。与传统日志不同,你无需关联多行日志。一行就包含了一个请求的所有上下文。
error.data.why和error.data.fix字段是 evlog 专用的结构化错误字段。存在这些字段时,它们会提供最具可操作性的信息。duration使用带单位的易读格式(例如"706ms")。durationMs表示相同的耗时,单位为毫秒;请使用durationMs进行筛选和排序。"source":"client"的事件源自浏览器端日志,并通过 HTTP drain 端点发送到服务器。- 日志文件会自动加入
.gitignore。它们仅存在于运行应用的本地计算机或服务器上。