All Products
Search
Document Center

Application Real-Time Monitoring Service:Use OpenTelemetry to report the trace data of Android applications

Last Updated:Jun 07, 2024

After you use OpenTelemetry to instrument an application and report the trace data to Managed Service for OpenTelemetry, Managed Service for OpenTelemetry starts to monitor the application. You can view the monitoring data of the application such as application topology, traces, abnormal transactions, slow transactions, and SQL analysis. This topic describes how to instrument an Android application and report the trace data of the Android application by using OpenTelemetry.

Before you begin

To obtain an endpoint of OpenTelemetry, perform the following steps:

  1. Log on to the Managed Service for OpenTelemetry console.

  2. In the left-side navigation pane, click Cluster Configurations. On the page that appears, click the Access point information tab.

  3. In the top navigation bar, select a region. In the Cluster Information section, turn on Show Token.

  4. Set the Client parameter to OpenTelemetry.

    Obtain an endpoint of OpenTelemetry in the Related Information column of the table in the lower part.OT接入点信息

    Note

    If your application is deployed in an Alibaba Cloud production environment, use a Virtual Private Cloud (VPC) endpoint. Otherwise, use a public endpoint.

Sample code

In this example, OpenTelemetry is used to report the trace data of an Android application. The method used in this example also applies to applications written in Java or Kotlin.

You can download the sample code from opentelemetry-android-demo.

Step 1: Create and configure an application

  1. Create an application.

    1. Create an application in Android Studio. Select Basic Views Activity and click Next.image..png

    2. Select Java or Kotlin as Language, select API 24: Android 7.0 (Nougat) as Minimum SDK, and then click Finish.

  2. Add dependencies.

    Add the following dependencies to the build.gradle file of a module or project.

    In this example, the version of OpenTelemetry SDK for Java is 1.25.0. For information about the SDK versions, see Releases of opentelemetry-java. For information about the complete sample code, see 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. Configure network settings.

    1. Create a file named network_security_config.xml in the app/res/xml directory and add the following content to the file:

      <!-- To view the complete content of the file, visit 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">
          <!-- Replace the domain name with the endpoint that you have obtained as instructed in the "Before you begin" section of this topic. The endpoint cannot contain http://, a port number, or a URL path. -->
          <domain includeSubdomains="true">tracing-analysis-dc-hz.aliyuncs.com</domain>
        </domain-config>
      </network-security-config>
    2. Add the following content to the app/src/main/AndroidManifest.xml file to allow the application to access the network:

      <!-- To view the complete content of the file, visit https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/AndroidManifest.xml. -->
      
      <?xml version="1.0" encoding="utf-8"?>
      <manifest ...>
        <!-- Add the following line to grant network access permissions. -->
        <uses-permission android:name="android.permission.INTERNET" />
      
        <application
          ...
          <!-- Add the following line to configure the network for the domain name to which you want to report data. -->
          android:networkSecurityConfig="@xml/network_security_config"
          ...>
      
          ...
        </application>
      
      </manifest>

Step 2: Initialize OpenTelemetry

  1. Create an OpenTelemetry utility class.

    Create an OpenTelemetryUtil file in the directory in which the MainActivity file resides and add the following content to the OpenTelemetryUtil file.

    • Method 1: Report trace data over gRPC

      /**
       Visit the following link to view the complete code:
       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(
                  // Replace <your-service-name> with your application name. 
              	ResourceAttributes.SERVICE_NAME, "<your-service-name>",
                  // Replace <your-host-name> with your hostname. 
              	ResourceAttributes.HOST_NAME, "<your-host-name>"
              )
          )
      );
      
      SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
          .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional. Display the trace data in logs or the command line. Comment this line if you do not need it. 
          // Replace <gRPC-endpoint> with the endpoint that you have obtained as instructed in the "Before you begin" section of this topic, and replace <gRPC-token> with the authentication token. 
          .addSpanProcessor(BatchSpanProcessor.builder(
              OtlpGrpcSpanExporter.builder()
                   .setEndpoint("<gRPC-endpoint>") // Example: http://tracing-analysis-dc-hz.aliyuncs.com:8090
                   .addHeader("Authentication", "<gRPC-token>") // Example: xxxx@xxxx_xxxx@xxxx
                   .build()).build()
          )
          .setResource(otelResource)
          .build();
      
      OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
          .setTracerProvider(sdkTracerProvider)
          .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
          .buildAndRegisterGlobal();
      
      // Obtain the tracer that is used to create a span. 
      tracer = openTelemetry.getTracer("android-tracer", "1.0.0");
      /**
       Visit the following link to view the complete code:
       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>", // Replace <your-service-name> with your application name. 
                  ResourceAttributes.HOST_NAME, "<your-host-name>"    // Replace <your-host-name> with your hostname. 
              )
          )
      )
      
      /* Report trace data over gRPC. */
      val sdkTracerProvider = SdkTracerProvider.builder()
          .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional. Display the trace data in logs or the command line. Comment this line if you do not need it. 
      	// Replace <gRPC-endpoint> with the endpoint that you have obtained as instructed in the "Before you begin" section of this topic, and replace <gRPC-token> with the authentication token. 
          .addSpanProcessor(
              BatchSpanProcessor.builder(
                  OtlpGrpcSpanExporter.builder()
                      .setEndpoint("<gRPC-endpoint>") // Example: http://tracing-analysis-dc-hz.aliyuncs.com:8090
                      .addHeader("Authentication", "<gRPC-token>") // Example: xxxx@xxxx_xxxx@xxxx
                      .build()
              ).build()
          )
          .setResource(otelResource)
          .build()
      
      val openTelemetry: OpenTelemetry = OpenTelemetrySdk.builder()
          .setTracerProvider(sdkTracerProvider)
          .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
          .buildAndRegisterGlobal()
      
      // Obtain the tracer that is used to create a span. 
      tracer = openTelemetry.getTracer("android-tracer", "1.0.0")
    • Method 2: Report trace data over HTTP

      /**
       Visit the following link to view the complete code:
       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(
                  // Replace <your-service-name> with your application name. 
                  ResourceAttributes.SERVICE_NAME, "<your-service-name>",
                  // Replace <your-host-name> with your hostname. 
                  ResourceAttributes.HOST_NAME, "<your-host-name>"
              )
          )
      );
      
      SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
          .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional. Display the trace data in logs or the command line. Comment this line if you do not need it.
          // Replace <HTTP-endpoint> with the endpoint that you have obtained as instructed in the "Before you begin" section of this topic. 
          .addSpanProcessor(BatchSpanProcessor.builder(
              OtlpHttpSpanExporter.builder()
                   .setEndpoint("<HTTP-endpoint>") // Example: 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();
      
      // Obtain the tracer that is used to create a span. 
      tracer = openTelemetry.getTracer("android-tracer", "1.0.0");
      /**
       Visit the following link to view the complete code:
       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>", // Replace <your-service-name> with your application name. 
                  ResourceAttributes.HOST_NAME, "<your-host-name>"    // Replace <your-host-name> with your hostname. 
              )
          )
      )
      
      /* Report trace data over HTTP. */
      val sdkTracerProvider = SdkTracerProvider.builder()
          .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional. Display the trace data in logs or the command line. Comment this line if you do not need it. 
      	// Replace <HTTP-endpoint> with the endpoint that you have obtained as instructed in the "Before you begin" section of this topic. 
          .addSpanProcessor(BatchSpanProcessor.builder(
              OtlpHttpSpanExporter.builder()
                  .setEndpoint("<HTTP-endpoint>") // Example: 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()
      
      // Obtain the tracer that is used to create a span. 
      tracer = openTelemetry.getTracer("android-tracer", "1.0.0")
  2. Initialize OpenTelemetry during the application initialization.

    Call the OpenTelemetryUtil.init() method in the onCreate method of the MainActivity class.

    /**
     Visit the following link to view the complete code:
     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);
            // Add the following line to initialize OpenTelemetry. 
            OpenTelemetryUtil.init();
            ...
        }
        ...
    }
    /**
     Visit the following link to view the complete code:
     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)
            // Add the following line to initialize OpenTelemetry. 
            OpenTelemetryUtil.init()
    
                ...
        }
    }

Step 3: Create a span to track trace data

  1. Create a span.

    In the method of monitoring button tap events in the FirstFragment file, create a span named First Fragment Button onClick.

    /**
     Visit the following link to view the complete code:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java
    */
    
    public void onClick(View view) {
        // Obtain the tracer.
        Tracer tracer = OpenTelemetryUtil.getTracer();
    	// Create a span.
        Span span = tracer.spanBuilder("First Fragment Button onClick").startSpan();
    	try (Scope scope = span.makeCurrent()) {
            // Obtain the trace ID.
            System.out.println(span.getSpanContext().getTraceId());
            ...
        } finally {
            span.end();
        }
    }
    /**
     Visit the following link to view the complete code:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt
    */
    
    binding.buttonFirst.setOnClickListener {
        // Obtain the tracer.
        val tracer: Tracer = OpenTelemetryUtil.getTracer()!!
        // Create a span.
        val span = tracer.spanBuilder("First Fragment Button onClick").startSpan()
        try {
            span.makeCurrent().use { scope ->
                // Obtain the trace ID.
                println(span.spanContext.traceId)
                // Obtain the span ID.
                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. Configure attributes and an event for the span.

    /**
     Visit the following link to view the complete code:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java
    */
    
    // Configure attributes.
    span.setAttribute("key", "value");
    
    Attributes eventAttributes = Attributes.of(
        AttributeKey.stringKey("key"), "value",
        AttributeKey.longKey("result"), 0L);
    // Add an event.
    span.addEvent("onClick", eventAttributes);
    /**
     Visit the following link to view the complete code:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt
    */
    
    // Configure attributes.
    span.setAttribute("key", "value")
    val eventAttributes =
        Attributes.of(
            AttributeKey.stringKey("key"), "value",
            AttributeKey.longKey("result"), 0L
        )
    
    // Add an event.
    span.addEvent("onClick", eventAttributes)
  3. Configure the status of the span.

    /**
     Visit the following link to view the complete code:
     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) {
        // Configure the status of the span.
        span.setStatus(StatusCode.ERROR, "Something wrong in onClick");
        throw t;
    } finally {
        span.end(); 
    }
    /**
     Visit the following link to view the complete code:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt
    */
    
    ...
    try {
        ...
    } catch (t: Throwable) {
        // Configure the status of the span.
        span.setStatus(StatusCode.ERROR, "Something wrong in onClick")
        throw t
    } finally {
        span.end()
    }
  4. Create a nested span.

    /**
     Visit the following link to view the complete code:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java
    */
    
    public void parentSpan() {
        // Obtain the tracer.
        Tracer tracer = OpenTelemetryUtil.getTracer();
        // Create a span.
        Span span = tracer.spanBuilder("Parent Span").startSpan();
        try (Scope scope = span.makeCurrent()) {
            // Obtain the trace ID.
            System.out.println(span.getSpanContext().getTraceId());
            // Obtain the span ID.
            System.out.println(span.getSpanContext().getSpanId());
            childSpan();
        } finally {
            span.end();
        }
    }
    
    public void childSpan() {
        // Obtain the tracer.
        Tracer tracer = OpenTelemetryUtil.getTracer();
        // Create a span.
        Span span = tracer.spanBuilder("Child Span").startSpan();
        try (Scope scope = span.makeCurrent()) {
            // Obtain the trace ID.
            System.out.println(span.getSpanContext().getTraceId());
            // Obtain the span ID.
            System.out.println(span.getSpanContext().getSpanId());
        } finally {
            span.end();
        }
    }
    /**
     Visit the following link to view the complete code:
     https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt
    */
    
    // Create a nested span.
    fun parentSpan() {
        // Obtain the tracer.
        val tracer: Tracer = OpenTelemetryUtil.getTracer()!!
        // Create a span.
        val span = tracer.spanBuilder("Parent Span").startSpan()
        try {
            span.makeCurrent().use { scope ->
                // Obtain the trace ID.
                println(span.spanContext.traceId)
                // Obtain the span ID.
                println(span.spanContext.spanId)
                childSpan()
            }
        } finally {
            span.end()
        }
    }
    
    // Create a nested span.
    fun childSpan() {
        // Obtain the tracer.
        val tracer: Tracer = OpenTelemetryUtil.getTracer()!!
        // Create a span.
        val span = tracer.spanBuilder("Child Span").startSpan()
        try {
            span.makeCurrent().use { scope ->
                // Obtain the trace ID.
                println(span.spanContext.traceId)
                // Obtain the span ID.
                println(span.spanContext.spanId)
            }
        } finally {
            span.end()
        }
    }

Step 4: Run the project to view the reported trace data

  1. Run the project and simulate a button tap on the application page.image..png

    You can view the logs in Logcat, including the span information that is exported by using LoggingSpanExporter.

    image..png

  2. Log on to the ARMS console. In the left-side navigation pane, choose Application Monitoring > Application List. On the Application List page, click the name of the application. On the page that appears, view the trace data.

    Note

    If the Java图标 icon is displayed in the Language column, the application is connected to Application Monitoring. If a hyphen (-) is displayed, the application is connected to Managed Service for OpenTelemetry.

    image..png

Step 5: Connect the client application and server application

  1. Change the format to pass trace data in the HTTP request header.

    • Different protocols use different HTTP request headers to pass the trace context. For example, OpenTelemtry uses the W3C Trace Context format by default and supports other formats, and Zipkin uses the B3 or B3 Multi format. For more information, see Specify the format to pass trace data.

    • Set the format to pass trace data for the client application based on the protocol used by the server application. This way, the Android client application and server application can be connected.

      • If the server application uses the W3C Trace Context format of OpenTelemetry, you do not need to specify the textPropagators parameter for the client application.

      • If the server application uses the B3 or B3 Multi format of Zipkin, set the textPropagators parameter to B3Propagator for the client application.

        // Specify the B3 format to pass trace data. 
        OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
                .setTracerProvider(sdkTracerProvider)
                .setPropagators(ContextPropagators.create(TextMapPropagator.composite(
                        B3Propagator.injectingMultiHeaders(),
                        B3Propagator.injectingSingleHeader())))
                .buildAndRegisterGlobal();
      • If the server application uses the Jaeger protocol, you must set the textPropagators parameter to JaegerPropagator for the client application.

        // Specify the Jaeger format to pass trace data. 
        OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
                .setTracerProvider(sdkTracerProvider)
                .setPropagators(ContextPropagators.create(TextMapPropagator.composite(
                        JaegerPropagator.getInstance())))
                .buildAndRegisterGlobal();
      • You can also specify multiple formats to pass trace data.

        // Specify the W3C Trace Context, B3, and Jaeger formats to pass trace data. 
        // Specify the Jaeger format to pass trace data. 
        OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
                .setTracerProvider(sdkTracerProvider)
                .setPropagators(ContextPropagators.create(TextMapPropagator.composite(
                        W3CTraceContextPropagator.getInstance(),
                        B3Propagator.injectingMultiHeaders(),
                        B3Propagator.injectingSingleHeader()
                        JaegerPropagator.getInstance())))
                .buildAndRegisterGlobal();
  2. Import OkHttp3 and opentelemetry-okhttp.

    opentelemetry-okhttp-3.0 is an automatic instrumentation plug-in provided by OpenTelemetry for OkHttp frameworks. It automatically intercepts all network requests that are sent by using the OkHttp3 framework and creates traces.

    • Add the following dependencies to the build.gradle file:

      dependencies {
          ...
          implementation 'io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0:2.3.0-alpha'
          implementation 'com.squareup.okhttp3:okhttp:4.12.0'
      }
    • Create the 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. Use OkHttp3 to send a network request to access the server application.

    private void callHttpService() throws IOException {
        Tracer tracer = OpenTelemetryUtil.getTracer();
        // Create a 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()) {
            // Use OkHttp to execute the network request.
            OkHttpConfiguration configuration = new OkHttpConfiguration();
            Call.Factory tracedClient = configuration.createTracedClient(GlobalOpenTelemetry.get());
    
            Request request = new Request.Builder().url("${Server address}").get().build();
    
            Call call = tracedClient.newCall(request);
            try (Response response = call.execute()) {
                // Process the response.
                String responseBody = response.body().string();
                System.out.println(responseBody);
            } catch (IOException e) {
                // Handle errors.
                e.printStackTrace();
            }
        }  finally {
            span.end();
        }
    }

    View the complete code for asynchronously calling the callHttpService method in the onClick event

    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) {
                    // Obtain the tracer.
                    Tracer tracer = OpenTelemetryUtil.getTracer();
                    // Create a span.
                    Span span = tracer.spanBuilder("First Fragment Button onClick").startSpan();
                    try (Scope scope = span.makeCurrent()) {
                        // Obtain the trace ID.
                        System.out.println(span.getSpanContext().getTraceId());
                        // Obtain the span ID.
                        System.out.println(span.getSpanContext().getSpanId());
                        // Configure attributes.
                        span.setAttribute("key", "value");
    
                        Attributes eventAttributes = Attributes.of(
                                AttributeKey.stringKey("key"), "value",
                                AttributeKey.longKey("result"), 0L);
    
                        // Add an event.
                        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());
    
            // Obtain the tracer.
            Tracer tracer = OpenTelemetryUtil.getTracer();
            // Create a span.
            Span span = tracer.spanBuilder("Parent Span").startSpan();
            try (Scope scope = span.makeCurrent()) {
                // Obtain the trace ID.
                System.out.println(span.getSpanContext().getTraceId());
                // Obtain the span ID.
                System.out.println(span.getSpanContext().getSpanId());
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        // Execute the network request.
                        try {
                            callHttpService();
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                        // After the execution is complete, use the handler to switch back to the main thread to process the result.
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                // Update the user interface (UI) and perform other operations.
                                childSpan();
                            }
                        });
                    }
                });
    
                executorService.shutdown();
            } finally {
                span.end();
            }
        }
    
        public void childSpan() {
            // Obtain the tracer.
            Tracer tracer = OpenTelemetryUtil.getTracer();
            // Create a span.
            Span span = tracer.spanBuilder("Child Span").startSpan();
            try (Scope scope = span.makeCurrent()) {
                // Obtain the trace ID.
                System.out.println(span.getSpanContext().getTraceId());
                // Obtain the span ID.
                System.out.println(span.getSpanContext().getSpanId());
            } finally {
                span.end();
            }
        }
    
        private void callHttpService() throws IOException {
            Tracer tracer = OpenTelemetryUtil.getTracer();
            // Create a 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()) {
                // Use OkHttp to execute the network request.
                OkHttpConfiguration configuration = new OkHttpConfiguration();
                Call.Factory tracedClient = configuration.createTracedClient(GlobalOpenTelemetry.get());
    
                Request request = new Request.Builder().url("${Server address}").get().build();
                Call call = tracedClient.newCall(request);
                try (Response response = call.execute()) {
                    // Process the response.
                    String responseBody = response.body().string();
                    System.out.println(responseBody);
                } catch (IOException e) {
                    // Handle errors.
                    e.printStackTrace();
                }
            }  finally {
                span.end();
            }
        }
    
    }
  4. View the trace between the client application and server application on the Trace Explorer page.

    The following figure shows an example. In this example, AsyncRequestZipkinServer is an Android application and zipkin-demo-server is a server application.

    image