npx skills add https://github.com/hugorcd/evlog --skill analyze-logs从本地的 .evlog/logs/ 目录读取并分析结构化宽事件日志,以调试错误、调查性能问题并理解应用程序行为。
日志由 evlog 的文件系统输出器以 .jsonl 文件形式写入,按日期组织。
格式检测:输出器支持两种模式:
pretty: false):每行一个紧凑的 JSON 对象。逐行解析。pretty: true):每个事件为多行缩进 JSON。通过读取整个文件并按顶级对象分割(例如 JSON.parse('[' + content.replace(/\}\n\{/g, '},{') + ']'))或使用流式 JSON 解析器来解析。始终检查文件的前几个字节以检测格式:如果第二个字符是换行符或 ",则为 NDJSON;如果是空格或换行符后跟空格,则为美化格式。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
搜索顺序 — 相对于项目根目录检查以下位置:
.evlog/logs/(默认).evlog/logs/(monorepos:apps/*/.evlog/logs/)使用 glob 模式查找日志文件:
.evlog/logs/*.jsonl
*/.evlog/logs/*.jsonl
apps/*/.evlog/logs/*.jsonl
文件按日期命名:2026-03-14.jsonl。从最新的文件开始。
文件系统输出器可能未启用。引导用户进行设置:
import { createFsDrain } from 'evlog/fs'
// Nuxt / Nitro: server/plugins/evlog-drain.ts
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog: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") |
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)。
读取最新的 .jsonl 文件。每一行是一个 JSON 事件。独立解析每一行。
根据用户的问题进行筛选:
"level":"error" 或 status >= 400pathduration(例如 "706ms")并筛选高值"source":"client" 筛选timestamp 值对于每个相关事件:
path, method, status, levelerror.message, error.data.why 以及堆栈跟踪error.data.fix 获取建议的补救措施Filter: level === "error"
Group by: error.message or path
Look for: recurring patterns, common failure modes
Filter: parse duration string, compare > threshold (e.g. 1000ms)
Sort by: duration 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 特定的结构化错误字段。当它们存在时,提供了最具可操作性的信息。"706ms")。解析数字部分以进行比较。"source":"client" 的事件源自浏览器端日志记录,并通过传输端点发送到服务器。.gitignore 忽略 — 它们仅存在于运行应用程序的本地机器或服务器上。每周安装量
105
代码仓库
GitHub 星标数
962
首次出现
10 天前
安全审计
已安装于
codex105
amp104
gemini-cli104
kimi-cli104
cursor104
opencode104
Read and analyze structured wide-event logs from the local .evlog/logs/ directory to debug errors, investigate performance issues, and understand application behavior.
Logs are written by evlog's file system drain as .jsonl files, organized by date.
Format detection : The drain supports two modes:
pretty: false): One compact JSON object per line. Parse line-by-line.pretty: true): Multi-line indented JSON per event. Parse by reading the entire file and splitting on top-level objects (e.g. JSON.parse('[' + content.replace(/\}\n\{/g, '},{') + ']')) or use a streaming JSON parser.Always check the first few bytes of the file to detect the format: if the second character is a newline or ", it's NDJSON; if it's a space or newline followed by spaces, it's pretty-printed.
Search order — check these locations relative to the project root:
.evlog/logs/ (default).evlog/logs/ inside app directories (monorepos: apps/*/.evlog/logs/)Use glob to find log files:
.evlog/logs/*.jsonl
*/.evlog/logs/*.jsonl
apps/*/.evlog/logs/*.jsonl
Files are named by date: 2026-03-14.jsonl. Start with the most recent file.
The file system drain may not be enabled. Guide the user to set it up:
import { createFsDrain } from 'evlog/fs'
// Nuxt / Nitro: server/plugins/evlog-drain.ts
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('evlog: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() })
After setup, the user needs to trigger some requests to generate logs, then re-analyze.
Each line is a self-contained JSON object (wide event). Key fields:
| Field | Type | Description |
|---|---|---|
timestamp | string | ISO 8601 timestamp |
level | string | info, warn, error, debug |
All other fields are application-specific context added via log.set() (e.g. user, cart, payment).
Read the latest .jsonl file. Each line is one JSON event. Parse each line independently.
Filter based on the user's question:
"level":"error" or status >= 400pathduration (e.g. "706ms") and filter high values"source":"client"timestamp valuesFor each relevant event:
path, method, status, levelerror.message, error.data.why, and the stack traceerror.data.fix for suggested remediationFilter: level === "error"
Group by: error.message or path
Look for: recurring patterns, common failure modes
Filter: parse duration string, compare > threshold (e.g. 1000ms)
Sort by: duration 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 and error.data.fix fields are evlog-specific structured error fields. When present, they provide the most actionable information."706ms"). Parse the numeric part for comparisons."source":"client" originated from browser-side logging and were sent to the server via the transport endpoint..gitignore'd automatically — they exist only on the local machine or server where the app runs.Weekly Installs
105
Repository
GitHub Stars
962
First Seen
10 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex105
amp104
gemini-cli104
kimi-cli104
cursor104
opencode104
MCP服务器模式指南:构建AI助手工具与资源的最佳实践
1,100 周安装
知识检索技能:使用ao CLI和grep搜索过往工作记录、学习成果与模式
164 周安装
App Store Connect 参考指南:崩溃分析、TestFlight反馈与性能指标导出
164 周安装
Nansen 聪明钱分析工具:追踪加密基金和顶级交易者持仓与交易数据
165 周安装
NSFC国家自然科学基金申请书研究内容写作工具 - LaTeX自动化编排助手
165 周安装
SOLID 原则详解:SRP、OCP、LSP 等设计模式,提升代码可维护性与灵活性
167 周安装
WordPress全站编辑(FSE)与区块编辑器指南:theme.json配置与站点编辑器实战
171 周安装
servicestring |
| Service name |
environment | string | development, production, etc. |
method | string | HTTP method (GET, POST, etc.) |
path | string | Request path (/api/checkout) |
status | number | HTTP response status code |
duration | string | Request duration ("234ms") |
requestId | string | Unique request identifier |
error | object | Error details: name, message, stack, statusCode, data |
error.data.why | string | Human-readable explanation of what went wrong |
error.data.fix | string | Suggested fix for the error |
source | string | client for browser logs, absent for server logs |
userAgent | object | Parsed browser/OS/device info |