手动仪表化

OpenTelemetry Swift 的手动仪表化

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.

设置

OpenTelemetry Swift 在其默认配置中提供了有限的功能。要使用更有用的功能,需要进行一些配置。

默认注册的 TracerProviderMetricProvider 没有经过配置以使用导出器。根据您的需求,有多种 导出器 可供选择。下面我们将探讨配置 OTLP 导出器,该导出器用于将数据发送给 收集器

import GRPC
import OpenTelemetryApi
import OpenTelemetrySdk
import OpenTelemetryProtocolExporter


// 初始化 OtlpTraceExporter
let otlpConfiguration = OtlpConfiguration(timeout: OtlpConfiguration.DefaultTimeoutInterval)

let grpcChannel = ClientConnection.usingPlatformAppropriateTLS(for: MultiThreadedEventLoopGroup(numberOfThreads:1))
                                                  .connect(host: <collector host>, port: <collector port>)

let traceExporter = OtlpTraceExporter(channel: grpcChannel,
                                      config: otlpConfiguration)

// 使用构建的 otlp trace 导出器构建并注册 TracerProvider
OpenTelemetry.registerTracerProvider(tracerProvider: TracerProviderBuilder()
                                                      .add(spanProcessor:SimpleSpanProcessor(spanExporter: traceExporter))
                                                      .with(resource: Resource())
                                                      .build())

OtlpMetricExporter 使用类似的模式:

// otlpConfiguration 和 grpcChannel 可以重复使用
OpenTelemetry.registerMeterProvider(meterProvider: MeterProviderBuilder()
            .with(processor: MetricProcessorSdk())
            .with(exporter: OtlpMetricExporter(channel: channel, config: otlpConfiguration))
            .with(resource: Resource())
            .build())

配置了 MeterProvider 和 TracerProvider 之后,所有后续初始化的仪表化都将使用该 OTLP 导出器进行导出。

追踪

获取追踪器

要进行追踪,您需要一个追踪器。追踪器是通过追踪器提供者获取的,它负责创建 span。在上面定义和注册的追踪器提供者中,OpenTelemetry 管理着追踪器提供者。要创建追踪器,需要一个仪表化名称和一个可选的版本:

let  tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "instrumentation-library-name", instrumentationVersion: "1.0.0")

创建 Span

Span 代表一个工作单元或操作。Span 是构成 Trace 的基本单元。要创建 Span,请使用与追踪器相关联的 span builder:

let span =  let builder = tracer.spanBuilder(spanName: "\(name)").startSpan()
...
span.end()

必须调用 end() 来结束 Span。

创建嵌套 Span

Span 用于建立操作之间的关系。以下是一个手动建立 Span 之间关系的示例。

我们在 parent() 中调用了 child(),并展示了如何手动链接每个方法的 Span。

func parent() {
  let parentSpan = someTracer.spanBuilder(spanName: "parent span").startSpan()
  child(span: parentSpan)
  parentSpan.end()
}

func child(parentSpan: Span) {
let childSpan = someTracer.spanBuilder(spanName: "child span")
                             .setParent(parentSpan)
                             .startSpan()
  // 进行工作
  childSpan.end()
}

如果使用了 activeSpan,父子关系将会自动链接:

func parent() {
  let parentSpan = someTracer.spanBuilder(spanName: "parent span")
                      .setActive(true) // 自动设置上下文
                      .startSpan()
  child()
  parentSpan.end()
}

func child() {
  let childSpan = someTracer.spanBuilder(spanName: "child span")
                             .startSpan() // 自动捕获 `active span` 作为父 Span
  // 进行工作
  childSpan.end()
}

获取当前 Span

有时在代码的任意位置处理当前/活动 Span 是很有用的。以下是如何从代码中的任意点访问当前 Span。

let currentSpan = OpenTelemetry.instance.contextProvider.activeSpan

Span 属性

还可以使用附加属性对 Span 进行注释。所有 Span 都将自动使用附加到追踪器提供者的 Resource 属性进行注释。Opentelemetry-swift SDK 已经提供了对 SDKResourceExtension 仪表化中常见属性的仪表化。在这个示例中,使用现有的 语义约定,为网络请求创建一个 Span,并捕获有关该请求的详细信息。

let span = tracer.spanBuilder("/resource/path").startSpan()
span.setAttribute("http.method", "GET");
span.setAttribute("http.url", url.toString());

创建 Span 事件

Span 事件可以被认为是 Span 上的结构化日志消息(或注释),通常用于指示 Span 在持续时间内的某个特定时间点上的有意义且独立的事件。

let attributes = [
    "key" : AttributeValue.string("value"),
    "result" : AttributeValue.int(100)
]
span.addEvent(name: "computation complete", attributes: attributes)

设置 Span 状态

可以在 Span 上设置一个状态,通常用于指定 Span 尚未成功完成 - SpanStatus.Error。在极少数情况下,可以将 Error 状态覆盖为 OK,但不要将 OK 设置为成功完成的 Span。

可以在 Span 结束之前的任何时候设置状态:

func myFunction() {
  let span = someTracer.spanBuilder(spanName: "my span").startSpan()
  defer {
    span.end()
  }
  guard let criticalData = get() else {
      span.status = .error(description: "something bad happened")
      return
  }
  // 做一些事情
}

在 Spans 中记录异常

语义约定为记录异常事件提供了特殊的分界线:

let span = someTracer.spanBuilder(spanName: "my span").startSpan()
do {
  try throwingFunction()
} catch {
  span.addEvent(name: SemanticAttributes.exception.rawValue,
    attributes: [SemanticAttributes.exceptionType.rawValue: AttributeValue.string(String(describing: type(of: error))),
                 SemanticAttributes.exceptionEscaped.rawValue: AttributeValue.bool(false),
                 SemanticAttributes.exceptionMessage.rawValue: AttributeValue.string(error.localizedDescription)])
  })
  span.status = .error(description: error.localizedDescription)
}
span.end()

指标

度量 API 和 SDK 的文档尚未完成,您可以通过 编辑此页面 帮助使其可用。

日志

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

SDK 配置

处理器

OpenTelemetry-swift 提供了不同的 Span 处理器。SimpleSpanProcessor 立即将结束的 Span 转发给导出器,而 BatchSpanProcessor 则将它们进行批处理并批量发送。使用 MultiSpanProcessor 可以配置多个同时处于活动状态的 Span 处理器。例如,您可以创建一个将 Span 导出到日志记录器的 SimpleSpanProcessor,以及一个将 Span 导出到 OpenTelemetry 收集器的 BatchSpanProcessor

let otlpConfiguration = OtlpConfiguration(timeout: OtlpConfiguration.DefaultTimeoutInterval)

let grpcChannel = ClientConnection.usingPlatformAppropriateTLS(for: MultiThreadedEventLoopGroup(numberOfThreads:1))
                                                  .connect(host: <collector host>, port: <collector port>)

let traceExporter = OtlpTraceExporter(channel: grpcChannel
                                      config: otlpConfiguration)

// 使用构建的 otlp trace 导出器构建并注册 TracerProvider
OpenTelemetry.registerTracerProvider(tracerProvider: TracerProviderBuilder()
                                                      .add(spanProcessor:BatchSpanProcessor(spanExporter: traceExporter))
                                                      .add(spanProcessor:SimpleSpanProcessor(spanExporter: StdoutExporter))
                                                      .with(resource: Resource())
                                                      .build())

批处理 Span 处理器允许进行各种参数的自定义,包括。

导出器

OpenTelemetry-Swift 提供了以下导出器:

  • InMemoryExporter:将 Span 数据保存在内存中。这对于测试和调试非常有用。
  • DatadogExporter:将 OpenTelemetry Span 数据转换为 Datadog traces,将 Span 事件转换为 Datadog 日志。
  • JaegerExporter:将 OpenTelemetry Span 数据转换为 Jaeger 格式并导出到 Jaeger 端点。
  • 持久化导出器:这是一个装饰器导出器,为现有的度量和追踪导出器提供数据持久化。
  • PrometheusExporter:将度量数据转换为 Prometheus 格式并导出到 Prometheus 端点。
  • StdoutExporter:将 Span 数据导出到标准输出。用于调试很有用。
  • ZipkinTraceExporter:将 Span 数据转换为 Zipkin 格式并导出到 Zipkin 端点。
最后修改 December 13, 2023: improve glossary translation (46f8201b)