---
title: "evlog 与 OpenTelemetry：连接日志与追踪"
description: "通过 OTLP HTTP 将 evlog 事件发送到 OpenTelemetry Collector，并附加活动追踪上下文，而不替换现有追踪"
canonical_url: "https://evlog.zhcndoc.com/compare/opentelemetry"
---
# evlog 与 OpenTelemetry：连接日志与追踪

> 通过 OTLP HTTP 将 evlog 事件发送到 OpenTelemetry Collector，并附加活动追踪上下文，而不替换现有追踪

你已经将追踪导出到 OpenTelemetry Collector，现在希望在旁边添加应用程序日志。evlog 可以构建这些日志事件，并通过 OTLP 发送。保留现有的追踪插桩：evlog 不会创建 spans 或 metrics。

## 为每一层分配职责

The diagram separates two paths into the Collector: the evlog event, which carries your application fields and the active span's IDs, and the spans and metrics the OTel SDK exports on its own.

```text [Data flow]
Application fields -> evlog event -> OTLP HTTP /v1/logs -> Collector -> backend
Active OTel span  -> traceId + spanId on the event
OTel SDK         -> spans and metrics                -> Collector -> backend
```

SDK 为操作添加插桩，Collector 接收并处理遥测数据，前端和后端工具负责存储与可视化。[OpenTelemetry 文档](https://opentelemetry.io/docs/)介绍了 SDK 和 Collector 的职责，[OpenTelemetry 是什么](https://opentelemetry.io/docs/what-is-opentelemetry/)则说明了前端与后端的分工。evlog 会将事件发送到你选择的后端，也可以通过[文件系统](https://evlog.zhcndoc.com/integrate/adapters/self-hosted/fs)和 [NuxtHub](https://evlog.zhcndoc.com/integrate/adapters/self-hosted/nuxthub) 适配器将事件保存在自有文件或数据库中。语义约定统一共享属性，同时仍允许使用自定义应用属性。

## 使用活动 span 上下文导出事件

此示例假设 Node.js 应用已经初始化了其 OpenTelemetry SDK 和上下文管理器。该函数必须在活动 span 内运行，才能附加追踪上下文。如果尚未配置追踪，请参阅 [JavaScript 插桩指南](https://opentelemetry.io/docs/languages/js/instrumentation/)。

在该应用中安装日志包和 OTel API：

```bash [Terminal]
npm install evlog @opentelemetry/api
```

该函数会将完成的结账事件写入本地 JSON，并通过 OTLP 导出。它会显式等待交付完成：导出失败时会记录 drain 名称，但不会抛出异常，因此不会中断请求路径。调用方需要观察失败时，请使用 `drain.raw({ event })`。`raw` 只会尝试一次，失败时会拒绝；默认 drain 会对临时故障重试两次，因此切换到 `raw` 后会失去这些重试，除非在 `createOTLPDrain()` 上设置 `retries`。不要同时在全局注册此 drain，否则会重复导出事件。

```typescript [checkout-log.ts]
import { isSpanContextValid, trace } from '@opentelemetry/api'
import { createLogger, initLogger } from 'evlog'
import { createOTLPDrain } from 'evlog/otlp'

initLogger({ env: { service: 'checkout' }, pretty: false })
const drain = createOTLPDrain({ recordShape: 'compact' })

export async function recordCheckout(orderId: string, outcome: 'paid' | 'declined') {
  const log = createLogger({ orderId, outcome })
  const spanContext = trace.getActiveSpan()?.spanContext()
  if (spanContext && isSpanContextValid(spanContext)) {
    log.set({ traceId: spanContext.traceId, spanId: spanContext.spanId })
  }
  if (outcome === 'declined') log.error(new Error('Payment declined'))
  const event = log.emit()
  if (event) await drain({ event })
}
```

在应用程序的环境中配置 OTLP HTTP 基础端点。如果未设置，drain 会记录缺少端点的警告并跳过交付：

```bash [.env]
OTLP_ENDPOINT=http://localhost:4318
```

通过应用程序或 Node 的 `--env-file` 选项加载该文件。仅有一个名为 `.env` 的文件并不会配置任意 Node.js 进程。

对于本地 Collector，启用 logs pipeline。以下最小配置会通过 debug exporter 打印接收到的记录：

```yaml [otel-collector.yaml]
receivers:
  otlp:
    protocols:
      http:
        endpoint: 127.0.0.1:4318
exporters:
  debug:
    verbosity: detailed
service:
  pipelines:
    logs:
      receivers: [otlp]
      exporters: [debug]
```

使用此配置运行 Collector，并在已插桩的操作中调用 `recordCheckout('order-123', 'paid')`。位于独立容器中的 Collector 需要可访问的接收器地址和端口映射。对于同一主机上的进程，请使用上面的环回配置。

## 在发布前验证关联

通过 `orderId` 查找记录。其 resource 应包含 `service.name: checkout`，`traceId` 和 `spanId` 字段应与同一操作中的活动 span 匹配。没有有效的活动 span 时，事件仍会导出，但不会包含这些标识符。

该 drain 会将级别和时间戳映射到 OTLP 严重性和时间字段。使用 `recordShape: 'compact'` 时，嵌套的应用字段会变成点号分隔的属性。默认 JSON 形状使用序列化的事件 body，并将嵌套属性值作为 OTLP 键值列表发送。设置 `semanticConventions: true` 可在 evlog 字段旁添加 `http.request.method` 和 `gen_ai.usage.input_tokens` 等 OpenTelemetry 属性名称。[OTLP 适配器参考](https://evlog.zhcndoc.com/integrate/adapters/hybrid/otlp)介绍了映射和交付选项。

TraceContext 丰富化器会读取传入的 `traceparent`，并将其 span 标识符记录为 `parentSpanId`，因为该 span 属于调用方。它不会设置 `spanId`。需要将事件关联到服务器 span 时，请像上面一样使用活动的 SDK 上下文。

## 决定采样内容和交付方式

evlog 的事件采样与 [OpenTelemetry 的追踪采样](https://opentelemetry.io/docs/concepts/sampling/)作用于不同信号。evlog 通过 `sampling.rates` 进行头部采样，按日志级别保留一定比例；也通过 `sampling.keep` 进行尾部采样，按状态码、持续时间或路径强制保留请求。[采样](https://evlog.zhcndoc.com/learn/sampling)文档介绍了这两种方式。保留下来的日志可能引用一个已被追踪策略丢弃的 trace。在依赖从每条错误日志跳转到已存储 trace 之前，请协调这两种策略。

这个示例会等待网络请求完成。生产环境的处理器集成需要有意配置 [drain 管道](https://evlog.zhcndoc.com/extend/drain-pipeline)和框架的后台交付生命周期，可从[框架集成](https://evlog.zhcndoc.com/integrate/frameworks/overview)开始。该适配器支持 OTLP HTTP 日志，不支持仅提供 gRPC 的端点。序列化、批处理、重试和导出都会增加成本，而事件构建微基准不会测量这些成本。相关边界见[性能](https://evlog.zhcndoc.com/reference/performance)。

如果你使用 Nitro，集成可以在启用 evlog 后，通过 `evlog:drain` 调用 `createOTLPDrain()`。无论采用哪种设置，都请保留现有的 OTel 插桩。有关库到库的选择，请继续阅读 [evlog 与其他日志记录器的对比](https://evlog.zhcndoc.com/reference/vs-other-loggers)。

---

- [OTLP 适配器](https://evlog.zhcndoc.com/integrate/adapters/hybrid/otlp)
- [性能基准](https://evlog.zhcndoc.com/reference/performance)


## Sitemap

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