日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

通過OpenTelemetry上報Android應用數據

通過OpenTelemetry為應用埋點并上報鏈路數據至可觀測鏈路 OpenTelemetry 版后,可觀測鏈路 OpenTelemetry 版即可開始監控應用,您可以查看應用拓撲、調用鏈路、異常事務、慢事務和SQL分析等一系列監控數據。本文介紹如何使用OpenTelemetry為Android應用埋點并上報數據。

前提條件

獲取接入點信息

新版控制臺

  1. 登錄可觀測鏈路 OpenTelemetry 版控制臺,在左側導航欄單擊接入中心

  2. 開源框架區域單擊OpenTelemetry卡片。

  3. 在彈出的OpenTelemetry面板中選擇數據需要上報的地域。

    說明

    初次接入的地域將會自動進行資源初始化。

  4. 選擇連接方式上報方式,然后復制接入點信息。

    • 連接方式:若您的服務部署在阿里云上,且所屬地域與選擇的接入地域一致,推薦使用阿里云內網方式,否則選擇公網方式。

    • 上報方式:根據客戶端支持的協議類型選擇HTTP或gRPC協議上報數據。

    image.png

舊版控制臺

  1. 登錄可觀測鏈路 OpenTelemetry 版控制臺

  2. 在左側導航欄單擊集群配置,然后在右側頁面單擊接入點信息頁簽。

  3. 在頁面頂部選擇需要接入的地域,然后在集群信息區域打開顯示Token開關。

  4. 客戶端采集工具區域單擊OpenTelemetry

    相關信息列中,獲取接入點信息。ot舊版中.jpg

    說明

    如果應用部署于阿里云生產環境,則選擇阿里云VPC網絡接入點,否則選擇公網接入點。

示例Demo

本文將通過具體示例介紹如何使用OpenTelemetry上報Android應用程序的鏈路數據,該方法同樣適用于Java語言和Kotlin語言應用。

示例代碼倉庫地址:opentelemetry-android-demo

步驟一:創建并配置應用

  1. 創建應用。

    1. 在Android Studio中新建應用,選擇Basic Views Activity應用模板,然后單擊Nextimage..png

    2. 選擇Java語言或者Kotlin語言,SDK支持的最小版本選擇API 24: Android 7.0 (Nougat),然后單擊Finish

  2. 添加依賴項。

    在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'
  3. 添加網絡配置。

    1. 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>
    2. 修改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初始化

  1. 創建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")
  2. 在應用程序初始化時對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追蹤鏈路數據

  1. 創建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()
        }
    }
  2. 為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)
  3. 為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()
    }
  4. 創建嵌套的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()
        }
    }

步驟四:運行項目查看上報的鏈路數據

  1. 運行項目,單擊Demo應用頁面中的按鈕。image..png

    通過logcat查看日志,可以看到通過LoggingSpanExporter導出的Span信息。

    image..png

  2. 可觀測鏈路 OpenTelemetry 版控制臺應用列表頁面選擇目標應用,查看鏈路數據。

    image..png

步驟五:打通客戶端與服務端應用鏈路

  1. 修改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();
  2. 導入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();
          }
      }
  3. 使用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();
        }
    }

    展開查看在onClick等事件中異步調用callHttpService方法的完整代碼

    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();
            }
        }
    
    }
  4. 調用鏈分析頁面查看客戶端與服務端打通的調用鏈。

    如下圖所示,AsyncRequestZipkinServer為Android應用,zipkin-demo-server為服務端應用。

    image