@agent-ils/logger
v0.3.0
Published
Local JSONL logger for AI-assisted debugging, with browser writes and CLI reads.
Downloads
71
Readme
AgentILS Logger
@agent-ils/logger 是一个面向 AI 辅助调试的本地 JSONL 日志器。它把前端、后端、WebView、MCP 服务或脚本运行时的关键事件写入本地 JSONL 文件,再让人或 LLM Agent 按尾部条数 / 时间范围把这些原始记录读回来。
它只做两件事:写日志、读日志。它不做自动总结、不做自动根因分析、不把日志压缩成 digest。JSONL 文件就是事实来源。
它同时面向普通用户和 LLM Agent:用户只需运行一条命令启动收集器并读取尾部日志,Agent 也能把它识别为 AgentILS 标准的日志收集方式,而不是凭聊天记录瞎猜失败原因。
本 README 面向用户。如果你需要 LLM Agent 帮你自动化安装、写日志或读日志,请把
LLM_USAGE.md丢给它而不是这份 README——LLM_USAGE.md没有 badges、双语切换等装饰性内容,体积更小,可以显著降低 LLM 的 token 消耗。
使用方式
启动本地日志收集器。它会监听本地 HTTP 接口,并把日志写入目标项目的 .agent-ils/logger/logs。
pnpm:
pnpm dlx @agent-ils/loggernpm:
npx @agent-ils/loggeryarn:
yarn dlx @agent-ils/loggerbun:
bunx @agent-ils/logger如果目标项目不在当前目录,可以传入 --cwd:
npx @agent-ils/logger --cwd packages/my-app启动成功后,默认 endpoint 是:
http://127.0.0.1:12138默认日志目录是:
.agent-ils/logger/logs读取最新 50 条日志:
npx @agent-ils/logger read --tail 50从某个时间点读到最新日志:
npx @agent-ils/logger read --from 2026-04-30T10:00:00Z --format json读取一个固定时间段:
npx @agent-ils/logger read --from 2026-04-30T10:00:00Z --to 2026-04-30T10:10:00Z --format json--from 和 --to 也支持 10m、2h、1d 这类相对时间:
npx @agent-ils/logger read --from 10m --format json包发布前,可以在本仓库中用构建产物测试:
pnpm --filter @agent-ils/logger build
node packages/logger/dist/cli.js read --tail 50npx、pnpm dlx、yarn dlx、bunx 会先运行一个很小的 Node wrapper。
这个 wrapper 必须从系统或 ~/.agent-ils/bin 解析真正的原生
agent-ils-logger 二进制;它会刻意跳过 node_modules/.bin 下的包管理器
shim,避免递归启动自己。
常用命令
显式启动本地日志收集器:
npx @agent-ils/logger serve指定端口和日志目录:
npx @agent-ils/logger serve --port 12138 --log-dir .agent-ils/logger/logs输出机器可读的启动信息:
npx @agent-ils/logger serve --json读取尾部日志:
npx @agent-ils/logger read --tail 80 --format json按稳定字段过滤日志:
npx @agent-ils/logger read --tail 80 --source frontend --level warn --event api.slow --format json按时间范围读取:
npx @agent-ils/logger read --from 2026-04-30T10:00:00Z --to 2026-04-30T10:10:00Z --format json省略 read 子命令但传入读取参数时,CLI 会自动按 read 执行:
npx @agent-ils/logger --tail 80 --format jsonAgent / LLM 用法
如果你想让 LLM Agent 替你安装、启动、写日志或读日志,不要把这份 README 丢给它,请把 LLM_USAGE.md 丢给它——这是给 LLM 看的单页参考,token 消耗远小于本 README。
如果你的 Agent 运行时支持 skill(Claude Code、Copilot、Cursor、AgentILS 等),本包还提供一个召回用的精炼 skill:
node_modules/@agent-ils/logger/dist/templates/llm/agent-ils-logger.skill.md你可以这样让 LLM 自己安装这个 skill:
请读取 node_modules/@agent-ils/logger/dist/templates/llm/agent-ils-logger.skill.md
(如果还没安装包,请从 npm 或 GitHub 拉取最新版),然后把它复制到你当前所在的
Agent 运行时(Codex、Claude Code、Copilot、Cursor、AgentILS 等)的 skill /
instruction 目录里。你知道自己运行在哪个环境上,必要时请查阅该环境的官方文档
确认目录约定。不要凭空猜路径,不确定就先问我。这是有意设计:让运行时的 LLM 自己决定安装位置,包不维护脆弱的 IDE→目录对照表。
CLI 参数
Usage:
agent-ils-logger serve [options]
agent-ils-logger read [options]
Options for serve:
--cwd <dir> 项目根目录,默认当前目录
--host <host> 收集器 host,默认 127.0.0.1
--port <port> 收集器端口,默认 12138
--log-dir <dir> JSONL 日志目录,默认 .agent-ils/logger/logs
--file-prefix <name> 默认 JSONL 文件名前缀,默认 agent-ils
--json 输出机器可读的启动信息
--silent 减少启动输出
Options for read:
--cwd <dir> 项目根目录,默认当前目录
--log-dir <dir> 要扫描的 JSONL 日志目录,默认 .agent-ils/logger/logs
--tail <n> 读取尾部 n 条记录,默认 50
--from <time> 开始时间:ISO 时间、epoch ms,或 10m / 2h / 1d 这类相对时间
--to <time> 结束时间;省略时表示从 --from 读到最新记录
--source <source> 按 source 字段过滤
--level <level> 按 level 字段过滤,大小写不敏感
--event <event> 按 event 字段过滤
--format <format> text、json 或 jsonl,默认 text日志记录结构
每条 JSONL 记录都尽量保持可读、可检索、可被 AI 直接引用。典型记录如下:
{
"ts": "2026-04-30T10:00:00.000Z",
"seq": 1,
"pid": 12345,
"source": "frontend",
"namespace": "frontend",
"level": "info",
"event": "api.response",
"message": "GET /api/users returned 200",
"fields": {
"url": "/api/users",
"status": 200,
"empty": true
},
"traceId": "user-list-001",
"fileName": "frontend-2026-04-30.jsonl",
"filePath": "/Users/me/project/.agent-ils/logger/logs/frontend-2026-04-30.jsonl",
"relativePath": "./.agent-ils/logger/logs/frontend-2026-04-30.jsonl",
"line": 34,
"location": "/Users/me/project/.agent-ils/logger/logs/frontend-2026-04-30.jsonl:34",
"relativeLocation": "./.agent-ils/logger/logs/frontend-2026-04-30.jsonl:34"
}写入成功后,HTTP 返回体会带上实际写入的 record。工具需要稳定打开文件时用
record.location(绝对 path:line);展示给人或 LLM 时优先用
record.relativeLocation,更短也更符合仓库上下文。读取日志时也会带上这些字段;
旧 JSONL 没有存这些字段时,读取逻辑会用当前文件路径和物理行号补齐。
推荐写入字段:
source:日志来源,例如frontend、backend、webview、mcpevent:稳定事件名,例如api.request、api.response、ui.clicktraceId:串起一次用户操作、请求链路或工具调用url/method/status:接口排查最常用字段params/body/empty:判断请求参数和返回内容是否符合预期costMs:排查慢请求或超时error:错误名称、错误消息,必要时含 stack
Browser SDK
@agent-ils/logger/browser 是浏览器安全的写日志方法,会通过 fetch 投递到本地收集器。
import { createBrowserLogger } from '@agent-ils/logger/browser'
const logger = createBrowserLogger({
endpoint: 'http://127.0.0.1:12138',
source: 'frontend',
defaultFields: { app: 'agentils-webview' },
})
await logger.debug('state.transition', { from: 'idle', to: 'loading' })
const result = await logger.info('api.response', { url: '/api/users', status: 200 }, { traceId: 'user-list-001' })
if (result.record) console.log(result.record.relativeLocation ?? result.record.location)
await logger.warn('api.slow', { url: '/api/users', costMs: 3500 })
await logger.error('api.error', { url: '/api/users', message: 'timeout' })可以用 group / groupEnd 把相关日志圈成一组,语义类似 console.group:
const trace = { traceId: 'user-list-001' }
await logger.group('load users', { screen: 'users' }, trace)
await logger.info('api.request', { url: '/api/users' }, trace)
await logger.info('api.response', { url: '/api/users', status: 200 }, trace)
await logger.groupEnd(undefined, trace)组内日志会在 fields 里自动带上 group、groupPath、groupDepth。
group() 会写一条 group.start 记录,groupEnd() 会写一条 group.end 记录。
可以用 child 复用上下文字段:
const taskLogger = logger.child({ page: 'users' })
await taskLogger.info('ui.click', { button: 'refresh' })
await taskLogger.info('api.request', { url: '/api/users' })常用配置:
endpoint:本地收集器地址source:当前 writer 的日志来源defaultFields:每条日志都会带上的字段traceId:默认顶层 trace id。浏览器端如果要按单次调用设置顶层 trace id,请把{ traceId }作为第三个参数传入;defaultFields.traceId只会留在fields内filePrefix:JSONL 文件名前缀fileName:指定 JSONL 文件名enabled:关闭投递但保留调用点overrideKey:当配置值与window.$agentILS.logger.overrideKey匹配时,即使enabled: false也强制记录日志。SSR 环境下window不可用时不生效,直接走enabled原逻辑timeoutMs:每次写日志请求的超时时间onDeliveryError:写入失败时的回调open:为true时构造 logger 后立即启动健康探测,并在 Node 环境自动拉起 collector
写入结果:浏览器端成功写入时返回 { ok: true, status: 200, record }。如果投递被关闭或 collector 尚未就绪,会返回 { ok: true, status: 204 };此时没有写入 JSONL,record 也不存在。发送失败时返回 { ok: false, error }。
Collector 就绪检测:Browser SDK 会在后台每 10 秒探测 GET /api/health,与 log() 调用解耦。只有健康响应 JSON 包含 { "ok": true, "name": "agentils-logger" } 时才算就绪;同端口上其它服务即使返回 2xx,也会被当作未就绪。collector 未就绪时 log() 立即返回 { ok: true, status: 204 },不会请求 /api/logs,因此不会产生 CONNECTION_REFUSED 或误打到其它服务的 404 噪音;发送失败会重置就绪状态并继续后台探测。传入 open: true 可以在构造时就开始探测,并在 Node 环境自动拉起 collector。首次健康探测是异步的;如果第一条浏览器日志就必须拿到 record,请先启动 collector 或先确认 /api/health 的 JSON body 正确。
环境变量行为:Browser SDK 不读取 AGENTILS_DEBUG、AGENTILS_LOG_URL 或 AGENTILS_LOG_DIR;浏览器端请显式传 enabled、endpoint 和 open。createLogger() / createChannelLogger() 会用 AGENTILS_DEBUG 过滤 debug / info(warn / error 始终写出)。createHttpLogger() 默认 endpoint 来自 AGENTILS_LOG_URL,并且只有设置 respectDebugEnv: true 时才尊重 AGENTILS_DEBUG。AGENTILS_LOG_DIR 只影响 Node defaultLogDir() / startHttpLogServer() 默认值;原生 Go CLI 使用 --cwd 和 --log-dir。
日志目录 .gitignore:collector 会在日志目录自动创建内容为 * 的 .gitignore,避免日志文件被误提交。
Node 写入 API
包根入口提供 Node 端的 logger helper,可用于 Node 进程、MCP server 或 VS Code extension host:
import { createHttpLogger, createLogger } from '@agent-ils/logger'
const stderrLogger = createLogger('mcp')
stderrLogger.warn('tool failed', { toolName: 'request_user_clarification' })
const httpLogger = createHttpLogger({
source: 'mcp',
endpoint: 'http://127.0.0.1:12138',
traceId: 'feedback-001',
defaultFields: { component: 'mcp' },
})
httpLogger.group('feedback flow')
httpLogger.info('interaction.submitted', { toolName: 'request_user_feedback', textLen: 42 })
httpLogger.groupEnd()Node HTTP 日志中,traceId 选项会设置默认顶层 trace id;单次调用的
fields.traceId 会覆盖它。defaultFields.traceId 只保留在 fields 内。
createHttpLogger() 是 fire-and-forget:它的方法返回 void,不会把 collector
响应体直接暴露给调用方。如果调用方需要马上拿到写入结果,请使用 Browser SDK
或 raw HTTP API;也可以之后用 @agent-ils/logger/query 把 JSONL 读回来。
HTTP 写入 API
不使用 SDK 时,也可以直接写 HTTP:
curl -X POST http://127.0.0.1:12138/api/logs \
-H 'content-type: application/json' \
-d '{
"source": "frontend",
"level": "info",
"event": "api.response",
"message": "GET /api/users returned 200",
"fields": { "url": "/api/users", "status": 200, "empty": true },
"traceId": "user-list-001",
"filePrefix": "frontend"
}'POST /api/logs 支持单条 payload,也支持 payload 数组。
单条 payload 成功时返回:
{
"ok": true,
"record": {
"event": "api.response",
"filePath": "/Users/me/project/.agent-ils/logger/logs/frontend-2026-04-30.jsonl",
"relativePath": "./.agent-ils/logger/logs/frontend-2026-04-30.jsonl",
"line": 34,
"location": "/Users/me/project/.agent-ils/logger/logs/frontend-2026-04-30.jsonl:34",
"relativeLocation": "./.agent-ils/logger/logs/frontend-2026-04-30.jsonl:34"
}
}数组 payload 成功时返回 { "ok": true, "records": [...] }。
健康检查:
curl http://127.0.0.1:12138/api/health有效的 collector 健康响应类似:
{ "ok": true, "name": "agentils-logger", "logDir": "/abs/project/.agent-ils/logger/logs" }读取 API
如果要在自己的 UI、脚本或 Ink 面板里复用读取逻辑,可以使用 @agent-ils/logger/query:
import { formatLogRecords, readLogRecords } from '@agent-ils/logger/query'
const records = await readLogRecords({
tail: 80,
from: '2026-04-30T10:00:00Z',
})
console.log(formatLogRecords(records, 'json'))读取参数与 CLI 保持一致:tail、from、to、format。程序化 formatter
额外支持 markdown;Go CLI 支持 text、json、jsonl。
不做什么
@agent-ils/logger 故意不做这些事:
- 不做自动 digest
- 不做自动根因分析
- 不做日志数据库
- 不提供复杂查询语言
- 不替人或 AI 下结论
它是观察工具,不是判断工具。
