1. OTel 简介
OTel 是 OpenTelemetry 的简称,OpenTelemetry 官方提供了 Android、iOS SDK 安装包。
OTel 主要做了什么?
制定标准规范
接收、处理、输出观测数据
数据采集 SDK
各种语言的 SDK
Instrumentation,开箱即用的数据采集器
OTel SDK 的特征:
数据产生
只依赖API库,可以理解为面向API接口采集数据,不关注SDK的具体实现。业务方使用时,可以按需选择 SDK 库的具体实现。
API
Signal 协议的声明,如:Trace、Logs、Metrics,扩展性较好
scopes,包含作用域信息
context,可自动管理上下文
propagation,提供 context 传播机制
processor,支持对 Span 进行自定义处理
SDK
API 的具体实现,OTel 针对主流的语言实现了默认的SDK。OTel SDK 主要做的事情是实现对应Signal的协议,具备良好的扩展性,并基于OTLP协议默认实现了几个Exporters。
Exporter
数据导出,把采集的Span等数据导出到目标位置。
Instrumentation
具体要采集什么数据,一般需要通过Instrumentation实现。即:针对具体要采集的数据(如 HTTP ),把元数据按照通用的语义规范(semantic conventions),通过 OTel SDK 进行数据采集。
2. 准备工作
2.1 开通 Trace 实例
采集 Android/iOS Trace 数据时,需要先开通 Trace 服务。请参考创建 Trace 实例这篇文章开通 Trace 服务。
2.2 保留必要信息
Trace 服务开通后,需要保留以下信息,初始化 SDK 时会使用到后续也可以在 Trace 服务列表中找到相关信息。
instanceId:也叫实例ID。
project:Trace 实例关联的 Log Project。
endpoint:Log Project 所在的地域,在 Project 的项目概览页面可以看到该 Project 所在地域的服务入口。
3. 接入 SDK
3.1 Android SDK 集成
在 Android 平台上,可以通过集成 OpenTelemetry Java SDK 来支持。
// BOM清单,用于同步依赖版本
implementation(platform("io.opentelemetry:opentelemetry-bom:1.22.0"))
// APIs
implementation("io.opentelemetry:opentelemetry-api")
implementation("io.opentelemetry:opentelemetry-context")
// API extensions,项目中使用到了 kotlin 时建议添加该依赖
implementation("io.opentelemetry:opentelemetry-extension-kotlin")
// SDKs
implementation('io.opentelemetry:opentelemetry-sdk')
// semantic conventions
implementation("io.opentelemetry:opentelemetry-semconv")
// exporters
// 官方 gRPC exporter
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
Trace 数据的上报需要申请网络权限,请在 AndroidManifest.xml 文件中加入以下权限声明。
接下来,需要完成 OTel SDK 的初始化,一般建议在 Application 类的 onCreate 方法中对 SDK 进行初始化。
// 初始化 exporter。exporter 的主要作用是导出 trace 数据到 SLS logstore。
OtlpGrpcSpanExporter grpcSpanExporter = OtlpGrpcSpanExporter.builder()
.setEndpoint("https://${endpoint}") // 注意,该endpoint需要带端口号
.addHeader("x-sls-otel-project", "${project}")
.addHeader("x-sls-otel-instance-id", "${instanceId}")
.addHeader("x-sls-otel-ak-id", "${access-key-id}")
.addHeader("x-sls-otel-ak-secret", "${access-key-secret}")
.build();
// 初始化 tracer provider。tracer provider 暴露一些主要的API,用于对 Span 预处理,自定义Clock,
// 自定义TraceId、SpanId生成规则,自定义采样器等。可以根据实际的需要进行配置
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(grpcSpanExporter).build())
.setResource(Resource.create(Attributes.builder()
.put(ResourceAttributes.SERVICE_NAME, "${service}")
.put(ResourceAttributes.SERVICE_NAMESPACE, "${service.namespace}")
.put(ResourceAttributes.SERVICE_VERSION, "${version}")
.put(ResourceAttributes.HOST_NAME, "${host}")
.put(ResourceAttributes.DEPLOYMENT_ENVIRONMENT, "${environment}")
.build()
)
)
.build();
// 初始化 OpenTelemetrySdk。
OpenTelemetrySdk telemetrySdk = OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.build(); // 如果通过 build() 方法生成实例,需要根据实际使用情况来决定是否对telemetrySdk进行全局持有
// 也可以初始化一个全局的 OpenTelemetrySdk
// OpenTelemetrySdk telemetrySdk = OpenTelemetrySdk.builder()
// .setTracerProvider(tracerProvider)
// .buildAndRegisterGlobal();
// 后续可通过 GlobalOpenTelemetry.get() 或 GlobalOpenTelemetry.getTracer() 进行访问
${endpoint}、${project} 等变量的说明,参见通过《OpenTelemetry接入Android Trace数据》文档。
3.2 iOS SDK 集成
在 iOS 平台上,可以通过 OpenTelemetry Swift SDK 来支持。如果您的 iOS 项目主要使用 ObjC 语言,还需要引用 opentelemetry-objc-extension SDK。opentelemetry-objc-extension SDK 是 SLS 团队基于 opentelemetry-swift SDK 开发的非官方扩展。
通过 Xcode 集成
在 Xcode 中点开 File 菜单,然后选择 Add Package,在弹出的 Package 添加窗口中输入以下链接。
https://github.com/open-telemetry/opentelemetry-swift
// ObjC 项目还要引入 opentelemetry-objc-extension
https://github.com/aliyun-sls/opentelemetry-objc-extension
接下来,选择您要使用的版本。对于新接入的项目,我们建议使用最新版本的 OpenTelemetry。
通过 Package.swift 集成
要通过Package.swift 清单将 OpenTelemetry 集成到 Swift 软件包,您可以将 OpenTelemetry 添加到软件包的 depenencies 数组中。如需了解详情,请参阅 Swift Package Manager 文档。
dependencies: [
.package(url: "https://github.com/open-telemetry/opentelemetry-swift", from: "1.4.0"),
// ...
],
然后,在任何依赖 OpenTelemetry 的 target 中,将 OpenTelemetry 添加到该 target 的 dependencies 数组中。
.target(
name: "YourTargetName",
dependencies: ["OpenTelemetryApi"] // 或者 dependencies: ["OpenTelemetrySdk"]
)
接下来,需要完成 OTel 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 数据到 SLS logstore。
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", "${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 数据到 sls logstore。
// ${endpoint}、${port}、${project} 等变量的说明,参见下表变量说明。
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}、${project} 等变量的说明,参见通过《OpenTelemetry接入iOS Trace数据》文档。
4. 生成 Trace 数据
Trace 数据通常也叫做追踪数据,即 Tracing。Tracing 通常由一组逻辑操作(Span)构成。Span 代表了事务中的操作,每个 Span 会封装操作名称、起止时间戳、属性、事件、父 Span 等信息。
4.1 创建 Tracer
在生成 Trace 数据之前,我们需要先创建一个 Tracer。
Java 示例:
Tracer tracer = telemetrySdk.getTracer("OTel App", "1.0.0");
ObjC 示例:
TracerObjc *tracer = [OpenTelemetryObjc.instance.tracerProvider get:@"OTel App" instrumentationVersion:@"1.0"]
Swift 示例:
let tracer: Tracer = OpenTelemetry.instance.tracerProvider.get(instrumentationName: "OTel App", instrumentationVersion: "1.0.0")
建议根据不同的业务场景来创建 Tracer。创建 Tracer 时需要传入 instrumentation scope name。不同的业务场景传入不同的 Instrumentation name 有利于对 Trace 数据按照 scope 进行区分。
4.2 创建常规 Span
如上图,是一个包含时间跨度信息(也指操作执行耗时信息,即:487.56ms),操作名称是“operation name”,来源服务是 Android,操作类型是 client 的 Trace。这种类型的 Trace 该如何生成?
Java 示例:
final Span span = tracer
.spanBuilder("operation name")
.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];
Swift 示例:
let spanBuilder = tracer.spanBuilder(spanName: "operation name")
let span = spanBuilder .setSpanKind(spanKind: .client).startSpan()
// do stuff
// ...
span.end()
以上示例中的 spanKind 建议根据实际情况设置。OTel SDK 中,spanKind 的默认值是 internal。
4.3 给 Span 带上属性、事件、状态
如上图:
这条 Trace 数据的状态是 ERROR
属性中携带item_id、product_id、shop_id 三个信息
日志中包含了一条名为“item id is empty”的事件,扩展信息中包含 item_id 信息
我们看下如何产生这种类型的 Trace 数据。
Java 示例:
final Span span = tracer
.spanBuilder("operation name")
.setSpanKind(SpanKind.CLIENT)
// 设置属性信息
// 也可通过下面的方式设置属性信息:
// span.setAttribute("product_id", 202302210002L)
.setAttribute("product_id", 202302210002L)
.setAttribute("shop_id", 201708080003L)
.setAttribute("item_id", 202302220001L)
.startSpan();
// do stuff
// ...
// 设置事件信息
span.addEvent("item id is empty", Attributes.of(AttributeKey.longKey("item_id"), 202302220001L));
// 设置状态信息
span.setStatus(StatusCode.ERROR, "item id is empty");
span.end();
ObjC 示例:
SpanBuilderObjc *builder = [[_tracer spanBuilder:@"operation name"] setSpanKind:SpanKindObjc.CLIENT];
// 设置属性信息
// 也可通过下面的方式设置属性信息:
// [span setAttribute:@"product_id" doubleValue:202302210002L)];
[builder setAttribute:@"product_id" doubleValue:202302210002L];
[builder setAttribute:@"shop_id" doubleValue:201708080003L];
[builder setAttribute:@"item_id" doubleValue:202302220001L];
SpanObjc *span = [builder startSpan];
// do stuff
// ...
// 设置事件信息
[span addEvent:@"item id is empty" attributes:@{
@"item_id": [AttributeValueObjc double:202302220001L]
}];
// 设置状态信息
[span setStatus:[StatusObjc error: @"item id is empty"]];
[span end];
Swift 示例:
let span = tracer.spanBuilder(spanName: "operation name")
.setSpanKind(spanKind: .client)
// 设置属性信息
// 也可通过下面的方式设置属性信息:
// span.setAttribute(key: "product_id", value: AttributeValue.double(202302210002))
.setAttribute(key: "product_id", value: 202302210002)
.setAttribute(key: "shop_id", value: 201708080003)
.setAttribute(key: "item_id", value: 202302220001)
.startSpan()
// do stuff
// ...
// 设置事件信息
span.addEvent(name: "item id is empty", attributes: ["item_id": AttributeValue.double(0)])
// 设置状态信息
span.status = .error(description: "item id is empty")
span.end()
4.4 创建嵌套 Span
很多时候,一个操作会包含多个子操作,甚至子操作也会包含多个子操作。我们可以通过手动关联 Span,也可以通过 OTel 提供的 Api 自动关联。
Java 示例:
// 手动链接示例
void methodA() {
final Span parent = tracer
.spanBuilder("parent operation")
.setSpanKind(SpanKind.CLIENT)
.startSpan();
methodB(parent);
parent.end();
}
void methodB(Span parent) {
final Span child = tracer
.spanBuilder("child operation")
.setSpanKind(SpanKind.CLIENT)
// 手动链接
.setParent(Context.current().with(parent))
.startSpan();
// do stuff
// ...
child.end();
}
// 自动链接示例
void methodA() {
final Span parent = tracer
.spanBuilder("parent operation")
.setSpanKind(SpanKind.CLIENT)
.startSpan();
try (Scope ingored = parent.makeCurrent()) {
methodB();
} finally {
parent.end();
}
}
void methodB() {
final Span child = tracer
.spanBuilder("child operation")
.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];
}
// 自动关联
- (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];
}
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()
}
// 自动关联
- (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];
}
4.5 传播上下文信息
OTel 提供了一种使用文本传播上文信息的方法。基于这种方法可以使用 W3C Trace Context HTTP 头信息在客户端与微服务之间传递上下文信息,从而串联起端到端之间的调用。如下图:
Java 示例:
// 基于 HttpURLConnection Header setter
TextMapSetter setter =
new TextMapSetter() {
@Override
public void set(HttpURLConnection carrier, String key, String value) {
// Insert the context as Header
carrier.setRequestProperty(key, value);
}
};
URL url = new URL("http://127.0.0.1:8088/resource/catalog");
Span httpSpan = tracer.spanBuilder("GET /resource/catalog").setSpanKind(SpanKind.CLIENT).startSpan();
try (Scope scope = httpSpan.makeCurrent()) {
// 注入属性信息,记录HTTP请求的相关详情
httpSpan.setAttribute(SemanticAttributes.HTTP_METHOD, "GET");
httpSpan.setAttribute(SemanticAttributes.HTTP_URL, url.toString());
HttpURLConnection transportLayer = (HttpURLConnection) url.openConnection();
// 把当前的 Context 信息注入到 HTTP request 中
telemetrySdk.getPropagators().getTextMapPropagator().inject(Context.current(), transportLayer, setter);
// do stuff
} finally {
httpSpan.end();
}
ObjC 示例:
// 在SDK初始化时,需要完成 URLSessionInstrumentationObjc 的初始化
// 初始化 URLSessionInstrumentationObjc 时,需要传入一个实现了URLSessionInstrumentationConfigurationImpl协议的类(可参考后文的TestURLSessionInstrumentation实现)
[URLSessionInstrumentationObjc urlSessionInstrumentation:
[URLSessionInstrumentationConfigurationObjc urlSessionInstrumentationConfiguration:[TestURLSessionInstrumentation instrumentation]]
];
// TestURLSessionInstrumentation 的实现,供参考
#pragma mark - URLSessionInstrumentation
@interface TestURLSessionInstrumentation: NSObject
+ (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
Swift 示例:
// 在SDK初始化时,需要完成 URLSessionInstrumentation 的初始化
// Swift 的初始化相对简单些,可以按需传入对应的参数
URLSessionInstrumentation(
configuration: URLSessionInstrumentationConfiguration(
shouldInstrument: { request in
// 是否采集该request的数据
return true
}
)
)
5. 分析 Trace 数据
5.1 查询 Android、iOS Trace 数据
Trace 数据经过 OTel SDK 采集到日志服务之后,数据会存储在 SLS 对应的 Log Store 中。这些数据是经过协议化之后的原始数据,我们在进行分析时,直接对原始数据分析体感上并不友好。SLS Trace 服务提供了可视化的查询能力,我们可以在 Trace 分析页面中通过简单的操作,即可筛选出目标数据。
如上图,在 Trace 分析页面,通过筛选出 Service 字段的值,即可过滤出目标数据。其中,Service 字段需要与前文中接入 SDK 时配置的 ${service} 值一致。
还可以对 Attributes 进行过滤,如下图:
实际使用时,可以根据业务的需要对指定 attribute 进行过滤。
除此之外,还支持在高级查询中对 SpanKind 和 Resource 等进行过滤查询,如下图:
5.2 链路调用分析
在 Trace 分析页面,还可以直观看到每个 Span 之间的调用链路。找一个包含子 Span 的节点,然后进入 Trace 详情,如下图:
可以比较清晰的看到:
每个操作的耗时信息
通过耗时信息,我们可以分析出整个调用链路中每个操作的耗时分布,进而找出对链路影响比较大的节点。
操作之间的关联关系
端与端之间的调用链路
5.3 耗时操作分析
通过慢 Trace 分析,可以自动的发现指定时间段内是否存在耗时异常的操作。
选取了 Service 和时间范围后,可以看到系统帮我们自动统计出了对应操作的平均响应时间、是否存在异常,并绘制出相关的趋势图。
系统也会自动识别出当前时间段内最耗时的 10 条 Trace,通过对应 Trace 的入口,可以直接跳转到对应的 Trace 详情。
通过 Trace 详情可以比较容易的知道当前耗时较长的操作所处的具体调用链路,方便进一步分析。
5.4 自定义分析
SLS Trace 服务支持使用 SQL92 语句对原始 Trace 日志进行自定义分析。例如:基于 Trace 数据做 UV、PV 的分析。
可以分别用下面两条 SQL 分析语句生成上图的结果:
用户数
* and service: Android | select
count(distinct json_extract(resource, '$["device.id"]')) as uv,
count(json_extract(resource, '$["device.id"]')) as pv
from log
用户数趋势
* and service: Android | select
count(distinct json_extract(resource, '$["device.id"]')) as uv,
count(json_extract(resource, '$["device.id"]')) as pv,
date_trunc('day', __time__) as day
from log
group by day
附:
联系阿里云 SLS