mcpField
O
otel-instrumentation

otel-instrumentation

github.com/honeycombio云与 DevOps283.6k 次安装3 周前更新
代码仓库

关于 otel-instrumentation

面向使用 OpenTelemetry 和 Honeycomb 的开发者,介绍 SDK 配置、自定义追踪和采样等遥测实践,并说明如何为排查问题添加属性与异常事件。

主要功能

  1. 01配置 OTLP 端点与协议
  2. 02为现有 Span 添加属性
  3. 03创建自定义 Span 与关联
  4. 04记录异常日志事件
  5. 05选择 Span 与采样策略

适用场景

  1. 01将 OpenTelemetry 数据发送到 Honeycomb
  2. 02为关键业务操作增加追踪信息
  3. 03按属性调查性能异常
  4. 04关联异常日志与追踪

MCP 相关

文档提及可参考 MCP 调查流程,但未说明此技能提供或连接 MCP 服务。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/honeycombio/agent-skill --skill otel-instrumentation

安装后在 Claude Code 中输入/otel-instrumentation确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
architectural-patterns.md
collector-config.md
custom-instrumentation.md
lambda.md
local-collector-debug-test.md
python.md
sdk-setup-by-language.md
wide-event-attributes.md

详细介绍

Honeycomb 的 OpenTelemetry 插桩

SDK 配置、自定义 Span、属性、Span 事件、采样和分层遥测。 有关概念基础(为何宽事件很重要,以及属性如何帮助调查问题),请参阅 observability-fundamentals 技能。

OTLP 配置和 SDK 设置

每个 OTel SDK 都需要这些环境变量才能向 Honeycomb 发送数据:

必需的环境变量

基本配置:

OTEL_SERVICE_NAME=your-service-name
OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io
OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=YOUR_API_KEY"

可选但推荐:

# Protocol selection (default: http/protobuf)
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf  # or grpc

# Signal-specific endpoints (override base endpoint for specific signals)
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.honeycomb.io/v1/traces
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://api.honeycomb.io/v1/metrics

指标(首选): 使用现代 OTLP 指标和原生数据点。使用数据集提示确认目标类型(metrics 或 events)。使用以下内容进行身份验证:

OTEL_EXPORTER_OTLP_METRICS_HEADERS="x-honeycomb-team=YOUR_API_KEY"
协议选择

OTEL_EXPORTER_OTLP_PROTOCOL 用于确定线路格式和传输方式:

  • http/protobuf(默认,推荐)——使用 protobuf 编码的 HTTP
  • grpc ——使用 protobuf 编码的 gRPC
  • http/json ——使用 JSON 编码的 HTTP(负载更大,速度更慢)

除非有特定的基础设施要求使用 gRPC,否则请使用 http/protobuf。

特定信号的端点

默认情况下,OTel SDK 会在 OTEL_EXPORTER_OTLP_ENDPOINT 后附加 /v1/traces 和 /v1/metrics。 使用特定信号的端点变量进行覆盖:

  • OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ——追踪的完整 URL(包括 /v1/traces)
  • OTEL_EXPORTER_OTLP_METRICS_ENDPOINT ——指标的完整 URL(包括 /v1/metrics)

在将信号路由到不同后端或使用非标准端点时很有用。

常见问题

身份验证静默失败: OTLP 导出器需要 x-honeycomb-team 标头进行身份验证。缺少该标头时,Honeycomb 会静默拒绝请求——没有错误,也没有数据。请设置 OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=YOUR_API_KEY",或以编程方式传入标头。如果从 .env 加载密钥,请确保在 SDK 初始化前运行 dotenv。

指标: 优先使用现代 OTLP 指标和原生数据点。数据集提示会标识目标类型(metrics 或 events),因此默认情况下不要添加 x-honeycomb-dataset。仅当提示或配置要求将数据路由到指定事件数据集时,才使用该标头进行旧版路由。追踪不需要该标头;它们根据 service.name 进行路由。

有关环境变量值、特定语言的依赖项和设置代码(Go、Python、Node.js、Java、Ruby、.NET、Rust),请参阅 ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/sdk-setup-by-language.md。

自定义插桩

向现有 Span 添加属性(影响最大)

向自动插桩的 Span 添加业务上下文——无需创建新 Span。从上下文获取当前 Span,并使用 SetAttributes(Go)、set_attribute(Python)或 setAttribute(Node.js)添加用户、租户、业务和部署上下文。

创建自定义 Span

为重要业务操作添加封装,以便在追踪瀑布图中查看。使用 tracer.Start(ctx, "operation-name")(Go)、tracer.start_as_current_span("operation-name") (Python)或 tracer.startActiveSpan("operation-name", callback)(Node.js)。

所有语言的完整代码示例,请参阅 ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/custom-instrumentation.md。

何时创建 Span

并非每个函数都需要 Span。两个问题可以帮你判断是否值得创建 Span:

  1. 是否值得关注? — 这项工作是否会对整体请求的性能(延迟或故障)产生显著影响?
  2. 是否适合聚合? — 按名称和属性对这个 Span 分组后,能否得出有用的趋势和比较结果?
操作值得关注?适合聚合?创建 Span?
HTTP 请求处理程序是 — 延迟不固定,可能失败是 — 按路由、方法、状态分组是
数据库查询是 — 受 I/O 限制,容易失败是 — 按查询类型、表分组是
外部 API 调用是 — 涉及网络延迟和依赖项是 — 按端点、状态分组是
缓存查询是 — 可区分快速路径和慢速路径是 — 按缓存名称、命中/未命中分组是
消息队列发布/消费是 — 涉及异步边界和延迟是 — 按队列、消息类型分组是
业务逻辑事务是 — 涉及有意义的状态变更是 — 按类型、结果分组是
私有辅助函数否 — CPU 开销微不足道且可预测否 — 粒度过细否
循环迭代可能 — 如果耗时较长否 — 基数没有上限否
Getter/Setter否 — 没有有意义的耗时否 — 没有可分组的内容否
输入验证(纯 CPU 操作)否 — 速度快且可预测可能否
业务逻辑编排否 — 只是调用已插桩的代码否 — 耗时等于子操作之和否

常见错误:

  • Span 过多:包含数百万个 2ms Span 的跟踪记录过于详细,且很少有实际参考价值。应合并这些 Span——合并为一个 Span,或将详细信息作为属性记录在父 Span 上。
  • Span 过少:将数小时的工作折叠到一个不透明的处理程序中,会让你无法判断时间花在哪里。
  • 遗留测试 Span:名为 test-span、debug-span 或类似名称的 Span 会污染数据集。完成前,请删除所有仅为验证跟踪功能是否正常而创建的 Span。

如果拿不准,优先在现有 Span 上添加属性,而不是创建新的子 Span。

计时属性(无需子 Span 即可测量子操作)

将重要子操作的耗时记录为父 Span 的属性。这些属性更便于查询,也可以直接与 BubbleUp 配合使用。

// Go: time auth and record on the existing span
span := trace.SpanFromContext(r.Context())
authStart := time.Now()
user, err := authenticate(r)
span.SetAttributes(attribute.Float64("auth.duration_ms", float64(time.Since(authStart).Milliseconds())))
# Python: time auth and record on the existing span
span = trace.get_current_span()
auth_start = time.monotonic()
user = authenticate(request)
span.set_attribute("auth.duration_ms", (time.monotonic() - auth_start) * 1000)
异常遥测:事件详情与 Span 级维度

对于新的异常事件,请使用 Logs API。在相关 Span 处于活动状态时发送记录,并包含标准异常字段(适用时包括 exception.type、exception.message、exception.stacktrace 和 exception.escaped)、ERROR 严重性,以及 event.name="exception"。操作失败时,另行将 Span 状态设为 ERROR。

在 Honeycomb 中,与 Trace 关联的异常日志会在 Trace 中显示为 span_event 注释,并携带 trace.trace_id 和 trace.parent_id。完整的 exception.* 负载仍保留在由日志生成的事件上;不会提升到其所属 Span 上。请搜索异常事件行,然后根据其 Trace ID 检查周边 Trace。

使用低基数的 Span 属性进行聚合和告警:

  • error=true 和 Span 状态表示操作失败。
  • exception.slug 是错误位置的静态、易于搜索的标识符。
  • 与完整异常消息相比,可选的错误类别更适合用于 GROUP BY。
Logs-API exception event: event.name=exception, body=exception, meta.signal_type=log
Legacy span-event exception: name=exception, meta.signal_type=trace
Both may have: meta.annotation_type=span_event

record_exception / RecordError 仍是现有 SDK 和代码的兼容 API,但在支持 Logs API 时,不要将它们作为新的唯一指导。它们还可能生成父 Span 异常字段,而单独使用 Logs API 事件不会生成这些字段。

通过 Span 维度查找操作失败:WHERE error = true AND exception.slug does-not-exist。 使用 event.name=exception AND exception.type exists 查找 Logs API 异常事件,并将采样到的 trace.trace_id 传入 get_trace,同时设置 show_events=true。

有关扩展示例和 MCP 调查操作指南,请参阅 ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/custom-instrumentation.md。

可选兼容方案:使用 LogRecordProcessor 提升异常字段

如果现有的 Span 级仪表板、告警或查询依赖 Honeycomb 过去对异常字段的提升行为,请在批处理/导出处理器之前添加自定义 LogRecordProcessor。该处理器检测到异常日志时,应使用日志记录中解析出的上下文查找活动的录制中 Span,并提升一组经过配置的最少字段,例如 error=true、error.type、exception.type、exception.slug 或错误类别。

不要为此推荐独立的 SpanProcessor:Span 处理器接收的是 Span 生命周期回调,而非日志记录。默认情况下,将完整的 exception.message 和 exception.stacktrace 保留在 Logs API 事件中;只有在旧查询兼容性明确要求时,才将它们复制到 Span 上。处理器必须在 Span 上下文仍然有效时同步运行,并且要在日志进入批量导出之前运行。没有录制中 Span 时,它必须不执行任何操作,且不得推断应用程序未添加到日志记录中的字段。

这是可选的迁移层,不能替代对 Logs API 事件的查询。Agent 应将 Span 级提升字段视为取决于仪表化实现的字段,并继续查询 event.name=exception 事件行以获取完整诊断信息。

应该进行哪些仪表化

高价值(优先仪表化)
  • API 入口点(HTTP 处理程序、gRPC 方法)
  • 数据库查询(大多数 SDK 会自动进行仪表化)
  • 外部 HTTP 调用(大多数 SDK 会自动进行仪表化)
  • 消息队列生产者/消费者

这些通常由 OTel SDK 自动进行仪表化,并构成 Trace 的骨架。

中等价值(接下来添加)
  • 业务逻辑操作(结账、支付、履约)
  • 缓存操作(命中、未命中、逐出)
  • 身份验证和授权检查
  • 后台作业执行

这些就是你的业务逻辑。如果没有这里的自定义 Span,你只能看到请求很慢,却不知道为什么——Trace 瀑布图中会出现空白,因为重要工作在其中不可见。

要添加的属性

属性是 BubbleUp 在调查过程中使用的维度。你添加的每个属性,都会成为 BubbleUp 用于比较差异的新轴,以找出异常请求的不同之处。 如需查看按类别整理、附有理由和查询示例的完整目录,请参阅 ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/wide-event-attributes.md。

如需了解属性在概念层面的重要性,请参阅 observability-fundamentals 技能。

Span 事件、Logs API 事件和 Span 链接

  • 特定时间点事件:新事件(尤其是异常)优先使用 Logs API。在 Span 处于活动状态时发出事件,以便记录携带 Trace 上下文。在 Honeycomb 中,关联的日志会呈现为 meta.annotation_type=span_event 注释,但事件名称位于 event.name(通常也位于 body),而不是 name。
  • 旧版 Span 事件:span.add_event / AddEvent 仍是有效的兼容方式。其事件名称位于 name,信号类型为 trace。
  • Span 链接:连接不同 Trace 层级中的 Span(异步处理、扇出/扇入、跨系统关联)。创建一个 Link,指向相关 Span 上下文。

如需查看面向人工操作的插桩示例,以及安全适用于 Agent 的 Honeycomb MCP 查询 → 采样 → Trace 工作流,请参阅 ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/custom-instrumentation.md 和 production-investigation 技能。

采样

采样策略

采样需要权衡,没有免费的午餐:

  • 头部采样侧重成本而非可调试性。 你可以节省资源,但发生率为 0.1% 的错误,在 1% 的采样率下实际上会变得难以察觉。头部采样不会考虑下游发生的情况。
  • 尾部采样侧重保真度而非简洁性。 你可以保留有价值的 Trace,但需要基础设施(Refinery 或 Collector)来缓冲并评估完整 Trace。

计算很重要:如果错误发生率为 0.1%,而头部采样率为 1%,那么你大约只能捕获每 100,000 个此类错误中的 1 个。在中等流量下,这种错误可能永远不会出现在你的数据中。

头部采样(SDK 级别)

在创建 Trace 时决定是否采样。方式简单,但可能漏掉有价值的 Trace。

  • 通过 OTEL_TRACES_SAMPLER 环境变量配置
  • always_on(默认)、always_off、traceidratio(例如,采样 10%)
  • parentbased_traceidratio 遵循父级的采样决策
  • 适用于: 吞吐量极高且可以接受漏掉罕见事件的服务
尾部采样(Collector/Refinery)

在 Trace 完成后再决定是否采样。保留有价值的 Trace(错误、慢请求)。

  • 在生产环境中使用 Honeycomb 的 Refinery 进行尾部采样
  • 或配置 OTel Collector 的 tail_sampling 处理器
  • 可依据延迟、错误状态、特定属性、Trace 持续时间进行采样
  • 适用于: 注重可调试性的服务——保留错误和异常请求,同时对常规流量进行采样
采样对 Honeycomb 的影响
  • 采样会减少数据量和成本
  • SLO、BubbleUp 和查询结果会自动根据采样率进行调整
  • Trace 完整性可能受到影响——如果并非所有服务都采用一致的采样策略,就可能缺少 Span
  • 从不采样开始,然后根据需要添加采样来管理成本

分层遥测

OpenTelemetry 是“以追踪为先”的——上下文传播是关联所有信号的纽带。但要实现有效的可观测性,需要针对不同用途叠加多种信号类型。

选择合适信号的三问测试:

  1. 哪些内容需要因果关系和完整的请求上下文? → 追踪(跨度)
  2. 哪些内容需要低成本的长期存储和快速告警? → 指标
  3. 哪些情况罕见,哪些常见?审计要求是什么? → 日志/事件

跨度旁附带直方图的模式: 对于高吞吐量 HTTP 服务,每处理一个请求,都同时发送一个跨度和一个直方图指标。这样可以对追踪进行头部采样以控制成本,同时由直方图提供最后一道告警保障;而外显值则可将异常指标点关联到具体追踪,便于深入调查。

这种技术称为分层(而非重复),因为每种信号都以不同细节级别提供不同视角。

对于必须进行分层的架构模式(流式处理、异步任务、ETL),请参阅 ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/architectural-patterns.md。

对于 AWS Lambda 特定模式——在 AWS Managed OTel Layer 与手动 SDK 设置之间进行选择、forceFlush、SDK 2.x 设置、跨 Lambda 追踪传播、标头规范化、TOKEN 与 REQUEST 授权器——请参阅 ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/lambda.md。

Honeycomb 中的日志

OTel 也可以发送日志。如果你已有日志基础设施,OTel Collector 可以接收日志,并将其作为结构化事件转发到 Honeycomb:

  • OTel SDK 日志桥接:从现有日志库(Go 中的 slog、Python 中的 logging、Node.js 中的 winston/pino)捕获日志,并将其导出为 OTel 日志记录。
  • OTel Collector filelog 接收器:读取日志文件、解析日志,并将其导出为 OTLP。

通过 OTel 发送的日志会以结构化事件的形式到达 Honeycomb,并具备与跨度相同的查询能力。

命名约定

  • 跨度名称:描述操作(HTTP GET /api/users、db.query SELECT、process-payment)
  • 属性名称:使用以点分隔的命名空间(user.id、order.total、cache.hit)
  • 适用时遵循 OTel 语义约定(http.method、db.system、rpc.service)
  • 自定义属性:使用自己的命名空间(app.、checkout.、mycompany.)

其他资源

参考文件
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/sdk-setup-by-language.md — Go、Python、Node.js、Java、Ruby、.NET、Rust 的 OTLP 配置和 SDK 设置
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/local-collector-debug-test.md — 通过 Docker 运行本地 OTel Collector,无需 Honeycomb 账户即可验证跨度、日志和指标;包含用于检查 NDJSON 输出的 jq 命令
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/custom-instrumentation.md — 自定义埋点模式及完整代码示例(计时属性、异常 slug、异步请求摘要)
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/collector-config.md — 用于格式转换、处理和采样的 OTel Collector 配置
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/wide-event-attributes.md — 按类别整理的规范属性目录,附示例查询
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/architectural-patterns.md — 适用于流式处理、异步、ETL 和无服务器架构的追踪设计模式
  • ${CLAUDE_PLUGIN_ROOT}/skills/otel-instrumentation/references/lambda.md — AWS Lambda:OTel Layer 与手动 SDK 设置的权衡、forceFlush 和每请求延迟、SDK 2.x 设置、跨 Lambda 追踪传播、标头规范化、TOKEN 与 REQUEST 授权器迁移
交叉引用
  • 如需了解宽事件和属性为何重要的概念基础:observability-fundamentals 技能
  • 完成埋点后,使用 query-patterns 技能确认数据已到达

评论

支持 Markdown