evlog 与 Pino:请求上下文和迁移
你的 Pino 配置已经能够输出 JSON 日志。接下来的决策是应用如何组装请求上下文。evlog 为该上下文提供累加器和生命周期。Pino 提供 JSON 日志记录、绑定、序列化器和传输器,如果它们已经适合你的应用,你可以继续保留。
比较你需要维护的工作
| 关注点 | evlog | Pino |
|---|---|---|
| 请求上下文 | createLogger() 和类型化的 set() 调用会累积字段,直到 emit() | child() 会将绑定附加到记录上。应用可以累积一个对象,然后只记录一次 |
| 添加绑定 | set() 会将字段合并到待处理事件中 | setBindings() 会在创建后添加绑定。它不会覆盖已有键,并且可能引入重复键 |
| 错误字段 | createError() 携带 why、fix 和 link | 错误序列化器,包括 pino.stdSerializers.err,会对错误记录进行组织 |
| 可扩展性 | 插件和增强器可以接入事件生命周期 | 每个键的序列化器、格式化器和传输器 |
| 级别 | 四种严重级别、全局 minLevel、宽事件采样 | 内置和自定义级别、可变的日志记录器级别 |
| 交付 | 排空适配器以及可配置的批处理和重试 | 目标和传输器,包括工作线程传输器 |
Pino 在其 API 参考中记录了这些契约。工作线程传输器会将传输处理和交付移到工作线程中。日志记录器仍会在调用线程上执行初始 JSON 序列化。参见 Pino 传输器。
比较一次已完成的操作
两个库都可以为一次操作输出一条结构化记录。安装 pino 或 evlog,然后使用 Node.js 24 运行相应的 TypeScript 文件。decline 参数会执行失败路径。这些示例模拟相同的结账决策,但不会调用支付服务提供商。
使用 Pino 时,应用负责累积上下文,并在 finally 中输出:
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() 之后选择错误严重级别:
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 与其他日志记录器比较。