evlog 与 LogTape:上下文和配置
你是在发布一个库,还是在运营一个应用程序?先从谁应该拥有日志配置开始。LogTape 允许库通过类别记录日志,而使用它的应用程序选择输出方式。evlog 提供事件累积功能,以及面向应用程序请求生命周期的集成。
LogTape 同样适用于应用程序。关键在于判断你需要的是它的类别和配置模型、evlog 累积的事件,还是为库代码和应用程序代码分别安排日志记录。请参阅 LogTape 的库指南,了解由使用方拥有配置的契约。
比较上下文和配置
| 关注点 | evlog | LogTape |
|---|---|---|
| 事件构建 | set() 累积字段,直到调用 emit() | 使用消息模板和属性的结构化记录 |
| 组织方式 | 每个操作使用一个 logger,通过 fork() 创建分支 | 具有继承配置的层级类别 |
| 显式上下文 | 操作 logger 上的字段 | logger.with() 附加可复用属性 |
| 隐式访问 | 集成中使用由 AsyncLocalStorage 支持的 useLogger() | 配置了上下文局部存储时使用 withContext() |
| 级别 | debug、info、warn、error | trace、debug、info、warning、error、fatal |
| 测试 | 用于捕获和检查事件的内存排出 | 专用的捕获/断言包和 lint 规则 |
LogTape 的上下文文档区分了显式上下文和隐式上下文。隐式上下文需要兼容的运行时和已配置的 contextLocalStorage,例如 Node 的 AsyncLocalStorage。它不同于 log.fork(),后者会创建一个累积事件的分支。在假定隐式上下文可在浏览器中运行之前,请先检查运行时支持情况。
比较一次已完成的结账
下面的每个示例都会输出一条带有明确结果的业务记录。结账流程是模拟的,因此两者都不需要支付服务提供商。安装对应的库,然后使用 Node.js 24 运行文件。传入 decline 可测试错误路径。
LogTape 通过应用程序配置的类别记录最终结果:
import { configure, getConsoleSink, getLogger } from '@logtape/logtape'
await configure({
sinks: { console: getConsoleSink() },
loggers: [
{ category: 'checkout', lowestLevel: 'info', sinks: ['console'] },
{ category: ['logtape', 'meta'], lowestLevel: 'warning', sinks: ['console'] },
],
})
const logger = getLogger('checkout').with({ orderId: 'order-123', amount: 2999 })
try {
if (process.argv.includes('decline')) throw new Error('Payment declined')
logger.info('Checkout {outcome}', { outcome: 'paid' })
} catch (error) {
logger.error('Checkout {outcome}: {error}', { outcome: 'declined', error })
process.exitCode = 1
}
evlog 会累积结果,并在 finally 中输出:
import { createLogger, initLogger } from 'evlog'
initLogger({ env: { service: 'checkout' }, pretty: false })
const log = createLogger({ orderId: 'order-123', amount: 2999 })
try {
if (process.argv.includes('decline')) throw new Error('Payment declined')
log.set({ outcome: 'paid' })
} catch (error) {
log.error(error instanceof Error ? error : new Error(String(error)))
log.set({ outcome: 'declined' })
process.exitCode = 1
} finally {
log.emit()
}
这些示例比较的是上下文和输出的所有权,而不是等效的输出格式或速度。这里 LogTape 的控制台 sink 会将记录格式化后输出到终端。evlog 配置为 JSON。两个示例都不会在检查结果之前记录成功,也不会重复记录失败。
围绕你使用的功能规划迁移
类别特定的详细程度在 evlog 的操作模型中没有直接对应项。在将类别映射到上下文字段之前,先决定如何保留这种控制。 如果仪表板或警报依赖这些级别,请有意规划 trace 和 fatal 的映射。
LogTape 提供单独的脱敏和测试包。evlog 会在输出前应用已配置的脱敏,并通过 evlog/memory 提供 createMemoryDrain()、readMemoryLogs() 和 clearMemoryLogs()。内存缓冲区会为你的断言提供事件,但它并不是等效的断言 DSL。请将这些工作流与 LogTape 测试指南进行比较。
迁移到 evlog 时,自定义 LogTape sink 也需要明确的交付计划。不要假定配置、刷新或重试行为可以原样迁移。
检查你将要发布的包
不同项目发布的测量结果使用了不同的工作负载、版本和导入方式。特别是,LogTape 的比较表标明了其数据所使用的历史版本。这并不能确定你当前的应用程序包相对于 evlog 的大小或吞吐量。
性能参考解释了 evlog 基准测试的边界。在根据大小或速度做出选择之前,请测量你计划部署的入口点和输出设置。
当使用方拥有的配置、类别或其测试工具是你的设计核心时,请保留 LogTape。当 evlog 的宽事件生命周期、结构化错误和框架集成能够减少应用程序中的代码时,可以考虑 evlog。对于带有序列化器和 worker 传输的 Node.js logger,请参阅 evlog 与 Pino。logger 概览介绍了其他选择,而简单日志记录则介绍了 evlog 的逐消息 API。