Compare

evlog 与 Pino:请求上下文和迁移

在将 Pino 应用迁移到 evlog 之前,比较请求上下文、序列化器、传输器和迁移成本

你的 Pino 配置已经能够输出 JSON 日志。接下来的决策是应用如何组装请求上下文。evlog 为该上下文提供累加器和生命周期。Pino 提供 JSON 日志记录、绑定、序列化器和传输器,如果它们已经适合你的应用,你可以继续保留。

比较你需要维护的工作

关注点evlogPino
请求上下文createLogger() 和类型化的 set() 调用会累积字段,直到 emit()child() 会将绑定附加到记录上。应用可以累积一个对象,然后只记录一次
添加绑定set() 会将字段合并到待处理事件中setBindings() 会在创建后添加绑定。它不会覆盖已有键,并且可能引入重复键
错误字段createError() 携带 whyfixlink错误序列化器,包括 pino.stdSerializers.err,会对错误记录进行组织
可扩展性插件和增强器可以接入事件生命周期每个键的序列化器、格式化器和传输器
级别四种严重级别、全局 minLevel、宽事件采样内置和自定义级别、可变的日志记录器级别
交付排空适配器以及可配置的批处理和重试目标和传输器,包括工作线程传输器

Pino 在其 API 参考中记录了这些契约。工作线程传输器会将传输处理和交付移到工作线程中。日志记录器仍会在调用线程上执行初始 JSON 序列化。参见 Pino 传输器

比较一次已完成的操作

两个库都可以为一次操作输出一条结构化记录。安装 pinoevlog,然后使用 Node.js 24 运行相应的 TypeScript 文件。decline 参数会执行失败路径。这些示例模拟相同的结账决策,但不会调用支付服务提供商。

使用 Pino 时,应用负责累积上下文,并在 finally 中输出:

checkout-pino.ts
import pino from 'pino'

const logger = pino()
const context = { orderId: 'order-123', amount: 2999, outcome: 'pending' }
let failure: Error | undefined

try {
  if (process.argv.includes('decline')) throw new Error('Payment declined')
  context.outcome = 'paid'
} catch (error) {
  failure = error instanceof Error ? error : new Error(String(error))
  context.outcome = 'declined'
  process.exitCode = 1
} finally {
  if (failure) logger.error({ ...context, err: failure }, 'checkout completed')
  else logger.info(context, 'checkout completed')
}

使用 evlog 时,日志记录器负责累加器,并在 error() 之后选择错误严重级别:

checkout-evlog.ts
import { createLogger, initLogger } from 'evlog'

initLogger({ env: { service: 'checkout' }, pretty: false })
const log = createLogger({ orderId: 'order-123', amount: 2999, outcome: 'pending' })

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()
}

每个版本都会在任一路径上输出一条记录。两者的信封不同:Pino 使用数字级别及其错误序列化器,而 evlog 会添加事件元数据和持续时间。当多个层贡献字段且框架集成负责请求生命周期时,evlog 的宽事件模型会很有用。Pino 的 pino-http 也提供自动 HTTP 请求日志记录。

在更改整个应用之前先迁移一个处理程序

清点你的仪表板所查询的字段、自定义级别、序列化器和传输器配置。在切换输出之前,明确映射它们。Pino 序列化器无法原样迁移到 evlog 插件中,自定义传输器可能需要新的排空器。

在验证一个 evlog 集成期间,保留不相关处理程序现有的 Pino 路径。除非你有意在查询和摄取成本中对此进行核算,否则避免通过两条路径为同一个请求输出重复记录。使用关于必需字段的相同断言,测试成功请求、抛出错误、关闭和脱敏。

在根据速度做出选择之前先阅读基准条件

代码库中的历史比较使用了静默的 evlog 事件构建、将 Pino JSON 写入 /dev/null,并且在请求生命周期场景中使用了不同的输出数量。它无法建立等效输出吞吐量排名。性能参考记录了工作负载以及如何测量你自己的配置。

当 Pino 的序列化器、生态系统集成或工作线程传输器已经解决你的问题时,继续使用 Pino。当 evlog 的上下文累加器、结构化错误和框架生命周期能够移除你原本需要维护的应用代码时,选择 evlog。如需了解其他选择,请参见evlog 与其他日志记录器比较