集成
integration 从平台行为中自动采集日志。它们始终需要主动开启:只有配置了对应的 integration,才会采集相应内容。每条采集到的日志都带有 source: "integration:<name>",便于下游过滤和防止回环。
应该开启哪些采集、如何清洗数据等隐私建议,见 运维。
运行时支持
| 运行时 | 支持 | 数量 | 说明 |
|---|---|---|---|
| 浏览器 / 前端 | @loggerjs/browser 中的一方自动采集器 | 19 | console、脚本错误、fetch/XHR、WebSocket、Web Vitals、Performance API、路由、用户操作、service worker、浏览器扩展/Electron 渲染进程钩子,以及浏览器 context 传播。 |
| Node.js / 服务端 | @loggerjs/node 中的一方自动采集器 | 16 | 进程崩溃、diagnostics channel、HTTP 框架、出站客户端、CLI/serverless 生命周期、队列和数据库客户端。 |
| 与运行时无关 / core | @loggerjs/core 只提供 integration API | - | core 包定义 integration 契约和防回环辅助工具;具体的平台采集在 browser 和 Node.js 包中。 |
自定义 integration 应先检测平台能力,不可用时什么也不做。
稳定性分级
integration 的稳定性描述的是公开的 setup/选项契约和拆除行为,并不表示底层平台在每个运行时、浏览器版本、框架版本或部署方式中都会产生每一种信号。
| 级别 | 含义 |
|---|---|
| Stable | 受 1.x 兼容承诺保护。选项名、setup/拆除行为以及采集字段的整体结构受保护。 |
| Compatible | 公开且有测试,但具体字段结构或框架/运行时边界情况的处理仍可能在更早的 minor 中先弃用后再细化。 |
| Runtime-dependent | 公开 API 稳定,但信号本身取决于平台支持、浏览器策略、框架钩子或部署生命周期。 |
| Integration | 稳定性 | 原因 |
|---|---|---|
captureConsoleIntegration() | Stable | 核心的浏览器采集能力,具备防回环和拆除测试。 |
captureBrowserErrorsIntegration() | Stable | 标准的浏览器错误和 rejection 采集;CSP 细节因浏览器而异。 |
captureFetchIntegration() / captureXHRIntegration() | Compatible | 请求/响应采集提供显式的数据清洗钩子,但采集字段仍可能在弃用之后调整。 |
pageLifecycleIntegration() | Runtime-dependent | API 稳定,但 pagehide/visibility 的触发时机由浏览器决定,只能尽力而为。 |
captureWebVitalsIntegration() | Runtime-dependent | 依赖 PerformanceObserver 和浏览器对各项指标的支持。 |
capturePerformanceIntegration() | Runtime-dependent | 能拿到哪些 entry 取决于浏览器、权限策略和页面生命周期。 |
captureReportingIntegration() | Runtime-dependent | ReportingObserver 及报告类型因浏览器而异。 |
captureRouterIntegration() | Stable | 通用浏览器路由的 history/hash 采集稳定。 |
| 框架路由适配器 | Compatible | 公开的适配器有测试,但各框架的钩子形态可能变化。 |
captureFrameworkErrorsIntegration() | Compatible | 公开的辅助 API 稳定;框架错误钩子的 payload 仍由框架决定。 |
captureUserActionsIntegration() | Compatible | 隐私优先的默认值稳定;元素元数据的推断规则可能调整。 |
captureWebSocketIntegration() | Compatible | 构造函数 patch 和事件采集是公开的;采样消息的细节可能变化。 |
captureServiceWorkerIntegration() | Runtime-dependent | 取决于 service worker 是否可用以及其生命周期消息。 |
captureRuntimeHostIntegration() | Runtime-dependent | 浏览器扩展和 Electron 的能力与宿主相关,需要按频道显式开启。 |
browserContextPropagationIntegration() | Stable | 环境 context 绑定契约稳定。 |
captureProcessIntegration() | Stable | Node 崩溃/警告/退出采集以及有时限的 flush 行为属于生产承诺。 |
diagnosticsChannelIntegration() | Runtime-dependent | Node 频道名和 payload 来自 Node 以及已埋点的库。 |
| HTTP 框架 integration | Compatible | Express/Fastify/Koa/Nest/Hapi 适配器是公开的;框架生命周期细节可能调整。 |
nodeFetchIntegration() / nodeHttpClientIntegration() | Compatible | 出站 HTTP 采集是公开的;Node/undici/http 的边界细节可能变化。 |
captureCliIntegration() / serverlessIntegration() | Compatible | 生命周期契约是公开的;平台相关的调用元数据可能细化。 |
queueIntegration() / bullMqIntegration() | Compatible | 通用队列和 BullMQ 操作采集是公开的;队列 payload 元数据有意设计为可配置。 |
databaseIntegration() / prismaIntegration() / redisIntegration() | Compatible | 数据客户端的方法包装是公开的;语句/命令的提取规则可能变化。 |
导入边界
根入口是便捷预设。公开的 integration 子路径都列在这里,方便用户选择更小的 bundle,也防止新的内置 integration 在没有文档的情况下悄悄扩大 API。
| 运行时 | 公开的 integration 子路径 |
|---|---|
| Browser | @loggerjs/browser/integration-console, @loggerjs/browser/integration-context, @loggerjs/browser/integration-errors, @loggerjs/browser/integration-fetch, @loggerjs/browser/integration-xhr, @loggerjs/browser/integration-framework-errors, @loggerjs/browser/integration-framework-routers, @loggerjs/browser/integration-reporting, @loggerjs/browser/integration-router, @loggerjs/browser/integration-runtime-host, @loggerjs/browser/integration-service-worker, @loggerjs/browser/integration-user-actions, @loggerjs/browser/integration-websocket, @loggerjs/browser/integration-web-vitals, @loggerjs/browser/integration-performance, @loggerjs/browser/integration-page-lifecycle |
| Node.js | @loggerjs/node/integration-process, @loggerjs/node/integration-cli, @loggerjs/node/integration-koa, @loggerjs/node/integration-nest, @loggerjs/node/integration-hapi, @loggerjs/node/integration-prisma, @loggerjs/node/integration-redis, @loggerjs/node/integration-queue, @loggerjs/node/integration-bullmq, @loggerjs/node/integration-serverless, @loggerjs/node/integration-database, @loggerjs/node/integration-express, @loggerjs/node/integration-fastify, @loggerjs/node/integration-fetch, @loggerjs/node/integration-http-client, @loggerjs/node/integration-diagnostics |
如果某个公开的 integration 子路径被导出却没有列在这里,pnpm verify:component-docs 会失败。新增条目时也应同步更新上方的稳定性表,以及该类 integration 的运行时验证说明。
浏览器 / 前端(@loggerjs/browser)
| Integration | 采集内容 | 说明 |
|---|---|---|
captureConsoleIntegration() | console.debug/info/log/warn/error/trace 调用 | 级别允许列表(levels)、限流(默认每秒 100 条)。拆除时恢复被 patch 的方法;console transport 通过未被 patch 的方法输出,因此不会形成回环。 |
captureBrowserErrorsIntegration() | window.onerror 的脚本/资源错误、unhandledrejection,以及可选的 CSP 违规 | 对短时间内重复出现的相同脚本错误去重。 |
captureFetchIntegration() | 失败的(状态码 >= minStatus,默认 400)以及按采样率记录的成功 fetch 调用 | header 允许列表、URL 清洗函数。采集后错误仍会重新抛给应用。 |
captureXHRIntegration() | XMLHttpRequest 生命周期,包含状态码和耗时 | 与 fetch 相同的清洗选项。 |
pageLifecycleIntegration() | 在 pagehide / visibilitychange 时 flush 各 transport | 合并短时间内的多次 flush;与 HTTP transport 的 Beacon 模式配合使用。 |
captureWebVitalsIntegration() | CLS、FCP、INP、LCP、TTFB | 通过 PerformanceObserver 输出中间值和最终值。 |
capturePerformanceIntegration() | navigation、resource、longtask、measure、mark 条目 | 去重,并受 maxEntries 限制。 |
captureUserActionsIntegration() | 点击、输入、提交 | 按元素节流;默认不采集文本和输入值。 |
captureRouterIntegration() | 路由变化(pushState/replaceState/popstate/hashchange) | 可选的 state 规范化。 |
captureReportingIntegration() | ReportingObserver 报告(CSP、deprecation、intervention、crash) | 拆除时取出尚未处理的报告。 |
captureServiceWorkerIntegration() | service worker 生命周期、消息、消息错误 | 默认不采集消息数据。 |
captureWebSocketIntegration() | WebSocket 连接/打开/关闭/错误,以及采样的消息 | 包装构造函数;setup 之前创建的 socket 不会被跟踪。 |
captureFrameworkErrorsIntegration() | React/Vue/Solid/Svelte 的错误钩子 | 提供 reactComponentDidCatch()、vueErrorHandler() 等方法;logger 创建前抛出的错误会先缓存(maxPending)。 |
captureRuntimeHostIntegration() | 浏览器扩展消息、指定频道上的 Electron IPC | 默认保守:不监听任何频道。 |
browserContextPropagationIntegration() | session/request/action 以及 trace context | 为 traceparent、baggage、session id、request id 和最近一次用户操作添加环境 context provider。 |
nextRouterIntegration() / reactRouterIntegration() / vueRouterIntegration() / nuxtRouterIntegration() | 框架路由跳转 | 对常见路由 API 的轻量适配;记录前请先清洗 URL。 |
Node.js / 服务端(@loggerjs/node)
| Integration | 采集内容 | 说明 |
|---|---|---|
captureProcessIntegration() | uncaughtException(fatal)、unhandledRejection、warning、退出 | 启用 exitOnUncaught 后,先记录一条 fatal record,调用 flushSync(),最多等待 flushTimeoutMs 让异步 flush() 完成,然后以退出码 1 退出。 未处理的 rejection 遵循 Node 的 --unhandled-rejections 模式:默认会记录为 fatal,flush 后以退出码 1 退出(exitOnUnhandledRejection)。 |
diagnosticsChannelIntegration() | Node diagnostics_channel 消息(http、undici、自定义频道) | 默认不采集消息 payload。 |
expressIntegration(logger) | 请求完成,包含状态码、路由、耗时、request id | 返回一个 Express 中间件;可选地为每个请求绑定 withContext。 |
fastifyIntegration(logger) | 通过 onRequest/onError/onResponse 钩子采集请求生命周期 | 返回一个 Fastify 插件;状态保存在 WeakMap 中。 |
nodeFetchIntegration() | 出站 fetch 调用,包含状态码和耗时 | 采集后错误仍会重新抛出。 |
nodeHttpClientIntegration() | http.request / http.get 调用 | 采集 Node http 客户端的请求生命周期。 |
captureCliIntegration() | CLI 启动、退出码、SIGINT/SIGTERM | 按 token/password/secret 等模式清洗 argv。 |
serverlessIntegration(logger, handler) | 包装 serverless handler:调用、耗时、冷启动、错误 | 支持 promise、callback 和同步 handler。 |
queueIntegration() | 队列客户端操作(publish/consume/ack/nack),包含耗时 | 按客户端 patch 你列出的方法。 |
databaseIntegration() | 数据库客户端调用(query/execute/...),包含语句和耗时 | 语句取自第一个字符串参数,或 .sql/.text/.query 属性。 |
koaIntegration() / nestMiddlewareIntegration() / hapiIntegration() | 框架请求生命周期 | 分别是 Koa、兼容 Express 的 Nest 中间件和 Hapi 请求钩子的轻量适配。Nest 适配器不会接入 Nest 的 exception filter、interceptor、guard,也拿不到原始抛出的 Error。 |
prismaIntegration() | Prisma 原始查询方法 | 只包装 $queryRaw / $executeRaw 系列原始查询方法。不订阅 $on("query"),也不采集 prisma.user.findMany() 这类模型操作。 |
redisIntegration() | Redis 命令方法 | 采集选定的命令方法、耗时、错误和可选的 payload 元数据。 |
bullMqIntegration() | BullMQ Queue 方法调用 | 包装 add、addBulk,以及存在时的旧版 process 方法。不接入 Worker 或 QueueEvents 的 completed、failed、stalled 等生命周期事件。 |
Context 管理器
它不是 integration,但同样在启动时安装一次:
import { installAsyncLocalStorageContext } from "@loggerjs/node";
installAsyncLocalStorageContext();安装后,withContext() 设置的值会跨越 await 跟随异步执行流传递。
编写自定义 Integration
import type { Integration } from "@loggerjs/core";
export function captureThingIntegration(): Integration {
return {
name: "thing",
setup(api) {
const original = thing.onEvent;
const capture = api.guard((payload: unknown) => {
api.capture({
level: "info",
message: "thing event",
props: { payload },
});
});
thing.onEvent = (payload) => {
capture(payload);
return original(payload);
};
return () => {
thing.onEvent = original;
};
},
};
}setup 上下文(api)提供:
capture(input):主要入口,会自动打上source: "integration:thing"。log/trace/debug/info/warn/error/fatal/event/captureException:当 capture 语义不合适时,可以直接调用这些日志方法。guard(fn):为回调加上重入计数。如果被 patch 的对象本身会被日志管线触发(典型场景是 console 采集 + console transport),递归调用会被丢弃并计入 meta(integration.dropped.reentrant),而不会无限递归。unpatched:原始console.*/fetch/XMLHttpRequest实现的注册表,在所有 integration 之间共享,因此多次 patch 可以正确叠加。flush/flushSync/close:供页面隐藏等由生命周期驱动的 integration 使用。
面向 integration 作者的辅助函数在 @loggerjs/core/integration-api 中:createIntegrationSetupContext() 可以在 logger 之外构造 setup context(适合测试),getUnpatchedRegistry() / registerUnpatchedDefaults() 提供共享的平台原始函数注册表,onceTeardown() 让 teardown 只执行一次。Integration 和 IntegrationSetupContext 类型仍从 @loggerjs/core 导入。
注意事项:
- 始终返回一个拆除函数,恢复你 patch 过的内容。拆除函数会在
logger.close()时按 setup 的相反顺序各执行一次。 - setup 对每个 integration 实例 只执行一次;创建两个实例就会 patch 两次。请导出工厂函数并在文档中说明。
- 优雅降级:先检测平台能力,缺失时什么也不做。
- 采集原始的结构化数据,让 processor 负责脱敏;不要提前格式化消息。
