你已经将追踪导出到 OpenTelemetry Collector,现在希望在旁边添加应用程序日志。evlog 可以构建这些日志事件,并通过 OTLP 发送。保留现有的追踪插桩:evlog 不会创建 spans 或 metrics。
为每一层分配职责
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 接收并处理遥测数据,而 backend 提供存储、查询和告警。OpenTelemetry 文档 介绍了这些职责。语义约定统一共享属性,而自定义应用属性仍然有效。
使用活动 span 上下文导出事件
此示例假设 Node.js 应用已经初始化了其 OpenTelemetry SDK 和上下文管理器。该函数必须在活动 span 内运行,才能附加追踪上下文。如果尚未配置追踪,请参阅 JavaScript 插桩指南。
在该应用中安装日志包和 OTel API:
npm install evlog @opentelemetry/api
该函数将已完成的结账事件写入本地 JSON,并通过 OTLP 导出。它会显式等待交付完成,因此调用方可以观察到导出失败。不要同时在全局注册此 drain,否则事件会被导出两次。
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 基础端点:
OTLP_ENDPOINT=http://localhost:4318
通过应用程序或 Node 的 --env-file 选项加载该文件。仅有一个名为 .env 的文件并不会配置任意 Node.js 进程。
对于本地 Collector,启用 logs pipeline。以下最小配置会通过 debug exporter 打印接收到的记录:
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 适配器参考介绍了映射和交付选项。
TraceContext enrichers 可以读取传入的 traceparent,但其父 span 标识符不一定是活动的 server span。当你需要精确关联到该 span 时,请像上面一样使用活动的 SDK 上下文。
决定采样内容和交付方式
evlog 中的事件采样和 OpenTelemetry 中的追踪采样 作用于不同的信号。保留的日志可能引用一个被追踪策略丢弃的 trace。在依赖从每条错误日志导航到已存储 trace 之前,请协调好这些策略。
此示例会等待网络请求完成。对于生产环境的 handler 集成,请有意配置 drain pipeline 和框架的后台交付生命周期。该适配器支持 OTLP HTTP logs,不支持仅限 gRPC 的端点。序列化、批处理、重试和导出都会增加成本,而事件构建微基准不会测量这些成本。有关这些边界,请参阅 性能。
如果你使用 Nitro,集成可以在启用 evlog 后,通过 evlog:drain 调用 createOTLPDrain()。无论采用哪种设置,都请保留现有的 OTel 插桩。有关库到库的选择,请继续阅读 evlog 与其他日志记录器的对比。