手动仪表化

OpenTelemetry Ruby 的手动仪表化

Manual instrumentation is the act of adding observability code to an app yourself.

If you’re instrumenting an app, you need to use the OpenTelemetry SDK for your language. You’ll then use the SDK to initialize OpenTelemetry and the API to instrument your code. This will emit telemetry from your app, and any library you installed that also comes with instrumentation.

If you’re instrumenting a library, only install the OpenTelemetry API package for your language. Your library will not emit telemetry on its own. It will only emit telemetry when it is part of an app that uses the OpenTelemetry SDK. For more on instrumenting libraries, see Libraries.

For more information about the OpenTelemetry API and SDK, see the specification.

设置

首先,确保已安装 SDK 包:

gem install opentelemetry-sdk

然后,在程序初始化时包含配置代码。确保通过配置服务名称来设置 service.name

追踪

获取跟踪器

要开始进行追踪,您需要确保已初始化来自TracerProviderTracer

最简单和最常见的方法是使用全局注册的 TracerProvider。如果您使用一些自动仪表化库,比如在 Rails 应用中,那么一个 TracerProvider 将为您注册。

# 如果在 Rails 应用中,这些代码位于 config/initializers/opentelemetry.rb
require "opentelemetry/sdk"

OpenTelemetry::SDK.configure do |c|
  c.service_name = '<YOUR_SERVICE_NAME>'
end

# 'Tracer' 可以在代码的任何地方使用了
MyAppTracer = OpenTelemetry.tracer_provider.tracer('<YOUR_TRACER_NAME>')

获取了 Tracer 后,您可以手动跟踪代码。

获取当前 Span

在您的程序中,通常会在某个位置向当前span添加信息。为此,您可以获取当前 span,并向其添加属性

require "opentelemetry/sdk"

def track_extended_warranty(extended_warranty)
  # 获取当前 span
  current_span = OpenTelemetry::Trace.current_span

  # 并向其中添加有用的内容!
  current_span.add_attributes({
    "com.extended_warranty.id" => extended_warranty.id,
    "com.extended_warranty.timestamp" => extended_warranty.timestamp
  })
end

创建新的 Span

要创建一个span,您需要一个配置好的 Tracer

通常,在创建新 span 时,您希望它成为活动/当前 span。为此,请使用 in_span

require "opentelemetry/sdk"

def do_work
  MyAppTracer.in_span("do_work") do |span|
    # 执行需要跟踪的一些工作!
  end
end

创建嵌套的 Spans

如果您有一个作为另一个操作的一部分进行跟踪的明确子操作,您可以创建嵌套的spans来表示关系:

require "opentelemetry/sdk"

def parent_work
  MyAppTracer.in_span("parent") do |span|
    # 执行需要跟踪的一些工作!

    child_work

    # 之后继续执行一些工作
  end
end

def child_work
  MyAppTracer.in_span("child") do |span|
    # 执行需要跟踪的一些工作!
  end
end

在上述示例中,创建了两个 span,分别命名为 parentchild,其中 child 嵌套在 parent 之下。如果在跟踪可视化工具中查看具有这些 span 的追踪,则 child 将嵌套在 parent 之下。

向 Span 添加属性

属性允许您将键/值对附加到span,以便更多地了解它所跟踪的当前操作的信息。

您可以使用 set_attribute 向 span 添加单个属性:

require "opentelemetry/sdk"

current_span = OpenTelemetry::Trace.current_span

current_span.set_attribute("animals", ["elephant", "tiger"])

您可以使用 add_attributes 添加属性映射:

require "opentelemetry/sdk"

current_span = OpenTelemetry::Trace.current_span

current_span.add_attributes({
  "my.cool.attribute" => "a value",
  "my.first.name" => "Oscar"
})

您还可以在创建 Span 时向其添加属性:

require "opentelemetry/sdk"

MyAppTracer.in_span('foo', attributes: { "hello" => "world", "some.number" => 1024 }) do |span|
  # 使用 span 做一些事情
end

⚠ Span 是线程安全的数据结构,在修改它们时需要进行锁定。因此,应尽量避免多次调用 set_attribute,而是使用哈希表在创建 span 或在现有 span 上使用 add_attributes 一次性分配属性。

⚠ 采样决策是在创建 span 的时刻进行的。如果您的采样器在决定是否对一个 span 进行采样时考虑 span 属性,则在创建 span 时必须将这些属性传递。因为采样决策已经定下来,之后添加的属性不会被采样器看到。

添加语义属性

语义属性是预定义的属性,是常见数据类型的众所周知的命名约定。使用语义属性可以在您的系统中规范化此类信息。

要在 Ruby 中使用语义属性,请添加相应的 gem:

gem install opentelemetry-semantic_conventions

然后可以在代码中使用它:

require 'opentelemetry/sdk'
require 'opentelemetry/semantic_conventions'

current_span = OpenTelemetry::Trace.current_span

current_span.add_attributes({
  OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => "GET",
  OpenTelemetry::SemanticConventions::Trace::HTTP_URL => "https://opentelemetry.io/",
})

添加 Span 事件

Span 事件是 span 上的可读性高的消息,表示其生命周期中的“某些事件”。例如,想象一个需要在互斥锁下独占访问资源的函数。可以在两个点创建一个事件——一次是我们尝试获取资源的时候,另一次是我们获取互斥锁的时候。

require "opentelemetry/sdk"

span = OpenTelemetry::Trace.current_span

span.add_event("Acquiring lock")
if mutex.try_lock
  span.add_event("Got lock, doing work...")
  # 这里的一些代码
  span.add_event("Releasing lock")
else
  span.add_event("Lock already in use")
end

事件的一个有用特征是它们的时间戳显示为相对于 span 开始的偏移量,这样您可以轻松查看它们之间经过的时间。

事件也可以具有自己的属性,例如:

require "opentelemetry/sdk"

span.add_event("Cancelled wait due to external signal", attributes: {
  "pid" => 4328,
  "signal" => "SIGHUP"
})

添加 Span 链接

一个span可以带有零个或多个span 链接,将其与另一个 span 有因果性地联系起来。链接需要span 上下文来创建。

require "opentelemetry/sdk"

span_to_link_from = OpenTelemetry::Trace.current_span

link = OpenTelemetry::Trace::Link.new(span_to_link_from.context)

MyAppTracer.in_span("new-span", links: [link])
  # 做一些 'new_span' 需要跟踪的事情

  # 'new_span' 中的链接与被链接的 span 有关联,但不一定是子 span。
end

Span 链接通常用于链接在某种方式上相关的不同追踪,例如调用异步子任务的长时间运行任务。

链接也可以使用附加属性创建:

link = OpenTelemetry::Trace::Link.new(span_to_link_from.context, attributes: { "some.attribute" => 12 })

设置 Span 状态

状态可以在span上设置,通常用于指定 span 未成功完成 - StatusCode.ERROR。在罕见的情况下,您可以使用 StatusCode.OK 覆盖错误状态,但不要在成功完成的 span 上设置 StatusCode.OK

可以在 span 完成之前的任何时间设置状态:

require "opentelemetry/sdk"

current_span = OpenTelemetry::Trace.current_span

begin
  1/0 # 很明显会失败的代码
rescue
  current_span.status = OpenTelemetry::Trace::Status.error("在此处输入错误消息!")
end

在 span 中记录异常

在发生异常时记录异常通常是一个好主意。建议与设置 Span 状态结合使用。

require "opentelemetry/sdk"

current_span = OpenTelemetry::Trace.current_span

begin
  1/0 # 很明显会失败的代码
rescue Exception => e
  current_span.status = OpenTelemetry::Trace::Status.error("在此处输入错误消息!")
  current_span.record_exception(e)
end

记录异常会在当前 span 上创建一个Span 事件,并将堆栈跟踪记录为 span 事件的属性。

异常还可以记录具有附加属性的异常:

current_span.record_exception(ex, attributes: { "some.attribute" => 12 })

上下文传播

分布式跟踪追踪单个请求(称为 Trace)在构成应用程序的服务处理该请求时的进展。分布式追踪跨进程、网络和安全边界。词汇表

这需要_上下文传播_,即将跟踪的标识符发送到远程进程的机制。

ℹ 只要您的服务使用自动仪表化的库,OpenTelemetry Ruby SDK 将负责上下文传播。有关更多详细信息,请参阅 自动仪表化

为了在网络上传播跟踪上下文,必须向 OpenTelemetry SDK 注册传播器。W3 TraceContext 和 Baggage 传播器默认配置。操作员可以通过将 OTEL_PROPAGATORS 环境变量设置为以逗号分隔的propagators列表来覆盖此值。例如,要添加 B3 传播,请将 OTEL_PROPAGATORS 设置为您希望支持的传播格式的完整列表:

export OTEL_PROPAGATORS=tracecontext,baggage,b3

tracecontextbaggage 之外的传播器必须作为 gem 依赖项添加到您的 Gemfile 中,例如:

gem 'opentelemetry-propagator-b3'

指标

指标 API 和 SDK 目前正在开发中。

日志

日志 API 和 SDK 目前正在开发中。

下一步

您还需要配置适当的导出器将您的遥测数据导出到一个或多个遥测后端。 请参阅导出您的遥测数据

最后修改 December 13, 2023: improve glossary translation (46f8201b)