mcpField
O
otel-generic-style

otel-generic-style

github.com/superloglabs开发13370 次安装21 周前更新
代码仓库

关于 otel-generic-style

面向没有专属配套风格的语言,提供通用 OpenTelemetry 实践指南。内容涵盖 SDK 选择、追踪、指标、日志、资源属性及 OTLP/HTTP 备用方案。

主要功能

  1. 01使用官方语言 SDK 和 HTTP OTLP 导出器
  2. 02跨度与错误处理规范
  3. 03指标和资源属性指南
  4. 04OTLP/HTTP JSON 备用方案
  5. 05自动插桩建议

适用场景

  1. 01为 Go 或 Java 服务添加遥测
  2. 02为有明确边界的业务操作插桩
  3. 03转发带追踪上下文的日志
  4. 04在缺少 SDK 的运行时发送 OTLP

安装

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

$npx skills add https://github.com/superloglabs/skills --skill otel-generic-style

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

详细介绍

通用 OTel 风格

适用于没有专属 otel-*-style 配套指南的语言(Go、Java/Kotlin、Ruby、Rust、.NET/C#、PHP、Elixir,以及不使用 Next.js 或 Expo 的纯 Node/TypeScript 等)。请先阅读 otel-onboarding-style 了解跨语言规则;本指南是该指南的语言无关版本。

如果你正在使用的运行时有对应的语言专属指南(otel-python-style、otel-fastapi-style、otel-livekit-style、 otel-nextjs-style、otel-expo-style、otel-supabase-edge-style),请优先使用该指南——它会覆盖本指南。

使用语言官方的 OTel SDK

从 OpenTelemetry 项目获取该语言的 SDK 和导出器。 不要围绕它们自行设计辅助 API。示例:

  • Go:go.opentelemetry.io/otel、otel/sdk、otel/exporters/otlp/otlptrace/otlptracehttp
  • Java/Kotlin:io.opentelemetry:opentelemetry-sdk + opentelemetry-exporter-otlp(或使用 Java agent 进行自动插桩)
  • Ruby:opentelemetry-sdk、opentelemetry-exporter-otlp、opentelemetry-instrumentation-all
  • Rust:opentelemetry、opentelemetry_sdk、opentelemetry-otlp
  • .NET/C#:OpenTelemetry、OpenTelemetry.Exporter.OpenTelemetryProtocol、框架 OpenTelemetry.Instrumentation.* 包
  • PHP:open-telemetry/sdk、open-telemetry/exporter-otlp
  • Elixir::opentelemetry、:opentelemetry_api、:opentelemetry_exporter
  • 纯 Node/TS:@opentelemetry/sdk-node + @opentelemetry/auto-instrumentations-node(Next.js 使用 @vercel/otel——参见 otel-nextjs-style)

使用 HTTP OTLP 导出器,不要使用 gRPC。gRPC 会引入原生绑定,导致打包器、精简容器和无服务器环境的冷启动出现问题。

在模块/包作用域内只获取一次 Tracer/Meter

无论该语言惯用的“模块顶部”写法是什么——Go 中的包级变量、Java/.NET 中的静态字段、Ruby/Node 中的文件顶部常量, 或 Elixir 中 @moduledoc 级别的属性。不要在每次调用时都新建 Tracer 或 Meter。

// Go
var (
    tracer = otel.Tracer("mugline.api")
    meter  = otel.Meter("mugline.api")
    ordersSubmitted, _ = meter.Int64Counter("orders.submitted")
)
// Java
private static final Tracer TRACER = GlobalOpenTelemetry.getTracer("mugline.api");
private static final Meter METER = GlobalOpenTelemetry.getMeter("mugline.api");
private static final LongCounter ORDERS_SUBMITTED =
    METER.counterBuilder("orders.submitted").build();

有界工作

对于任何起止边界明确的函数,创建一个覆盖整个操作且会自动结束的 Span。使用该语言内置的构造——defer span.End()、try-with-resources、using、with、块语法等。对于有界工作,不要在一处启动 Span,却在其他位置手动结束。

ctx, span := tracer.Start(ctx, "order.submit")
defer span.End()
span.SetAttributes(
    attribute.String("tenant.id", tenantID),
    attribute.String("order.id", orderID),
)
using var activity = ActivitySource.StartActivity("order.submit");
activity?.SetTag("tenant.id", tenantId);
activity?.SetTag("order.id", orderId);

Span 名称应遵循惯例并保持低基数:domain.verb (order.submit、payment.charge、voice.session、llm.generate_copy)。

错误路径

在当前活动的 Span 上记录异常并将 Span 状态设为错误,然后重新抛出异常,让调用方仍能感知失败。

if err != nil {
    span.RecordError(err)
    span.SetStatus(codes.Error, err.Error())
    return err
}
rescue => e
  span = OpenTelemetry::Trace.current_span
  span.record_exception(e)
  span.status = OpenTelemetry::Trace::Status.error(e.message)
  raise
end

日志

如果声称日志会通过 OTLP 转发,请安装该语言的 OTel 日志桥接,这样现有日志调用就会自动携带 trace_id / span_id。 保留现有日志记录器(log/slog、Logback、Logger、Serilog、Logger.Logger 等)——只需在其下方添加 OTLP 处理器/处理管线。

不要用自定义日志记录器替换项目的结构化日志记录器。

初始化行为

在遥测初始化区域使用 otel-onboarding-style 中的源码级公开 Superlog 配置模式。公开的项目令牌是只写的,应与端点放在同一个配置块中,例如 PostHog 项目令牌或 Sentry DSN。

如果初始化可能运行多次(测试重新加载、框架重启、多个入口点),请为 Provider/导出器设置添加保护,避免重复安装处理器。

资源属性

为每个服务设置在 OTel 资源上:

  • service.name
  • service.version(如果可用)
  • deployment.environment.name
  • vcs.repository.url.full — 仓库的规范 HTTPS URL
  • vcs.ref.head.revision — 尽可能从构建环境获取的提交 SHA (GITHUB_SHA、VERCEL_GIT_COMMIT_SHA、RAILWAY_GIT_COMMIT_SHA、 SOURCE_COMMIT、GIT_COMMIT、HEROKU_SLUG_COMMIT 等)

不要在运行中的进程里通过 shell 调用 git。请严格使用 OTel 语义约定中的键,不要自行定义 git.repo / app.repo_url。

指标

用于累加总量的计数器:请求、事件、作业、错误、业务状态转换。用于表示分布的直方图:持续时间、延迟、负载大小、队列深度。

仅使用低基数属性——租户/组织/项目、操作/用例、提供方/模型、结果。不要在指标标签中放入原始用户 ID 或请求 ID。

对于 LLM 令牌/成本遥测,请遵循 otel-onboarding-style 中的 gen_ai.* / app.gen_ai.* 约定。不要添加应用端 llm.cost_usd 指标——Superlog 会集中计算成本。

当不存在 OTel SDK 时

有些运行时没有可用的 OpenTelemetry SDK——较旧的语言(Perl、 Bash/shell、Lua、Crystal、Nim、Zig)、小众运行时、受限的边缘 环境,或是其“SDK”已被弃用/仍处于预 Alpha 阶段,效果不如自己实现 的语言。在这种情况下,可直接发送 OTLP/HTTP JSON。 其线格式稳定、文档齐全且精简。

手动实现 OTLP 发送器的规则:

  • 使用 OTLP/HTTP+JSON,而非供应商格式。 POST 到 https://intake.superlog.sh/v1/traces、/v1/metrics、/v1/logs,并设置 Content-Type: application/json,在 x-api-key 请求头中传入公开项目令牌(x-api-key: sl_public_...)。摄取端只读取 x-api-key 或 Authorization: Bearer <token>(字面前缀 Bearer )—— 即使令牌有效,任何其他请求头名称都会导致每次请求都返回 401。请求体 结构遵循 OTLP proto 到 JSON 的 映射(resourceSpans / resourceMetrics / resourceLogs → scopeSpans → spans,其中 traceId/spanId 使用小写十六进制)。
  • 让垫片保持精简并符合 OTel 风格。 暴露未来移植 SDK 时可直接使用的名称: startSpan(name)、setAttributes、recordException、 endSpan、counter.add、histogram.record。不要发明 sendSuperlogEvent 或 recordCounter——这正是其他地方的风格 所禁止的。
  • 正确生成 ID。 16 字节的 trace ID 和 8 字节的 span ID,均使用小写十六进制;使用运行时的 CSPRNG。时间戳为自 Unix 纪元以来的纳秒数(相当于 time.UnixNano()——注意某些语言的默认单位是毫秒或微秒)。
  • 批量处理并刷新。 在内存中缓冲 spans/metrics/logs,每隔较短时间(几秒)以及进程退出时刷新。缓冲区溢出时丢弃数据,而不要阻塞关键路径。对于 CLI 或短生命周期脚本,在退出前执行一次最终同步刷新。
  • 资源属性仍然适用。 在资源上设置一次 service.name、 service.version、deployment.environment.name、 vcs.repository.url.full、vcs.ref.head.revision,并在每个导出封装中复用。
  • 使用与基于 SDK 的服务相同的公开配置。 将端点和公开项目令牌放在同一个配置块中,并在每个导出封装中设置资源属性。如果注册流程仍在进行中,请正常完成初始化,并注明在浏览器流程认领令牌之前,摄取端可能会拒绝生成的令牌。
  • Trace 上下文传播使用 W3C traceparent。 如果运行时是服务端,则从传入 HTTP 请求头中读取;在传出请求中发送 traceparent: 00-<trace-id>-<span-id>-01。

对于 shell 脚本和一次性工具,即使只用一条 curl POST 向 /v1/traces 发送手动构造的 JSON 请求体也可以——这仍然是 OTLP,而且可以与用户流水线中的其他部分组合使用。

如果该语言确实有 SDK,但 SDK 无法在这个特定运行时中加载(打包器、边缘环境、受限的 FFI),则同样适用垫片方案。 Supabase Edge 技能就是一个实际示例。

自动插桩

如果该语言有打包好的自动插桩方案,请以此为基础:

  • Java:OpenTelemetry Java agent(-javaagent:opentelemetry-javaagent.jar)
  • .NET:OpenTelemetry.Instrumentation.AspNetCore / Http / SqlClient 等
  • Ruby:opentelemetry-instrumentation-all
  • Node:@opentelemetry/auto-instrumentations-node
  • Go:特定框架的 otelhttp、otelgin、otelpgx、otelsql 包装器(Go 没有全局 agent)
  • PHP:open-telemetry/opentelemetry-auto-* 扩展
  • Elixir::opentelemetry_phoenix、:opentelemetry_ecto、:opentelemetry_cowboy

然后,围绕自动插桩无法观察到的业务操作添加自定义 spans、metrics 和 logs—— 当出现异常时,人类运维人员真正希望检查的那些操作。

评论

支持 Markdown