@composy/error-core
v0.0.2
Published
Framework-agnostic error management core for LDesign
Readme
@composy/error-core
LDesign 错误处理核心包,提供框架无关的错误模型、捕获、上报、事件、作用域和 Engine bridge。所有框架适配包都应优先复用本包能力,避免复制捕获、去重、限流、上报和诊断逻辑。
安装
pnpm add @composy/error-core分层职责
- catcher:捕获运行时错误、Promise 拒绝、资源错误、网络错误和可选的 console 错误。
- reporter:批量上报、重试、采样、卸载发送和 IndexedDB 离线缓存。
- manager:组合 catcher、reporter 和 emitter,提供统一门面 API。
- scope:为同步或异步流程追加 tags、extra、breadcrumbs 和 userId。
- engine:把 ErrorManager 注册到 LDesign Engine 的 state / events。
- utils:错误规范化、堆栈解析、指纹、限流、环境和 ID 工具。
配置与构建
.ldesign/eslint.config.js和.ldesign/tsconfig.json是本包 ESLint / TypeScript 的权威配置。- 构建使用本目录
.ldesign/builder.config.ts的@composy/builder/ rolldown 配置。 - Playground TypeScript 配置位于
.ldesign/tsconfig.playground.json;tsconfig.json路径保留兼容 shim。 pnpm run type-check检查 core 源码和 Playground,pnpm run build生成并校验发布产物。
快速使用
import { createErrorManager, ErrorLevel, withScopeAsync } from '@composy/error-core'
const manager = createErrorManager({
autoReport: true,
catcher: {
captureNetworkErrors: true,
enableDeduplication: true,
maxErrorsPerMinute: 100,
},
reporter: {
endpoint: '/api/errors',
batchSize: 10,
sampleRate: 1,
},
})
manager.on('error', (error) => {
console.info('[error captured]', error.message)
})
manager.install()
manager.captureMessage('用户进入结算页', ErrorLevel.INFO)
await withScopeAsync(async (scope) => {
scope.setTag('module', 'checkout')
scope.setExtra('orderId', 'SO-1001')
scope.addBreadcrumb({
type: 'click',
category: 'ui',
message: 'submit order',
})
await submitOrder()
})诊断与维护
getDiagnostics() 返回只包含副本的快照,适合调试面板、日志、健康检查和问题复现。
const diagnostics = manager.getDiagnostics()
console.info(diagnostics.stats.total) // 总错误数
console.info(diagnostics.catcher.rateLimitRemaining) // 限流剩余
console.info(diagnostics.reporter.queueLength) // 上报队列长度配置边界
数值配置会在运行时归一化,避免无效值让错误链路失效:
maxErrors、reporter.batchSize和reporter.maxQueueSize最低为1。reporter.sampleRate会限制在0到1;timeout最低为1ms。catcher.maxBreadcrumbs和maxErrorsPerMinute最低为0。0分别表示不保留面包屑,以及在限流启用时拒绝所有捕获。- 重试次数、缓存数量和时间间隔会截断为非负整数;
NaN与无穷值回退为默认值。
运行时开关与去重聚合
ErrorCatcher#setOptions()
支持在应用运行中切换捕获策略。它会保留当前 session、用户和 breadcrumbs;如果实例已经
install(),更新时会先释放旧的全局事件、网络和 console
lease,再按新配置重新安装,避免旧监听器继续生效。将 enabled 设为 false
会同时阻止全局与手动捕获;重新启用后需要显式调用 install() 才会恢复全局监听。
catcher.setOptions({
captureNetworkErrors: false,
captureConsoleErrors: true,
maxErrorsPerMinute: 50,
})当同一 fingerprint 在去重窗口内再次出现时,重复事件仍会触发 ignored,但 ErrorManager
会在已保存的错误上累加 count 并更新 lastSeen,同时保留
firstSeen。这样既不会扩大内存队列,也不会让诊断面板丢失错误发生频率。
ErrorReporter#report() 对采样率采用半开区间语义:sampleRate: 0 始终不入队, sampleRate: 1
始终入队;这避免随机值恰好为 0 时突破零采样策略。
Reporter 内存队列默认最多保留 10,000 条。容量已满时,新到的采样通过错误会被丢弃,已有队列顺序保持不变;
onQueueOverflow 每次 report() / reportBatch() 溢出时报告丢弃数量,回调异常会被隔离。getDiagnostics() 提供累计
overflowCount;reporter.maxQueueSize 可在创建时设置,也可通过 setOptions() 动态调整,缩小时会保留队列头部并裁掉尾部。
reportBatch() 会在整批采样和容量裁剪后统一调度一次发送。
IndexedDB 中待补发的记录只按剩余容量逐条恢复,并在成功交付后继续补入;持久化副本在收到成功 ack 前保留。
数据安全边界
- 错误、网络和资源上下文中的 URL 会移除 query/hash,只保留 origin 与 pathname。
captureConsoleErrors会对循环对象、bigint和抛出异常的toString做安全降级,并遮盖password、token、secret、authorization、cookie与apiKey等字段。ErrorScope(0)表示不保留面包屑;ErrorCatcher#setOptions()可以在运行时切换捕获策略,同时保留当前session、用户和仍在容量范围内的面包屑。
全局监听生命周期
ErrorCatcher 通过 addEventListener 注册全局错误和未处理 Promise 拒绝监听,不会覆盖应用既有的
window.onerror 或
window.onunhandledrejection。多个 ErrorManager 可以同时安装,任一实例卸载只会移除自身监听器。
网络与控制台捕获使用共享拦截器分发给已安装实例,不会随着多个 ErrorManager 形成多层 fetch、XHR 或
console 包装;仅最后一个实例卸载时才恢复宿主函数。
ErrorManager#destroy() 与 ErrorReporter#destroy()
均为终态操作。管理器会立即停止接受安装与捕获;上报器会等待正在处理的请求完成或将失败批次交回内存/离线缓存,再关闭缓存连接。并发销毁调用等待同一次清理;销毁 Promise 完成后,迟到任务不会重新激活资源或触发业务回调。
Reporter 的离线缓存按 appId、endpoint 和 schemaVersion
命名空间隔离。缓存恢复只把数据取得内存队列,不会提前清空持久化副本;只有成功交付并完成 cache
ack 后才删除对应记录。发送失败、beforeSend
抛错或持久化失败时,批次会保留在内存队列或重新写入缓存,避免静默丢失。
ErrorReporter#setOptions() 可动态更新发送与卸载行为;enableOfflineCache 及启用离线缓存时的
appId、endpoint、schemaVersion
创建后固定。需要切换缓存开关或命名空间时,请创建新的 Reporter,避免把一个应用的离线错误发送到另一个端点。
ErrorCatcher 的网络与 console 观察通过 browserPatchBroker 共享。Reporter 请求带有
x-ldesign-error-owner: telemetry:error-reporter
标记,网络捕获器会忽略该 owner,避免错误上报请求再次触发错误上报。
Node 环境下 withScopeAsync() 自动使用 AsyncLocalStorage。浏览器若已有异步上下文实现,可调用
setErrorScopeContextCarrier() 注入 { get, run } carrier;没有 carrier 时仅能保证同步作用域安全。
核心 API
| API | 说明 |
| ------------------------------------------------------------------------- | -------------------------------------------- |
| createErrorManager(options) | 创建统一错误管理器 |
| ErrorManager#install() / uninstall() | 安装或卸载全局捕获 |
| ErrorManager#captureError() / captureMessage() / captureErrorInfo() | 手动捕获错误 |
| ErrorCatcher#setOptions() | 运行时更新捕获开关并同步监听器 |
| ErrorManager#flush() | 立即发送上报队列 |
| ErrorManager#getStats() | 读取错误统计 |
| ErrorManager#getDiagnostics() | 读取不可变诊断快照 |
| ErrorReporter#flush() | 并发调用会复用正在进行的 flush,避免重复请求 |
| withScope() / withScopeAsync() | 执行作用域逻辑,并保留 callback 返回值 |
| createErrorEnginePlugin() | 注册 Engine 插件 |
源码注释
本包所有源码文件均包含完整的中文逐行注释,涵盖:
- 每个模块/类/函数的用途和设计说明
- 参数、返回值和异常的详细描述
- 使用示例和最佳实践
- 性能考虑和兼容性说明
- 内部实现细节和算法解释
类型安全
本包严格禁止使用 any 类型,所有接口和工具类型都使用完整的类型定义:
Record<string, unknown>替代Record<string, any>- 回调参数使用精确类型定义
- 工具类型使用
unknown而非any - 泛型约束确保类型安全
构建产物
本包显式使用 @composy/builder 的内置 rolldown,构建后保持四类产物:
| 目录 | 说明 | 入口 |
| ------- | -------------------------- | ----------------------- |
| es/ | ESM + 类型声明 | module / types 入口 |
| esm/ | 保留模块结构和 Less 源样式 | 二次构建入口 |
| lib/ | CommonJS 产物 | main 入口 |
| dist/ | UMD 与压缩 UMD 产物 | CDN 入口 |
postbuild 会归一化声明、CJS 扩展名、样式和压缩 UMD,再检查入口字段、所有 exports、sourcemap、lib/package.json
与完整目录契约;任一缺失都会让构建失败。
本地验证
# 类型检查
pnpm --dir packages/error/packages/core run type-check
# 运行测试
pnpm --dir packages/error/packages/core run test:run
pnpm --dir packages/error/packages/core run test:watch
# 构建
pnpm --dir packages/error/packages/core run build
pnpm --dir packages/error run outputs:check相关链接
- 家族总览
@composy/error-vue—— Vue 3 适配层
License
MIT © LDesign Team
