API 稳定性
LoggerJS 1.0 让所有 @loggerjs/* 包都进入 1.x,但一个导出承诺多少取决于它的分级。仓库中的 api-reports/ 文件记录了每一个导出的 TypeScript 声明;本页说明每个导出属于哪个分级。
本页是写给人看的稳定性约定。机器可读的分级位于 docs/api-stability.policy.json;如果某个包的导出没有列入该文件,pnpm verify:api-stability 会失败。
当前策略
稳定范围是一个内核:core 的 logger 模型和管线契约、主要的浏览器和 Node 投递路径、主要的浏览器采集 integration、Node 进程采集与 context,以及 pretty 输出。1.0 发布时,早期合作用户还没有在生产环境中运行过这个内核(见 GOVERNANCE.md),因此 compatible 和 experimental 组件哪些升级、调整或弃用,仍由真实使用情况决定。
其他部分仍然公开、有测试、有文档,只是承诺更弱:Compatible 的导出和 Experimental 的包需要先在更早的 minor 中弃用才能变更,而不必等到下一个 major。厂商、可观测性和数据库相关的包保持 Experimental,直到真实使用和故障场景验证足以支持把它们升级。
状态分级
| 状态 | 含义 |
|---|---|
| Stable | 受语义化版本保护:同一个 major 内不删除、不重命名、不破坏签名,安全、数据丢失或线上协议正确性修复除外。新增内容在 minor 中发布。 |
| Compatible | 公开且有测试。只有在更早的 minor 已经将其标为 deprecated 并给出迁移路径之后,后续 minor 才能修改该导出。 |
| Experimental | 生产使用最少的包。它们遵循 Compatible 规则:破坏性变更需要先在更早的 minor 中弃用。当前行为满足需求时可以使用。 |
内部源码路径、dist 文件路径、生成的 bundle 结构、私有类字段,以及只能从测试中推断出的行为,在任何状态下都不属于公开 API。
Stable
稳定的导出记录在 api-stability.policy.json 中。当前稳定的包和入口如下:
| 包 | 稳定范围 |
|---|---|
@loggerjs/core | 根入口内核(createLogger/Logger、getLogger/configure、级别、类型、record 与 event 转换、环境 context、类型化事件、middleware、meta 计数器、错误与安全序列化工具、JSON codec,以及 console、memory、batch、reliability transport),以及 middleware、codec-json、context、events、transport-console、transport-batch、transport-reliability 子路径。 |
@loggerjs/browser | 根入口(core 内核加上本行的 stable 组件)、transport-http、offline-indexeddb、transport-indexeddb、offline-first-transport,以及 console、error、context、page-lifecycle integration。 |
@loggerjs/node | 根入口(core 内核加上本行的 stable 组件)、transport-stdout、transport-file、transport-rotating-file、transport-http、integration-process,以及 AsyncLocalStorage context。 |
@loggerjs/pretty | 根入口、formatter、console transport 和 stream transport。 |
稳定的语义包括:
- 用于应用日志和对库友好日志的
createLogger(options)、getLogger(category)和configure(...)。 - Logger 实例方法:
trace、debug、info、warn、error、fatal、log、capture、event、child、withTags、withType、setLevel、getLevel、isEnabled、isLevelEnabled、addTransport、addProcessor、addIntegration、ready、flush、flushSync和close。 - 级别名称和数值:
trace=10、debug=20、info=30、warn=40、error=50、fatal=60以及silent。 Middleware、Processor、Transport、Integration、Codec这些管线接口,包括TransportContext.toEvent(record)的缓存投影。- 禁用的级别会在分配 record 和计算延迟消息之前返回。
- middleware、processor、codec、integration 和 transport 的错误与应用代码隔离。
- 序列化仍由 transport 负责;middleware 和 processor 处理的始终是结构化的值。
Compatible
Compatible 的导出同样有文档和测试,但它们通过 minor 中的 deprecation 来变更,而不必等到下一个 major。当前属于 Compatible 的部分包括:
- 不在根入口中的 core 模块:
@loggerjs/core/trace-propagation、semantic-events、payload-transforms、diagnostics、integration-api、event-route、codec-metrics、codec-prepared和transport-test。它们在@loggerjs/core根入口的 re-export 在 0.7 标为 deprecated,并已在 1.0 删除;请从这些子路径导入。pnpm verify:api-stability只允许根入口通过 deprecated 的导出项转导出稳定性更低的模块。 - 浏览器的次要 transport 和采集器:BroadcastChannel、service worker、WebSocket、框架错误、框架路由、通用路由采集、ReportingObserver、运行时宿主、service worker 消息、用户操作和 WebSocket 采集。
- 浏览器的 fetch/XHR 采集、web vitals、performance 条目、压缩 payload 转换和支持日志 ZIP 导出。
- Node 的 syslog 和 worker transport、压缩 payload 转换、出站 fetch/HTTP client 采集、diagnostics_channel 采集和 logger 诊断。
- Node 的框架和数据类 integration:Express、Fastify、Koa、Nest、Hapi、Prisma、Redis、通用队列、BullMQ、serverless 生命周期、数据库方法包装和 CLI 采集。
@loggerjs/processors和@loggerjs/codecs目录。单个 processor 和 codec 都很小也很有用,但在真实使用表明哪些真正重要之前冻结约一百个导出,只会锁定错误的那部分。
它们的导入路径在同一个 major 内保持可用。采集字段、钩子覆盖范围和边界行为可以在 deprecation 之后调整,哪些组件升级为 Stable 由真实使用情况决定。
Experimental
以下包之所以公开,是因为它们对集成测试和早期使用者有用,但它们的生产使用最少:
| 包类别 | 实验性导出 |
|---|---|
| 可观测性适配器 | @loggerjs/otel/*, @loggerjs/sentry/* |
| 厂商协议 transport | @loggerjs/datadog/*, @loggerjs/elastic/*, @loggerjs/loki/*, @loggerjs/cloudwatch/* |
| 数据库 transport | @loggerjs/database/* |
实验性不等于没有测试。它的意思是:如果早期合作用户或真实端点表明有更好的设计,选项名、payload 映射、重试预期、批量建议或子路径结构仍可能变化:要么在更早的 minor 中先弃用,要么在厂商端点变化、旧映射失效时通过 patch 修正,这属于线上协议正确性修复。
原始的厂商 transport 本身不具备持久性。生产投递应使用 batchTransport() 和 retryTransport() 包装,或者投递到一个自己负责排队、重试、认证和退避的收集端点。
TypeScript 签名之外的契约
api-reports/ 只能看到 TypeScript 声明。以下契约改由测试保护:
- 线上格式。 codec 输出、logger 产出的事件结构,以及 Node 和浏览器 transport 发出的完整 HTTP 请求,都由
packages/*/test/golden/下的 golden 文件逐字节固定。改动它们就是线上协议变更,适用与所属 API 签名变更相同的策略。 - 浏览器持久化数据。
indexedDbTransport()和indexedDbBrowserHttpOfflineQueue()的 IndexedDB 结构必须能被下一个版本读取。tests/e2e/browser-upgrade.spec.ts用上一个已发布版本写入数据,再用当前代码读取。 - 进程共享状态。 使用
configure({ shareAcrossCopies: true })时,同一进程中加载的所有@loggerjs/core副本(ESM 与 CJS 构建,或两个已安装的版本)共用存放在Symbol.for("@loggerjs/core/shared-state/v1")下的 registry、环境 context 和 meta 计数器;否则各副本保持隔离。registry 中的 logger 由调用configure()的副本创建,因此该副本的诊断 sink 能看到所有这些 logger。同一构建的子路径入口始终通过共享 chunk 共享状态。只有该状态的结构发生不兼容变化时才会修改v1后缀,这属于破坏性变更。整个 1.x 期间默认都保持隔离:库的日志缺失时会有警告,一行配置即可解决;而默认共享会让一个微前端的configure()替换另一个的配置并关闭它的 transport。无论往哪个方向修改默认值,都属于破坏性变更。 - 投递计数。 交给第一方 transport 的每个事件,要么被投递,要么通过
onDrop和transport.dropped.*计数器报告;即使目标端出错,flush()/close()也必须结束。唯一的例外是browserHttpTransport()交给navigator.sendBeacon()的事件:浏览器从不确认它们,因此改为计入transport.beacon.accepted。故障注入测试、基于模型的测试和浸泡测试都会断言这一不变量。
变更策略
一个包的语义化版本保证只覆盖其中的 Stable 导出。其他层级在 1.x 包里保持各自的规则:
- Stable: 同一个 major 内不删除、不重命名、不破坏签名。删除一个 stable 导出,需要先在某个 minor 中标为 deprecated,再在下一个 major 中删除。新增内容在 minor 中发布:新的选项、字段、重载、processor、transport、integration 和子路径。除安全、数据丢失或线上协议正确性修复外,行为变化需要发 major,而这些修复必须在发布说明中写明。
- Compatible: 只有在更早的 minor 已将其标为
@deprecated并给出迁移路径之后,后续 minor 才能修改该导出,且发布说明必须写明。 - Experimental: 适用 Compatible 规则:破坏性变更需要先在更早的 minor 中弃用并给出迁移路径,且发布说明必须写明。厂商端点的线上协议正确性修复是例外,与 Stable 导出相同。
无论哪个层级,影响投递、隐私或性能的默认值都只能在更新文档并写入发布说明后变更;公开导出始终保持类型检查、测试、API 报告和文档齐全,因为“公开”不等于“可以随意丢弃”。
把剩余的 compatible 组件拆成独立的包,可以消除 @loggerjs/browser 和 @loggerjs/node 内部的分层;这仍是以后某个 major 的可选方案。
包的版本
@loggerjs/core、@loggerjs/browser、@loggerjs/node和@loggerjs/pretty承载 stable 内核。它们一起进入 1.0,并组成 Changesets 的linked组,版本号同步变化,用户不需要对照兼容表。- 其他包(
@loggerjs/processors、@loggerjs/codecs、可观测性适配器、厂商 transport 和@loggerjs/database)与内核一起进入 1.0.0,之后按各自的节奏发版,因此某个 processor、codec 或厂商适配器可以单独发 minor 或 major,而不影响内核。它们不在 linked 组中:Changesets 按组内最高版本计算 linked 发布,一个适配器的 major 会把 core 也推到同一个 major。 - 除 core 外的所有包都把
@loggerjs/core声明为 peer dependency,范围是^1.0.0,让一个应用只安装一份 core,前面提到的多副本问题只会出现在真正彼此独立的 bundle 之间。Changesets 启用了onlyUpdatePeerDependentsWhenOutOfRange,因此只要 core 的新版本仍在这个范围内,就不会强制发布每个包;pnpm pack:check会检查这些范围。
新增公开 API
新增包导出时必须:
- 在尽可能贴近真实运行时的层级新增或更新测试。
- 更新文档和示例,说明导入边界和注意事项。
- 把新导出加入
docs/api-stability.policy.json。 - 运行
pnpm verify:api-stability和pnpm api:check。
如果现有的稳定 API 已经能解决问题,优先提供示例和组合方式,而不是新增导出。
如何评估未来的升级
- 阅读包的 changelog 和发布说明。
- 查看本页和
api-stability.policy.json,确认你依赖的导出属于哪个状态。 - 如果你是贡献者,在本仓库运行
pnpm check;如果你是使用者,运行你自己应用的测试套件。 - 对热路径,用
pnpm bench:node或pnpm bench:browser复现相关的基准。 - 对远程投递,测试你真实使用的收集端或厂商端点,并监控
transport.dropped.*、transport.retry.*以及队列深度指标。
