通過OpenTelemetry為應用埋點并上報鏈路數據至可觀測鏈路 OpenTelemetry 版后,可觀測鏈路 OpenTelemetry 版即可開始監控應用,您可以查看應用拓撲、調用鏈路、異常事務、慢事務和SQL分析等一系列監控數據。本文介紹如何使用OpenTelemetry為Android應用埋點并上報數據。
前提條件
新版控制臺
登錄可觀測鏈路 OpenTelemetry 版控制臺,在左側導航欄單擊接入中心。
在開源框架區域單擊OpenTelemetry卡片。
在彈出的OpenTelemetry面板中選擇數據需要上報的地域。
說明初次接入的地域將會自動進行資源初始化。
選擇連接方式和上報方式,然后復制接入點信息。
連接方式:若您的服務部署在阿里云上,且所屬地域與選擇的接入地域一致,推薦使用阿里云內網方式,否則選擇公網方式。
上報方式:根據客戶端支持的協議類型選擇HTTP或gRPC協議上報數據。
舊版控制臺
在左側導航欄單擊集群配置,然后在右側頁面單擊接入點信息頁簽。
在頁面頂部選擇需要接入的地域,然后在集群信息區域打開顯示Token開關。
在客戶端采集工具區域單擊OpenTelemetry。
在相關信息列中,獲取接入點信息。
說明如果應用部署于阿里云生產環境,則選擇阿里云VPC網絡接入點,否則選擇公網接入點。
示例Demo
本文將通過具體示例介紹如何使用OpenTelemetry上報Android應用程序的鏈路數據,該方法同樣適用于Java語言和Kotlin語言應用。
示例代碼倉庫地址:opentelemetry-android-demo
步驟一:創建并配置應用
創建應用。
在Android Studio中新建應用,選擇Basic Views Activity應用模板,然后單擊Next。
選擇Java語言或者Kotlin語言,SDK支持的最小版本選擇API 24: Android 7.0 (Nougat),然后單擊Finish。
添加依賴項。
在Module或Project級別的build.gradle中,添加以下依賴。
本例中使用的OpenTelemetry Java SDK版本為1.25.0,更多版本請參見Opentelemetry Java Releases。build.gradle完整示例代碼請參見build.gradle。
implementation platform('io.opentelemetry:opentelemetry-bom:1.25.0') implementation "io.opentelemetry:opentelemetry-api" implementation "io.opentelemetry:opentelemetry-context" implementation 'io.opentelemetry:opentelemetry-exporter-otlp' implementation 'io.opentelemetry:opentelemetry-exporter-logging' implementation 'io.opentelemetry:opentelemetry-extension-kotlin' implementation 'io.opentelemetry:opentelemetry-sdk' implementation 'io.opentelemetry:opentelemetry-semconv'
添加網絡配置。
在
app/res/xml
目錄下創建network_security_config.xml文件并添加以下內容。<!-- 查看文件完整內容: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/res/xml/network_security_config.xml --> <?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="true"> <!-- 請將下面的域名替換為您在前提條件中獲取的接入點,請不要包含"http://"、端口號和URL路徑 --> <domain includeSubdomains="true">tracing-analysis-dc-hz.aliyuncs.com</domain> </domain-config> </network-security-config>
修改
app/src/main/AndroidManifest.xml
文件,添加以下兩行內容為應用開啟網絡權限。<!-- 查看文件完整內容: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/AndroidManifest.xml --> <?xml version="1.0" encoding="utf-8"?> <manifest ...> <!-- 添加下面一行內容,以開啟網絡權限 --> <uses-permission android:name="android.permission.INTERNET" /> <application ... <!-- 添加下面一行內容,對要上報數據的域名進行網絡配置 --> android:networkSecurityConfig="@xml/network_security_config" ...> ... </application> </manifest>
步驟二:OpenTelemetry初始化
創建OpenTelemetry工具類。
在MainActivity所在的同級目錄下創建OpenTelemetryUtil文件并添加以下內容。
方法一:通過gRPC上報Trace數據
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/OpenTelemetryUtil.java */ Resource otelResource = Resource.getDefault().merge( Resource.create( Attributes.of( // 請將<your-service-name>替換為您的應用名。 ResourceAttributes.SERVICE_NAME, "<your-service-name>", // 請將<your-host-name>替換為您的主機名。 ResourceAttributes.HOST_NAME, "<your-host-name>" ) ) ); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // 可選,將鏈路數據打印到日志/命令行,如不需要請注釋這一行。 // 請將<gRPC-endpoint>替換為從前提條件中獲取的接入點,<gRPC-token>替換為鑒權Token。 .addSpanProcessor(BatchSpanProcessor.builder( OtlpGrpcSpanExporter.builder() .setEndpoint("<gRPC-endpoint>") // 例如:http://tracing-analysis-dc-hz.aliyuncs.com:8090 .addHeader("Authentication", "<gRPC-token>") // 例如:xxxx@xxxx_xxxx@xxxx .build()).build() ) .setResource(otelResource) .build(); OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal(); // 獲取tracer,用來創建Span。 tracer = openTelemetry.getTracer("android-tracer", "1.0.0");
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/OpenTelemetryUtil.kt */ val otelResource = Resource.getDefault().merge( Resource.create( Attributes.of( ResourceAttributes.SERVICE_NAME, "<your-service-name>", // 請將<your-service-name>替換為您的應用名。 ResourceAttributes.HOST_NAME, "<your-host-name>" // 請將<your-host-name>替換為您的主機名。 ) ) ) /* 使用gRPC協議上報鏈路數據 */ val sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // 可選,將鏈路數據打印到日志/命令行,如不需要請注釋這一行。 // 請將<gRPC-endpoint>替換為從前提條件中獲取的接入點,<gRPC-token>替換為鑒權Token。 .addSpanProcessor( BatchSpanProcessor.builder( OtlpGrpcSpanExporter.builder() .setEndpoint("<gRPC-endpoint>") // 例如:http://tracing-analysis-dc-hz.aliyuncs.com:8090 .addHeader("Authentication", "<gRPC-token>") // 例如:xxxx@xxxx_xxxx@xxxx .build() ).build() ) .setResource(otelResource) .build() val openTelemetry: OpenTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal() // 獲取tracer,用來創建Span。 tracer = openTelemetry.getTracer("android-tracer", "1.0.0")
方法二:通過HTTP上報Trace數據
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/OpenTelemetryUtil.java */ Resource otelResource = Resource.getDefault().merge( Resource.create( Attributes.of( // 請將<your-service-name>替換為您的應用名。 ResourceAttributes.SERVICE_NAME, "<your-service-name>", // 請將<your-host-name>替換為您的主機名。 ResourceAttributes.HOST_NAME, "<your-host-name>" ) ) ); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // 可選,將鏈路數據打印到日志/命令行,如不需要請注釋這一行 // 請將<HTTP-endpoint>替換為從前提條件中獲取的接入點。 .addSpanProcessor(BatchSpanProcessor.builder( OtlpHttpSpanExporter.builder() .setEndpoint("<HTTP-endpoint>") // 例如 http://tracing-analysis-dc-hz.aliyuncs.com/adapt_xxxx@xxxx_xxxx@xxxx/api/otlp/traces .build()).build() ) .setResource(otelResource) .build(); OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal(); // 獲取tracer,用來創建Span。 tracer = openTelemetry.getTracer("android-tracer", "1.0.0");
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/OpenTelemetryUtil.kt */ val otelResource = Resource.getDefault().merge( Resource.create( Attributes.of( ResourceAttributes.SERVICE_NAME, "<your-service-name>", // 請將<your-service-name>替換為您的應用名。 ResourceAttributes.HOST_NAME, "<your-host-name>" // 請將<your-host-name>替換為您的主機名。 ) ) ) /* 使用HTTP協議上報鏈路數據 */ val sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // 可選,將鏈路數據打印到日志/命令行,如不需要請注釋這一行。 // 請將<HTTP-endpoint>替換為從前提條件中獲取的接入點。 .addSpanProcessor(BatchSpanProcessor.builder( OtlpHttpSpanExporter.builder() .setEndpoint("<HTTP-endpoint>") // 例如:http://tracing-analysis-dc-hz.aliyuncs.com/adapt_xxxx@xxxx_xxxx@xxxx/api/otlp/traces .build()).build() ) .setResource(otelResource) .build(); val openTelemetry: OpenTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal() // 獲取tracer,用來創建Span。 tracer = openTelemetry.getTracer("android-tracer", "1.0.0")
在應用程序初始化時對OpenTelemetry進行初始化。
在MainActivity的onCreate方法中調用OpenTelemetryUtil.init()方法。
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/MainActivity.java */ ... public class MainActivity extends AppCompatActivity { ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 請添加這一行,對OpenTelemetry進行初始化。 OpenTelemetryUtil.init(); ... } ... }
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/MainActivity.kt */ ... class MainActivity : AppCompatActivity() { ... override fun onCreate(savedInstanceState: Bundle?) { WindowCompat.setDecorFitsSystemWindows(window, false) super.onCreate(savedInstanceState) // 請添加這一行,OpenTelemetry初始化。 OpenTelemetryUtil.init() ... } }
步驟三:創建Span追蹤鏈路數據
創建Span。
在FirstFragment文件的按鈕點擊事件監聽方法中,創建一個名為First Fragment Button onClick的Span。
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java */ public void onClick(View view) { // 獲取Tracer Tracer tracer = OpenTelemetryUtil.getTracer(); // 創建Span Span span = tracer.spanBuilder("First Fragment Button onClick").startSpan(); try (Scope scope = span.makeCurrent()) { // 獲取traceId System.out.println(span.getSpanContext().getTraceId()); ... } finally { span.end(); } }
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt */ binding.buttonFirst.setOnClickListener { // 獲取Tracer val tracer: Tracer = OpenTelemetryUtil.getTracer()!! // 創建Span val span = tracer.spanBuilder("First Fragment Button onClick").startSpan() try { span.makeCurrent().use { scope -> // 獲取traceId println(span.spanContext.traceId) // 獲取spanId println(span.spanContext.spanId) findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment) } } catch (t: Throwable) { span.setStatus(StatusCode.ERROR, "Something wrong in onClick") throw t } finally { span.end() } }
為Span設置屬性和事件(Event)。
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java */ // 設置屬性 span.setAttribute("key", "value"); Attributes eventAttributes = Attributes.of( AttributeKey.stringKey("key"), "value", AttributeKey.longKey("result"), 0L); // 添加事件 span.addEvent("onClick", eventAttributes);
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt */ // 設置屬性 span.setAttribute("key", "value") val eventAttributes = Attributes.of( AttributeKey.stringKey("key"), "value", AttributeKey.longKey("result"), 0L ) // 添加事件 span.addEvent("onClick", eventAttributes)
為Span設置狀態(Status)。
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java */ ... try (Scope scope = span.makeCurrent()) { ... } catch (Throwable t) { // 設置Span狀態 span.setStatus(StatusCode.ERROR, "Something wrong in onClick"); throw t; } finally { span.end(); }
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt */ ... try { ... } catch (t: Throwable) { // 為Span設置狀態 span.setStatus(StatusCode.ERROR, "Something wrong in onClick") throw t } finally { span.end() }
創建嵌套的Span。
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java */ public void parentSpan() { // 獲取Tracer Tracer tracer = OpenTelemetryUtil.getTracer(); // 創建Span Span span = tracer.spanBuilder("Parent Span").startSpan(); try (Scope scope = span.makeCurrent()) { // 獲取traceId System.out.println(span.getSpanContext().getTraceId()); // 獲取spanId System.out.println(span.getSpanContext().getSpanId()); childSpan(); } finally { span.end(); } } public void childSpan() { // 獲取Tracer Tracer tracer = OpenTelemetryUtil.getTracer(); // 創建Span Span span = tracer.spanBuilder("Child Span").startSpan(); try (Scope scope = span.makeCurrent()) { // 獲取traceId System.out.println(span.getSpanContext().getTraceId()); // 獲取spanId System.out.println(span.getSpanContext().getSpanId()); } finally { span.end(); } }
/** 請訪問以下鏈接獲取完整代碼 https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt */ // 嵌套Span fun parentSpan() { // 獲取Tracer val tracer: Tracer = OpenTelemetryUtil.getTracer()!! // 創建Span val span = tracer.spanBuilder("Parent Span").startSpan() try { span.makeCurrent().use { scope -> // 獲取traceId println(span.spanContext.traceId) // 獲取spanId println(span.spanContext.spanId) childSpan() } } finally { span.end() } } // 嵌套Span fun childSpan() { // 獲取Tracer val tracer: Tracer = OpenTelemetryUtil.getTracer()!! // 創建Span val span = tracer.spanBuilder("Child Span").startSpan() try { span.makeCurrent().use { scope -> // 獲取traceId println(span.spanContext.traceId) // 獲取spanId println(span.spanContext.spanId) } } finally { span.end() } }
步驟四:運行項目查看上報的鏈路數據
運行項目,單擊Demo應用頁面中的按鈕。
通過logcat查看日志,可以看到通過LoggingSpanExporter導出的Span信息。
在可觀測鏈路 OpenTelemetry 版控制臺的應用列表頁面選擇目標應用,查看鏈路數據。
步驟五:打通客戶端與服務端應用鏈路
修改Header中的Trace透傳格式。
不同協議使用不同的HTTP Header向下游傳遞Trace上下文,如OpenTelemtry默認使用W3C Trace Context格式(也支持修改為其他格式),而Zipkin使用B3或B3 Multi格式。關于透傳格式的更多信息,請參見OpenTelemetry指定透傳Header格式。
根據服務端使用的協議類型,在客戶端中設置對應的透傳格式(textPropagators),以實現Android客戶端應用與服務端應用鏈路打通:
如果服務端使用OpenTelemetry默認的W3C Trace Context格式,客戶端無需設置textPropagators。
如果服務端使用Zipkin的B3/B3 Multi格式,客戶端的textPropagators需要設置為B3Propagator。
// 設置B3透傳格式。 OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(TextMapPropagator.composite( B3Propagator.injectingMultiHeaders(), B3Propagator.injectingSingleHeader()))) .buildAndRegisterGlobal();
如果服務端使用Jaeger協議,客戶端的textPropagators需設置為JaegerPropagator。
// 設置Jaeger透傳格式。 OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(TextMapPropagator.composite( JaegerPropagator.getInstance()))) .buildAndRegisterGlobal();
也可以同時設置多種Trace透傳格式。
// 同時使用W3C Trace Context、B3、Jaeger三種Trace透傳格式。 // 設置Jaeger透傳格式。 OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(TextMapPropagator.composite( W3CTraceContextPropagator.getInstance(), B3Propagator.injectingMultiHeaders(), B3Propagator.injectingSingleHeader() JaegerPropagator.getInstance()))) .buildAndRegisterGlobal();
導入okhttp3和opentelemetry-okhttp。
opentelemetry-okhttp-3.0是OpenTelemetry提供的針對OkHttp的自動埋點插件,可以自動攔截所有通過OkHttp3發出的網絡請求并創建調用鏈。
在build.gradle中添加以下兩個依賴。
dependencies { ... implementation 'io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0:2.3.0-alpha' implementation 'com.squareup.okhttp3:okhttp:4.12.0' }
創建OkHttpConfiguration。
import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.okhttp.v3_0.OkHttpTelemetry; import okhttp3.Call; import okhttp3.OkHttpClient; public class OkHttpConfiguration { //Use this Call.Factory implementation for making standard http client calls. public Call.Factory createTracedClient(OpenTelemetry openTelemetry) { return OkHttpTelemetry.builder(openTelemetry).build().newCallFactory(createClient()); } //your configuration of the OkHttpClient goes here: private OkHttpClient createClient() { return new OkHttpClient.Builder().build(); } }
使用OkHttp3進行網絡請求,訪問服務端。
private void callHttpService() throws IOException { Tracer tracer = OpenTelemetryUtil.getTracer(); // 創建Span Span span = tracer.spanBuilder("AsyncRequestZipkinServer").startSpan(); System.out.println("AsyncRequestZipkinServer TraceID: " + span.getSpanContext().getTraceId()); System.out.println("AsyncRequestZipkinServer SpanID: " + span.getSpanContext().getSpanId()); try (Scope scope = span.makeCurrent()) { // 執行網絡請求,例如使用 OkHttp OkHttpConfiguration configuration = new OkHttpConfiguration(); Call.Factory tracedClient = configuration.createTracedClient(GlobalOpenTelemetry.get()); Request request = new Request.Builder().url("${服務端地址}").get().build(); Call call = tracedClient.newCall(request); try (Response response = call.execute()) { // 處理響應 String responseBody = response.body().string(); System.out.println(responseBody); } catch (IOException e) { // 處理錯誤 e.printStackTrace(); } } finally { span.end(); } }
import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.navigation.fragment.NavHostFragment; import com.example.androidjavademo.databinding.FragmentFirstBinding; import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; import okhttp3.Call; import okhttp3.Request; import okhttp3.Response; public class FirstFragment extends Fragment { private FragmentFirstBinding binding; @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { binding = FragmentFirstBinding.inflate(inflater, container, false); return binding.getRoot(); } public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); binding.buttonFirst.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 獲取Tracer Tracer tracer = OpenTelemetryUtil.getTracer(); // 創建Span Span span = tracer.spanBuilder("First Fragment Button onClick").startSpan(); try (Scope scope = span.makeCurrent()) { // 獲取traceId System.out.println(span.getSpanContext().getTraceId()); // 獲取spanId System.out.println(span.getSpanContext().getSpanId()); // 設置屬性 span.setAttribute("key", "value"); Attributes eventAttributes = Attributes.of( AttributeKey.stringKey("key"), "value", AttributeKey.longKey("result"), 0L); // 添加事件 span.addEvent("onClick", eventAttributes); parentSpan(); NavHostFragment.findNavController(FirstFragment.this) .navigate(R.id.action_FirstFragment_to_SecondFragment); } catch (Throwable t) { span.setStatus(StatusCode.ERROR, "Something wrong in onClick"); throw t; } finally { span.end(); } } }); } @Override public void onDestroyView() { super.onDestroyView(); binding = null; } public void parentSpan() { ExecutorService executorService = Executors.newSingleThreadExecutor(); Handler handler = new Handler(Looper.getMainLooper()); // 獲取Tracer Tracer tracer = OpenTelemetryUtil.getTracer(); // 創建Span Span span = tracer.spanBuilder("Parent Span").startSpan(); try (Scope scope = span.makeCurrent()) { // 獲取traceId System.out.println(span.getSpanContext().getTraceId()); // 獲取spanId System.out.println(span.getSpanContext().getSpanId()); executorService.execute(new Runnable() { @Override public void run() { // 執行網絡請求 try { callHttpService(); } catch (IOException e) { throw new RuntimeException(e); } // 執行完畢,通過handler切回主線程處理結果 handler.post(new Runnable() { @Override public void run() { // 處理UI更新或其他工作 childSpan(); } }); } }); executorService.shutdown(); } finally { span.end(); } } public void childSpan() { // 獲取Tracer Tracer tracer = OpenTelemetryUtil.getTracer(); // 創建Span Span span = tracer.spanBuilder("Child Span").startSpan(); try (Scope scope = span.makeCurrent()) { // 獲取traceId System.out.println(span.getSpanContext().getTraceId()); // 獲取spanId System.out.println(span.getSpanContext().getSpanId()); } finally { span.end(); } } private void callHttpService() throws IOException { Tracer tracer = OpenTelemetryUtil.getTracer(); // 創建Span Span span = tracer.spanBuilder("AsyncRequestZipkinServer").startSpan(); System.out.println("AsyncRequestZipkinServer TraceID: " + span.getSpanContext().getTraceId()); System.out.println("AsyncRequestZipkinServer SpanID: " + span.getSpanContext().getSpanId()); try (Scope scope = span.makeCurrent()) { // 執行網絡請求,例如使用OkHttp OkHttpConfiguration configuration = new OkHttpConfiguration(); Call.Factory tracedClient = configuration.createTracedClient(GlobalOpenTelemetry.get()); Request request = new Request.Builder().url("${服務端地址}").get().build(); Call call = tracedClient.newCall(request); try (Response response = call.execute()) { // 處理響應 String responseBody = response.body().string(); System.out.println(responseBody); } catch (IOException e) { // 處理錯誤 e.printStackTrace(); } } finally { span.end(); } } }
在調用鏈分析頁面查看客戶端與服務端打通的調用鏈。
如下圖所示,
AsyncRequestZipkinServer
為Android應用,zipkin-demo-server
為服務端應用。