赛尔校园公共服务平台 Logo
平台使用
阿里云
百度云
移动云
智算服务
教育生态
登录 →
赛尔校园公共服务平台 Logo
平台使用 阿里云 百度云 移动云 智算服务 教育生态
登录
  1. 首页
  2. 阿里云
  3. 日志服务
  4. 操作指南
  5. 日志应用
  6. 全栈可观测
  7. Trace
  8. 接入Trace数据
  9. 新接入方案
  10. 通过OpenTelemetry接入iOS Trace数据

通过OpenTelemetry接入iOS Trace数据

  • 新接入方案
  • 发布于 2025-04-22
  • 0 次阅读
文档编辑
文档编辑

本文介绍通过OpenTelemetry将iOS应用的Trace数据接入到日志服务的操作步骤。

前提条件

已创建Trace实例。更多信息,请参见创建实例。

步骤一:集成SDK

Swift项目

  1. 导入opentelemetry-swift。

    1. 在Xcode中,选择File>Add Package。

    2. 在添加Package文本框中,输入如下链接。

      https://github.com/open-telemetry/opentelemetry-swift
    3. 选择Dependency Rule为Exact Version,设置版本号为1.4.0。

      更多信息,请参见OpenTelemetry iOS SDK Release。image

  2. 选择Swift Products。

    建议选择以下Products。

    • OpenTelemetryApi

    • OpenTelemetryProtocolExporter

    • OpenTelemetrySdk

    • URLSessionInstrumentation

    • StdoutExporter

    • ResourceExtension

    关于Swift Products的更多信息,请参见附录:OpenTelemetry Products说明。image

Objc项目

opentelemetry-swift对Objc语言的兼容较差,日志服务基于opentelemetry-swift实现了一个Objc扩展。Objc项目除了需要完成Swift项目的配置外,还需要增加opentelemetry-objc-extension。

  1. 完成Swift项目的配置。

  2. 导入opentelemetry-objc-extension。

    1. 在Xcode中,选择File>Add Package。

    2. 在添加Package文本框中,输入如下链接。

      https://github.com/aliyun-sls/opentelemetry-objc-extension
    3. 选择Dependency Rule为Exact Version,输入版本号为1.0.0。

      更多信息,请参见OpenTelemetry iOS Objc Extension SDK Release。image

  3. 选择Objc Extension Products。

    建议选择以下Products。

    • OpenTelemetryApiObjc

    • OpenTelemetryProtocolExporterObjc

    • OpenTelemetrySdkObjc

    • ResourceExtensionObjc

    • URLSessionInstrumentationObjc

    • StdoutExporterObjc

关于Objc Extension Products的更多信息,请参见附录:OpenTelemetry Products说明。

步骤二:初始化SDK

一般建议在AppDelegate类的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中进行SDK初始化。

Swift项目

// 导入如下模块。
import GRPC
import NIO
import OpenTelemetryApi
import OpenTelemetrySdk
import OpenTelemetryProtocolExporter
import StdoutExporter
import URLSessionInstrumentation

// 初始化Exporter。Exporter用于导出Trace数据到日志服务Logstore。
let client = ClientConnection.usingPlatformAppropriateTLS(for: MultiThreadedEventLoopGroup(numberOfThreads: 1))
.connect(host: "${endpoint}", port: ${port})	
let otlpTraceExporter = OtlpTraceExporter(
 channel: client,
 config: OtlpConfiguration(
 timeout: OtlpConfiguration.DefaultTimeoutInterval,
 headers:
 [
 ("x-sls-otel-project", "${project}"),
 ("x-sls-otel-instance-id", "${instanceId}"),
 ("x-sls-otel-ak-id", "${access-key-id}"),
 ("x-sls-otel-ak-secret", "${access-key-secret}")
 ]
 )
)

// 初始化tracer provider。tracer provider用于暴露主要的API,对Span进行预处理、自定义Clock,
// 自定义TraceId、SpanId生成规则,自定义采样器等。您可以根据实际的需要进行配置。
let spanExporters = MultiSpanExporter(spanExporters: [StdoutExporter(isDebug: true), otlpTraceExporter])
let spanProcessor = SimpleSpanProcessor(spanExporter: spanExporters)
OpenTelemetry.registerTracerProvider(
 tracerProvider: TracerProviderBuilder()
 .add(spanProcessor: spanProcessor)
 .with(resource: 
 Resource(attributes:
 [
 ResourceAttributes.serviceName.rawValue: AttributeValue.string("${service}"),
 ResourceAttributes.serviceNamespace.rawValue: AttributeValue.string("${service.namespace}"),
 ResourceAttributes.serviceVersion.rawValue: AttributeValue.string("${version}"),
 ResourceAttributes.hostName.rawValue: AttributeValue.string("${host}"),
 ResourceAttributes.deploymentEnvironment.rawValue: AttributeValue.string("${environment}"),
 ]
 )
 )
 .build()
)

// 配置其他的Instrumentation采集器。请根据实际业务需要进行配置。如下配置是开启采集NSUrlSession网络库的请求信息。
URLSessionInstrumentation(configuration: URLSessionInstrumentationConfiguration(
 shouldInstrument: { request in
 return true
 })
)
let tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "OTel Application", instrumentationVersion: "1.0.0")

Objc 项目

// 导入以下模块
@import OpenTelemetryApiObjc;
@import OpenTelemetrySdkObjc;
@import OpenTelemetryProtocolExporterObjc;
@import URLSessionInstrumentationObjc;
@import StdoutExporterObjc;

// 初始化Exporter。Exporter用于导出Trace数据到日志服务Logstore。
NSDictionary *headers = @{
 @"x-sls-otel-project": @"${project}",
 @"x-sls-otel-instance-id": @"${instanceId}",
 @"x-sls-otel-ak-id": @"${access-key-id}",
 @"x-sls-otel-ak-secret": @"${access-key-secret}"
};
OtlpConfigurationObjc *configuration = [OtlpConfigurationObjc configuration:OtlpConfigurationObjc.DefaultTimeoutInterval headers:headers];
OtlpTraceExporterObjc *exporter = [OtlpTraceExporterObjc exporter:@"https://${endpoint}"
 port:@"${port}"
 configuration:configuration
];

// 初始化tracer provider。tracer provider用于暴露主要的API,对Span进行预处理,自定义Clock。
// 自定义TraceId、SpanId生成规则,自定义采样器等。您可以根据实际的需要进行配置。
NSArray *exporters = @[
 [StdoutExporterObjc stdoutExporter:true], // 开发调试时,建议开启,实现在console中打印出Span的具体的内容。
 exporter
];
SpanProcessorObjc *spanProcessor = [BatchSpanProcessorObjc processor: [MultiSpanExporterObjc multiSpanExporter:exporters]];

TracerProviderBuilderObjc *providerBuilder = [TracerProviderBuilderObjc builder];
NSDictionary *resources = @{
 ResourceAttributesObjc.serviceName: [AttributeValueObjc string:@"${service}"], // 当前要追踪Trace的服务名称,建议取模块的名称,例如首页、会员中心。
 ResourceAttributesObjc.serviceNamespace: [AttributeValueObjc string:@"${service.namespace}"], // 建议固定为iOS/iPadOS/macOS/tvOS/watchOS。
 ResourceAttributesObjc.serviceVersion: [AttributeValueObjc string:@"${version}"], // 建议和App版本号保持一致。
 ResourceAttributesObjc.hostName: [AttributeValueObjc string:@"${host}"], // 建议固定为iOS。
 ResourceAttributesObjc.deploymentEnvironment: [AttributeValueObjc string:@"${environment}"] // 开发环境,一般开发阶段建议设置为dev,线上环境设置为prod。
};
providerBuilder = [providerBuilder withResource: [ResourceObjc resource:resources]];
providerBuilder = [providerBuilder addSpanProcessor: spanProcessor];

// 初始化OpenTelemetrySdk。
[OpenTelemetryObjc registerTracerProvider:[providerBuilder build]];

// 配置其他的Instrumentation采集器。请根据实际业务需要进行配置。如下配置是开启采集NSUrlSession网络库的请求信息。
[URLSessionInstrumentationObjc urlSessionInstrumentation:
 [URLSessionInstrumentationConfigurationObjc urlSessionInstrumentationConfiguration:[TestURLSessionInstrumentation instrumentation]]
];

变量说明如下表所示:

变量

说明

示例

${endpoint}

服务入口(Endpoint)表示日志服务对外服务的访问域名。服务入口与Project所在的地域相关。更多信息,请参见服务入口。

  • Port:网络端口,固定为10010。

cn-hangzhou.log.aliyuncs.com:10010

${project}

Project名称:项目(Project)是日志服务的资源管理单元,是进行多用户隔离与访问控制的主要边界。更多信息,请参见管理Project。

test-project

${instance}

Trace服务实例ID。更多信息,请参见创建Trace实例。

test-traces

${access-key-id}

AccessKey ID用于标识用户,更多信息,请参见访问密钥。

建议您遵循最小化原则,按需授予RAM用户必要的权限。关于授权的具体操作,请参见创建RAM用户及授权、RAM自定义授权示例。

无

${access-key-secret}

AccessKey Secret是用户用于加密签名字符串和日志服务用来验证签名字符串的密钥,必须保密。

无

${service.namespace}

服务归属的命名空间。

order

${service}

服务名,根据您的实际场景配置。

payment

${version}

服务版本号,建议使用va.b.c格式。

v1.0.0

${host}

主机名

localhost

${environment}

部署环境,例如测试环境、生产环境。

pre

步骤三:使用SDK

创建Tracer

建议根据不同的业务场景创建Tracer。创建Tracer时,需要传入instrumentation scope name,利于按照scope区分不同的Trace数据。

Swift示例

let tracer: Tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "OTel Application", instrumentationVersion: "1.0.0")

ObjC示例

TracerObjc *tracer = [OpenTelemetryObjc.instance.tracerProvider getWithInstrumentationName:@"app" instrumentationVersion:@"1.0"];

创建基本Span

Span代表了事务中的操作,每个Span都封装了操作名称、起止时间戳、属性信息、事件信息和Context信息等。

Swift示例

let spanBuilder = tracer.spanBuilder(spanName: "operation name")
let span = spanBuilder .setSpanKind(spanKind: .client).startSpan()
// do stuff
// ...
span.end()

ObjC示例

SpanBuilderObjc *spanBuilder = [_tracer spanBuilder:@"operation name"];
SpanObjc *span = [[spanBuilder setSpanKind:SpanKindObjc.CLIENT] startSpan];
// do stuff
// ...
[span end];

创建嵌套Span

当您希望为嵌套操作关联Span时,OpenTelemetry支持在进程内和跨远程进程进行跟踪。例如针对methodA调用方法methodB ,您可以通过以下方式创建嵌套Span。

Swift示例

func methodA() {
 let span = tracer.spanBuilder(spanName: "operation methodA").setSpanKind(spanKind: .client).startSpan()
	method(span)
 span.end()
}

func methodB(_ parent: Span) {
 let spanBuilder = tracer.spanBuilder(spanName: "operation methodB")
 spanBuilder.setParent(parent)
 let child = spanBuilder .setSpanKind(spanKind: .client).startSpan()
 // do stuff
 // ...
 child.end()
}

ObjC示例

- (void) methodA {
 SpanObjc *span = [[[_tracer spanBuilder:@"operation methodA"] setSpanKind:SpanKindObjc.CLIENT] startSpan];
 [self methodB: span];
 [span end];
}

- (void) methodB: (SpanObjc *)parent {
 SpanBuilderObjc *spanBuilder = [_tracer spanBuilder:@"operation name"];
 [spanBuilder setParent: parent];
 SpanObjc *span = [[spanBuilder setSpanKind:SpanKindObjc.CLIENT] startSpan];
 // do stuff
 // ...
 [span end];
}

OpenTemetry API还提供了一种自动化的方式来传播parentSpan。

Swift示例

func methodA() {
 let span = tracer.spanBuilder(spanName: "operation methodA").setSpanKind(spanKind: .client).startSpan()
 OpenTelemetry.instance.contextProvider.setActiveSpan(span)
 
 methodB(span)
 
 span.end()
}

func methodB(_ parent: Span) {
 let child = tracer.spanBuilder(spanName: "operation methodB").setSpanKind(spanKind: .client).startSpan()
 // do stuff
 // ...
 child.end()
}

ObjC示例

- (void) methodA {
 SpanObjc *span = [[[_tracer spanBuilder:@"operation methodA"] setSpanKind:SpanKindObjc.CLIENT] startSpan];
 [OpenTelemetryObjc.instance.contextProvider setActiveSpan:span];
 [self methodB];
 // do stuff
 // ...
 [span end];
}

- (void) methodB {
 SpanBuilderObjc *spanBuilder = [_tracer spanBuilder:@"operation name"];
 SpanObjc *span = [[spanBuilder setSpanKind:SpanKindObjc.CLIENT] startSpan];
 // do stuff
 // ...
 [span end];
}

创建带属性的Span

您可以通过属性在Span上提供特定操作的上下文信息。例如执行结果、关联的其他业务信息等,示例如下所示。

Swift示例

let spanBuilder = tracer.spanBuilder(spanName: "GET /resource/catalog")
let span = spanBuilder .setSpanKind(spanKind: .client).startSpan()
span.setAttribute(key: "http.method", value: "GET")
span.setAttribute(key: "http.url", value: "http url")

ObjC示例

SpanBuilderObjc *spanBuilder = [_tracer spanBuilder:@"GET /resource/catalog"];
SpanObjc *span = [[spanBuilder setSpanKind:SpanKindObjc.CLIENT] startSpan];
[span setAttribute:@"http.method" stringValue:@"GET"];
[span setAttribute:@"http.url" stringValue:request.URL.baseURL];

创建带事件的Span

您可以通过携带多个事件的方式对Span进行注释。

Swift示例

span.addEvent(name: "start")
// do stuff
// ...
span.addEvent(name: "start")

// 也可以携带属性。
span.addEvent(name: "event with attributes",
 attributes: [ "key1": AttributeValue.string("value1"),
 "key2": AttributeValue.double(2.2)
 ]
)

ObjC示例

[chilsSpan addEvent:@"start"];
// do stuff
// ...
[chilsSpan addEvent:@"end"];

// 也可以携带属性。
[chilsSpan addEvent:@"event with attributes" attributes:@{
 @"key1": [AttributeValueObjc string:@"value1"],
 @"key2": [AttributeValueObjc double:1.1],
}];

创建带链接的Span

一个 Span可以链接一个或多个因果相关的其他Span。

Swift示例

spanBuilder.addLink(spanContext: parent.context)
let span = spanBuilder .setSpanKind(spanKind: .client).startSpan()

ObjC示例

SpanBuilderObjc *spanBuilder = [_tracer spanBuilder:@"Another"];
[spanBuilder addLink:parent.context];

SpanObjc *span = [[spanBuilder setSpanKind:SpanKindObjc.CLIENT] startSpan];

从远程进程中读取上下文信息的具体操作,请参见Context Propagation。

给Span添加状态

Span包含StatusCode.UNSET、StatusCode.OK、StatusCode.ERROR三个状态,分别表示默认状态、成功状态、操作包含错误。例如参考如下示例,为Span添加操作包含错误的状态。

Swift示例

let span = tracer.spanBuilder(spanName: "operation name").startSpan()
do {
 try expression
 // do stuff
 // ...
} catch {
 span.status = .error(description: "\(error)")
}

ObjC示例

SpanObjc *span = [[_tracer spanBuilder:@"operation name"] startSpan];
@try {
 // do stuff
 // ...
} @catch (NSException *exception) {
 [span setStatus:[StatusObjc error: exception.description]];
} @finally {
 [span end];
}

传播上下文信息

OpenTelemetry提供了一种基于文本的方法,传播上下文信息。以下是使用 NSURLSession发出HTTP请求的示例。

Swift示例

// 在SDK初始化时,需要完成URLSessionInstrumentation的初始化。
// 按需传入对应的参数。
URLSessionInstrumentation(
 configuration: URLSessionInstrumentationConfiguration(
 shouldInstrument: { request in
 // 是否采集该request的数据。
 return true
 }
 )
)

ObjC示例

// 在SDK初始化时,需要完成URLSessionInstrumentationObjc的初始化。
// 初始化URLSessionInstrumentationObjc时,需要传入一个实现了URLSessionInstrumentationConfigurationImpl协议的类(可参见下面的TestURLSessionInstrumentation实现)
[URLSessionInstrumentationObjc urlSessionInstrumentation:
 [URLSessionInstrumentationConfigurationObjc urlSessionInstrumentationConfiguration:[TestURLSessionInstrumentation instrumentation]]
];

// TestURLSessionInstrumentation的实现示例。
#pragma mark - URLSessionInstrumentation
@interface TestURLSessionInstrumentation: NSObject<URLSessionInstrumentationConfigurationImpl>
+ (instancetype) instrumentation;
@end

@implementation TestURLSessionInstrumentation
+ (instancetype) instrumentation {
 return [[TestURLSessionInstrumentation alloc] init];
}
- (void)createdRequest:(NSURLRequest * _Nonnull)request span:(SpanObjc * _Nonnull)span {
 // request被创建时回调。
 [span setAttribute:@"createdRequest" stringValue:@"request created"];
}
- (void)injectCustomHeaders:(NSURLRequest * _Nonnull)request span:(SpanObjc * _Nullable)span {
 // 注入自定义请求头。
 [(NSMutableURLRequest *)request addValue:@"custom header" forHTTPHeaderField:@"injectCustomHeaders"];
}
- (NSString * _Nullable)nameSpan:(NSURLRequest * _Nonnull)request {
 // 重命名Span。
 if ([request.URL.host containsString:@"dns.alidns.com"]) {
 return @"请求解析DNS";
 }
 return nil;
}
- (void)receivedError:(NSError * _Nonnull)error dataOrFile:(NSObject * _Nullable)dataOrFile span:(SpanObjc * _Nonnull)span {
 // 接口失败时回调。
}
- (void)receivedResponse:(NSURLResponse * _Nonnull)response dataOrFile:(NSObject * _Nullable)dataOrFile span:(SpanObjc * _Nonnull)span {
 // 接口成功时回调。
 NSLog(@"receivedResponse: %@", dataOrFile);
}
- (BOOL)shouldInjectTracingHeaders:(NSURLRequest * _Nonnull)request {
 // 注入tracing headers。
 return YES;
}
- (BOOL)shouldInstrument:(NSURLRequest * _Nonnull)request {
 // 是否采集该request的数据。
 return YES;
}
- (BOOL)shouldRecordPayload:(NSURLSession * _Nonnull)session {
 // 是否采集请求体信息。
 return YES;
}
- (void)spanCustomization:(NSURLRequest * _Nonnull)request spanBuilder:(SpanBuilderObjc * _Nonnull)spanBuilder {
 // 自定义Span信息。
 [spanBuilder setAttribute:@"spanCustomization" stringValue:@"customize span"];
}
@end

目前,OpenTelemetry SDK支持按照W3C Trace Context标准传播上下文信息。更多信息,请参见W3CTraceContextPropagator类。

关于OpenTelemetry SDK的更多信息,请参见官方文档。

附录:OpenTelemetry Products说明

Swift

Objc

用途

OpenTelemetryApi

OpenTelemetryApiObjc

OpenTelemetry API的约定和最小实现。

OpenTelemetrySdk

OpenTelemetrySdkObjc

OpenTelemetry API的最小实现。

OpenTelemetryProtocolExporter

OpenTelemetryProtocolExporterObjc

OpenTelemetry Protocol实现。

StdoutExporter

StdoutExporterObjc

标准输出Exporter,用于将Trace数据打印在console。

ResourceExtension

ResourceExtensionObjc

Resource的扩展采集实现。

URLSessionInstrumentation

URLSessionInstrumentationObjc

URLSession网络库的自动采集实现。

常见问题

  • 问题:使用Swift SDK后,无数据上报到日志服务。

  • 解决方法:当前SDK需要通过OtlpTraceExporter进行数据上报,请确认OtlpTraceExporter的配置是否正确。以下为正确配置的示例。

    重要
    • host中不能添加 http:// 或https://。

    • port必须设置为10010。

    let client = ClientConnection
    .usingPlatformAppropriateTLS(for: MultiThreadedEventLoopGroup(numberOfThreads: 1))
    .connect(host: "cn-beijing.log.aliyuncs.com", port: 10010)
    
    let otlpTraceExporter = OtlpTraceExporter(channel: client, config: OtlpConfiguration(timeout: OtlpConfiguration.DefaultTimeoutInterval, headers: [
     ("x-sls-otel-project", "your trace project"),
     ("x-sls-otel-instance-id", "your trace instance id"),
     ("x-sls-otel-ak-id", "your access key id"),
     ("x-sls-otel-ak-secret", "your access key secret")
    ]))
相关文章

通过OpenTelemetry接入Java Trace数据 2025-04-22 10:45

本文介绍通过OpenTelemetry Java SDK将Java应用的Trace数据接入到日志服务的操作步骤。 前提条件

通过OpenTelemetry接入Golang Trace数据 2025-04-22 10:45

本文介绍通过OpenTelemetry Golang SDK将Golang应用的Trace数据接入到日志服务的操作步骤。 前提条件

通过OpenTelemetry接入Python Trace数据 2025-04-22 10:45

本文介绍通过OpenTelemetry Python SDK将Python应用的Trace数据接入到日志服务的操作步骤。 前提条件

通过OpenTelemetry接入Node.js Trace数据 2025-04-22 10:45

本文介绍通过opentelemetry-js SDK将Node.js应用的Trace数据接入到日志服务的操作步骤。 前提条件

通过OpenTelemetry接入C# Trace数据 2025-04-22 10:45

本文介绍通过OpenTelemetry .NET SDK将C#应用的Trace数据接入到日志服务的操作步骤。 前提条件

通过OpenTelemetry接入Rust Trace数据 2025-04-22 10:45

本文介绍通过OpenTelemetry Rust SDK将Rust应用的Trace数据接入到日志服务的操作步骤。 前提条件

目录
Copyright © 2025 your company All Rights Reserved. Powered by 赛尔网络.
京ICP备14022346号-15
gongan beian 京公网安备11010802041014号