Compare

evlog 与 LogTape:上下文和配置

比较 LogTape 的类别、应用程序所有者配置、上下文传播,以及使用 evlog 请求事件进行测试

你是在发布一个库,还是在运营一个应用程序?先从谁应该拥有日志配置开始。LogTape 允许库通过类别记录日志,而使用它的应用程序选择输出方式。evlog 提供事件累积功能,以及面向应用程序请求生命周期的集成。

LogTape 同样适用于应用程序。关键在于判断你需要的是它的类别和配置模型、evlog 累积的事件,还是为库代码和应用程序代码分别安排日志记录。请参阅 LogTape 的库指南,了解由使用方拥有配置的契约。

比较上下文和配置

关注点evlogLogTape
事件构建set() 累积字段,直到调用 emit()使用消息模板和属性的结构化记录
组织方式每个操作使用一个 logger,通过 fork() 创建分支具有继承配置的层级类别
显式上下文操作 logger 上的字段logger.with() 附加可复用属性
隐式访问集成中使用由 AsyncLocalStorage 支持的 useLogger()配置了上下文局部存储时使用 withContext()
级别debuginfowarnerrortracedebuginfowarningerrorfatal
测试用于捕获和检查事件的内存排出专用的捕获/断言包和 lint 规则

LogTape 的上下文文档区分了显式上下文和隐式上下文。隐式上下文需要兼容的运行时和已配置的 contextLocalStorage,例如 Node 的 AsyncLocalStorage。它不同于 log.fork(),后者会创建一个累积事件的分支。在假定隐式上下文可在浏览器中运行之前,请先检查运行时支持情况。

比较一次已完成的结账

下面的每个示例都会输出一条带有明确结果的业务记录。结账流程是模拟的,因此两者都不需要支付服务提供商。安装对应的库,然后使用 Node.js 24 运行文件。传入 decline 可测试错误路径。

LogTape 通过应用程序配置的类别记录最终结果:

checkout-logtape.ts
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 中输出:

checkout-evlog.ts
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 的操作模型中没有直接对应项。在将类别映射到上下文字段之前,先决定如何保留这种控制。 如果仪表板或警报依赖这些级别,请有意规划 tracefatal 的映射。

LogTape 提供单独的脱敏和测试包。evlog 会在输出前应用已配置的脱敏,并通过 evlog/memory 提供 createMemoryDrain()readMemoryLogs()clearMemoryLogs()。内存缓冲区会为你的断言提供事件,但它并不是等效的断言 DSL。请将这些工作流与 LogTape 测试指南进行比较。

迁移到 evlog 时,自定义 LogTape sink 也需要明确的交付计划。不要假定配置、刷新或重试行为可以原样迁移。

检查你将要发布的包

不同项目发布的测量结果使用了不同的工作负载、版本和导入方式。特别是,LogTape 的比较表标明了其数据所使用的历史版本。这并不能确定你当前的应用程序包相对于 evlog 的大小或吞吐量。

性能参考解释了 evlog 基准测试的边界。在根据大小或速度做出选择之前,请测量你计划部署的入口点和输出设置。

当使用方拥有的配置、类别或其测试工具是你的设计核心时,请保留 LogTape。当 evlog 的宽事件生命周期、结构化错误和框架集成能够减少应用程序中的代码时,可以考虑 evlog。对于带有序列化器和 worker 传输的 Node.js logger,请参阅 evlog 与 Pinologger 概览介绍了其他选择,而简单日志记录则介绍了 evlog 的逐消息 API。