文档

通过OpenTelemetry上报Swift应用数据

更新时间:

通过OpenTelemetry为应用埋点并上报链路数据至可观测链路 OpenTelemetry 版后,可观测链路 OpenTelemetry 版即可开始监控应用,您可以查看应用拓扑、调用链路、异常事务、慢事务和SQL分析等一系列监控数据。本文介绍如何使用OpenTelemetry为Swift应用埋点并上报数据。

前提条件

获取接入点信息

  1. 登录可观测链路 OpenTelemetry 版控制台

  2. 在左侧导航栏单击集群配置,然后在右侧页面单击接入点信息页签。

  3. 在页面顶部选择需要接入的地域,然后在集群信息区域打开显示Token开关。

  4. 客户端采集工具区域单击OpenTelemetry

    在下方表格的相关信息列中,获取接入点信息。OT接入点信息

    说明

    如果应用部署于阿里云生产环境,则选择阿里云VPC网络接入点,否则选择公网接入点。

获取接入点信息

  1. 登录可观测链路 OpenTelemetry 版控制台

  2. 在左侧导航栏单击集群配置,然后在右侧页面单击接入点信息页签。

  3. 在页面顶部选择需要接入的地域,然后在集群信息区域打开显示Token开关。

  4. 客户端采集工具区域单击OpenTelemetry

    在下方表格的相关信息列中,获取接入点信息。OT接入点信息

    说明

    如果应用部署于阿里云生产环境,则选择阿里云VPC网络接入点,否则选择公网接入点。

获取接入点信息

  1. 登录可观测链路 OpenTelemetry 版控制台

  2. 在左侧导航栏单击集群配置,然后在右侧页面单击接入点信息页签。

  3. 在页面顶部选择需要接入的地域,然后在集群信息区域打开显示Token开关。

  4. 客户端采集工具区域单击OpenTelemetry

    在下方表格的相关信息列中,获取接入点信息。OT接入点信息

    说明

    如果应用部署于阿里云生产环境,则选择阿里云VPC网络接入点,否则选择公网接入点。

获取接入点信息

  1. 登录可观测链路 OpenTelemetry 版控制台

  2. 在左侧导航栏单击集群配置,然后在右侧页面单击接入点信息页签。

  3. 在页面顶部选择需要接入的地域,然后在集群信息区域打开显示Token开关。

  4. 客户端采集工具区域单击OpenTelemetry

    在下方表格的相关信息列中,获取接入点信息。OT接入点信息

    说明

    如果应用部署于阿里云生产环境,则选择阿里云VPC网络接入点,否则选择公网接入点。

获取接入点信息

  1. 登录可观测链路 OpenTelemetry 版控制台

  2. 在左侧导航栏单击集群配置,然后在右侧页面单击接入点信息页签。

  3. 在页面顶部选择需要接入的地域,然后在集群信息区域打开显示Token开关。

  4. 客户端采集工具区域单击OpenTelemetry

    在下方表格的相关信息列中,获取接入点信息。OT接入点信息

    说明

    如果应用部署于阿里云生产环境,则选择阿里云VPC网络接入点,否则选择公网接入点。

示例Demo

本文将通过具体示例介绍如何通过OpenTelemetry上报Swift语言编写的macOS命令行应用数据,该方法同样适用于iOS应用。

示例代码仓库地址:opentelemetry-swift-demo

步骤一:创建应用并添加依赖

  1. 选择要创建的应用,例如macOS的Command Line Tool。

    Command Line Tool

  2. 在XCode中选择File > Add Packages...,然后在搜索框中输入https://github.com/open-telemetry/opentelemetry-swift,选择1.4.1版本。

    说明

    更多版本信息,请参考opentelemetry-swift releases信息

    opentelemetry-swift

  3. 选中所需的Package Products。

    本文中使用到的Package Products如下:Package Products

步骤二:OpenTelemetry初始化

  1. 创建用于导出观测数据的组件。

    从以下3种方法中选择1种上报Trace数据。

    • 方法一:通过gRPC协议上报Trace数据

      • 请分别将<gRPC-endpoint><gRPC-port>替换为从前提条件中获取的接入点信息,例如:host: "http://tracing-analysis-dc-hz.aliyuncs.com", port:8090

      • 请将<your-token>替换为从前提条件中获取的鉴权Token。

      let grpcChannel = ClientConnection(
          configuration: ClientConnection.Configuration.default(
              target: .hostAndPort("<gRPC-endpoint>", 8090), // 接入点填写示例:tracing-analysis-dc-hz.aliyuncs.com,不需要添加"http://"
              eventLoopGroup: MultiThreadedEventLoopGroup(numberOfThreads: 1)
          )
      )
      
      let otlpGrpcConfiguration = OtlpConfiguration(
          timeout: OtlpConfiguration.DefaultTimeoutInterval,
          headers: [
              ("Authentication","xxxxxx")
          ]
      
      )
      let otlpGrpcTraceExporter = OtlpTraceExporter(channel: grpcChannel, config: otlpGrpcConfiguration)
    • 方法二:通过HTTP协议上报Trace数据

      请将<HTTP-endpoint>替换为从前提条件中获取的接入点信息,例如:http://tracing-analysis-dc-hz.aliyuncs.com/adapt_xxxx@xxxx_xxxx@xxxx/api/otlp/traces

      let url = URL(string: "<HTTP-endpoint>")
      let otlpHttpTraceExporter = OtlpHttpTraceExporter(endpoint: url!)
    • 方法三:在命令行输出Trace数据

      let consoleTraceExporter = StdoutExporter(isDebug: true)
  2. 获取用于创建Span的Tracer。

    • 请将<your-service-name>替换为要上报的应用名,<your-host-name>替换为主机名。

    • 替换<trace-exporter>,根据步骤1上报Trace方法不同替换为不同值。

      • 方式一:<trace-exporter>替换为otlpGrpcTraceExporter

      • 方式二:<trace-exporter>替换为otlpHttpTraceExporter

      • 方式三:<trace-exporter>替换为consoleTraceExporter

    // 设置应用名与主机名
    let resource = Resource(attributes: [
        ResourceAttributes.serviceName.rawValue: AttributeValue.string("<your-service-name>"),
        ResourceAttributes.hostName.rawValue: AttributeValue.string("<your-host-name>")
    ])
    
    // 配置TracerProvider
    OpenTelemetry.registerTracerProvider(tracerProvider: TracerProviderBuilder()
                                         .add(spanProcessor: BatchSpanProcessor(spanExporter: <trace-exporter>)) // 上报至可观测链路 OpenTelemetry 版
                                         .with(resource: resource)
                                         .build())
    
    // 获取tracer,用来创建Span
    let tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "instrumentation-library-name", instrumentationVersion: "1.0.0")

步骤三:创建Span追踪链路数据

  1. 创建Span,为Span添加属性(Attribute)和事件(Event),并输出当前Span的TraceId。

    let span = tracer.spanBuilder(spanName: "first span").startSpan()
    // 设置属性
    span.setAttribute(key: "http.method", value: "GET")
    span.setAttribute(key: "http.url", value: "www.aliyun.com")
    let attributes = [
        "key": AttributeValue.string("value"),
        "result": AttributeValue.int(100)
    ]
    
    // your code...
    
    // 设置Event
    span.addEvent(name: "computation complete", attributes: attributes)
    
    // 打印TraceId
    print(span.context.traceId.hexString)
    
    // your code...
    
    // 结束当前span
    span.end()
  2. 创建嵌套的Span。

    let parentSpan = tracer.spanBuilder(spanName: "parent span").startSpan()
    
    // your code...
    
    let childSpan = tracer.spanBuilder(spanName: "child span").setParent(parentSpan).startSpan()
    
    // your code...
    
    childSpan.end()
    
    // your code...
    
    parentSpan.end()
  3. 启动应用。

    登录ARMS控制台后,在应用监控 > 应用列表页面选择目标应用,查看链路数据。

    说明

    语言列显示image图标的应用为接入应用监控的应用,显示-图标的应用为接入可观测链路 OpenTelemetry 版的应用。

步骤四:打通客户端与服务端应用链路

  1. 修改Header中的Trace透传格式。

    • 不同协议使用不同的HTTP Header向下游传递Trace上下文,如OpenTelemtry默认使用W3C Trace Context格式(也支持修改为其他格式),而Zipkin使用B3或B3 Multi格式。关于透传格式的更多信息,请参见OpenTelemetry指定透传Header格式

    • 根据服务端使用的协议类型,在客户端中设置对应的透传格式(textPropagators和baggagePropagator),以实现iOS客户端应用与服务端应用链路打通:

      • 如果服务端使用OpenTelemetry默认的W3C Trace Context格式,客户端无需设置textPropagators和baggagePropagator。

      • 如果服务端使用Zipkin的B3/B3 Multi格式,客户端的textPropagators需设置为B3Propagator,baggagePropagator设置为ZipkinBaggagePropagator。

        // 设置B3透传格式。
        OpenTelemetry.registerPropagators(textPropagators: [B3Propagator()],
                                          baggagePropagator: ZipkinBaggagePropagator())
      • 如果服务端使用Jaeger协议,客户端的textPropagators需设置为JaegerPropagator,baggagePropagator设置为JaegerBaggagePropagator。

        // 设置Jaeger透传格式。
        OpenTelemetry.registerPropagators(textPropagators: [JaegerPropagator()],
                                          baggagePropagator: JaegerBaggagePropagator())
      • 也可以同时设置多种Trace透传格式。

        // 同时使用W3C Trace Context、B3、Jaeger三种Trace透传格式。
        OpenTelemetry.registerPropagators(textPropagators: [W3CTraceContextPropagator(), 
                                                            B3Propagator(), 
                                                            JaegerPropagator()],
                                          baggagePropagator: W3CBaggagePropagator())
  2. 导入URLSessionInstrumentation。

    URLSessionInstrumentation是OpenTelemetry提供的针对URLSession的自动埋点插件,可以自动拦截所有通过URLSession发出的网络请求并创建调用链。

    import URLSessionInstrumentation
    
    ...
    let networkInstrumentation = URLSessionInstrumentation(configuration: URLSessionInstrumentationConfiguration())
  3. 使用URLSession进行网络请求,访问服务端。

    let url = URL(string: "<服务端地址>")!
    let request = URLRequest(url: url)
    let semaphore = DispatchSemaphore(value: 0)
    
    let task = URLSession.shared.dataTask(with: request) { data, _, _ in
        if let data = data {
            let string = String(decoding: data, as: UTF8.self)
            print(string)
        }
        semaphore.signal()
    }
    task.resume()
    
    semaphore.wait()

    展开查看完整示例代码

    OpenTelemetryUtil.swift

    import Foundation
    
    import GRPC
    import NIO
    import OpenTelemetryApi
    import OpenTelemetrySdk
    import OpenTelemetryProtocolExporter
    import StdoutExporter
    
    class OpenTelemetryUtil {
        
        private static let tracerProvider: TracerProvider = {
            // 通过gRPC协议上报
            let grpcChannel = ClientConnection(
                configuration: ClientConnection.Configuration.default(
                    target: .hostAndPort("tracing-analysis-dc-hz.aliyuncs.com", 8090),
                    eventLoopGroup: MultiThreadedEventLoopGroup(numberOfThreads: 1)
                )
            )
            
    
            let otlpGrpcConfiguration = OtlpConfiguration(
                timeout: OtlpConfiguration.DefaultTimeoutInterval,
                headers: [
                    ("Authentication","${鉴权Token}")
                ]
    
            )
            let otlpGrpcTraceExporter = OtlpTraceExporter(channel: grpcChannel, config: otlpGrpcConfiguration)
            let consoleTraceExporter = StdoutExporter(isDebug: true)
            
            // 设置应用名与主机名
            let resource = Resource(attributes: [
                ResourceAttributes.serviceName.rawValue: AttributeValue.string("otel-swift-demo-grpc"),
                ResourceAttributes.hostName.rawValue: AttributeValue.string("adam.mac")
            ])
    
            let tracerProvider = TracerProviderBuilder()
                .add(spanProcessor: BatchSpanProcessor(spanExporter: otlpGrpcTraceExporter))
    //            .add(spanProcessor: BatchSpanProcessor(spanExporter: consoleTraceExporter)) // 控制台打印 Trace,调试时使用
                .with(resource: resource)
                .build()
            
            
            // 配置TracerProvider
            OpenTelemetry.registerTracerProvider(tracerProvider: tracerProvider)
            // 修改透传格式
            OpenTelemetry.registerPropagators(textPropagators: [W3CTraceContextPropagator(),
                                                                B3Propagator(),
                                                                JaegerPropagator()],
                                              baggagePropagator: W3CBaggagePropagator())
            
            return tracerProvider
            
        }()
        
        
        // 获取tracer,用来创建Span
        static func getTracer(name: String, version: String) -> Tracer {
            return tracerProvider.get(instrumentationName: name, instrumentationVersion: version)
        }
    
    }
    

    main.swift

    import Foundation
    
    
    import OpenTelemetryApi
    import OpenTelemetrySdk
    // 对网络请求进行自动埋点
    import URLSessionInstrumentation
    
    let tracer = OpenTelemetryUtil.getTracer(name: "ios-demo", version: "1.0.0")
    
    // 创建嵌套的Span
    let parentSpan = tracer.spanBuilder(spanName: "parent span").startSpan()
    
    let childSpan = tracer.spanBuilder(spanName: "child span").setParent(parentSpan).startSpan()
    
    // 设置属性
    childSpan.setAttribute(key: "http.method", value: "GET")
    childSpan.setAttribute(key: "http.url", value: "www.aliyun.com")
    let attributes = [
        "stringKey": AttributeValue.string("value"),
        "intKey": AttributeValue.int(100)
    ]
    // 设置Event
    childSpan.addEvent(name: "event", attributes: attributes)
    // 打印TraceId
    print(childSpan.context.traceId.hexString)
    
    // 发送网络请求访问服务端
    let networkInstrumentation = URLSessionInstrumentation(configuration: URLSessionInstrumentationConfiguration())
    
    let url = URL(string: "${服务端地址}")!
    let request = URLRequest(url: url)
    let semaphore = DispatchSemaphore(value: 0)
    
    let task = URLSession.shared.dataTask(with: request) { data, _, _ in
        if let data = data {
            let string = String(decoding: data, as: UTF8.self)
            print(string)
        }
        semaphore.signal()
    }
    task.resume()
    
    semaphore.wait()
    
    
    // 手动结束手动创建的 Span
    childSpan.end()
    parentSpan.end()
    
    sleep(60)
    
    print("end")
    
  4. 启动应用,在调用链分析页面查看客户端与服务端打通的调用链。

    如下图所示,HTTP GET为iOS应用,zipkin-demo-server为服务端应用。

    image

  • 本页导读 (1)
文档反馈