---
title: "evlog 与 Pino：请求上下文和迁移"
description: "在将 Pino 应用迁移到 evlog 之前，比较请求上下文、序列化器、传输器和迁移成本"
canonical_url: "https://evlog.zhcndoc.com/compare/pino"
---
# evlog 与 Pino：请求上下文和迁移

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

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

## 比较你需要维护的工作

<table>
<thead>
  <tr>
    <th>
      关注点
    </th>
    
    <th>
      evlog
    </th>
    
    <th>
      Pino
    </th>
  </tr>
</thead>

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

Pino 在其 [API 参考](https://github.com/pinojs/pino/blob/main/docs/api.md)中记录了这些契约。工作线程传输器会将传输处理和交付移到工作线程中。日志记录器仍会在调用线程上执行初始 JSON 序列化。参见 [Pino 传输器](https://github.com/pinojs/pino/blob/main/docs/transports.md)。

## 比较一次已完成的操作

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

使用 Pino 时，应用负责累积上下文，并在 `finally` 中输出：

```typescript [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()` 之后选择错误严重级别：

```typescript [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 的[宽事件模型](https://evlog.zhcndoc.com/learn/wide-events)会很有用。Pino 的 `pino-http` 也提供自动 HTTP 请求日志记录。

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

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

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

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

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

当 Pino 的序列化器、生态系统集成或工作线程传输器已经解决你的问题时，继续使用 Pino。当 evlog 的上下文累加器、结构化错误和框架生命周期能够移除你原本需要维护的应用代码时，选择 evlog。如果选择了 evlog，请从[框架集成](https://evlog.zhcndoc.com/integrate/frameworks/overview)开始。其他选择请参见[evlog 与其他日志记录器比较](https://evlog.zhcndoc.com/reference/vs-other-loggers)。

---

- [性能基准](https://evlog.zhcndoc.com/reference/performance)
- [与其他日志记录器比较](https://evlog.zhcndoc.com/reference/vs-other-loggers)
- [宽事件](https://evlog.zhcndoc.com/learn/wide-events)


## Sitemap

See the full [sitemap](https://evlog.zhcndoc.com/sitemap.md) for all pages.
