All Products
Search
Document Center

Application Real-Time Monitoring Service:Use OpenTelemetry to submit the trace data of Java applications

Last Updated:Jul 26, 2023

Before you can view the trace data of your application in the Tracing Analysis console, you must submit the trace data to Tracing Analysis. This topic describes how to instrument an application and submit trace data.

Prerequisites

To obtain an endpoint of OpenTelemetry, perform the following steps:
  1. Log on to the Tracing Analysis console.
  2. In the left-side navigation pane, click Cluster Configurations. Then, 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. In the Client section, click OpenTelemetry.
    Obtain an endpoint of OpenTelemetry in the Related Information column of the table in the lower part. Endpoint of OpenTelemetry
    Note If your application is deployed in an Alibaba Cloud production environment, use an access point of Alibaba Cloud VPC. Otherwise, use a public endpoint.

Sample code

Download the sample code from java-opentelemetry-demo.

Method 1: Use the OpenTelemetry Java Agent to perform automatic instrumentation on an application

The OpenTelemetry Java Agent allows you to connect OpenTelemetry to Tracing Analysis in a non-intrusive manner and can be used to automatically upload trace data in dozens of Java frameworks. For more information about the frameworks, see Supported Libraries and Versions.

  1. Download the OpenTelemetry Java Agent.

  2. Modify the VM parameters in the Java startup configuration to submit trace data:

    -javaagent:/path/to/opentelemetry-javaagent.jar    // Replace the path with the URL that you use to download the OpenTelemetry Java Agent. 
    -Dotel.resource.attributes=service.name=<appName>     // Replace <appName> with an actual application name. 
    -Dotel.exporter.otlp.headers=Authentication=<token>
    -Dotel.exporter.otlp.endpoint=<endpoint>
    -Dotel.metrics.exporter=none
    • If you want to directly submit trace data, replace <token> with the token that you obtained in the "Connect to Tracing Analysis and authenticate clients" topic. Then, replace <endpoint> with the endpoint of the region to which you want to submit the trace data.

      Example:

      -javaagent:/Users/carpela/Downloads/opentelemetry-javaagent.jar
      -Dotel.resource.attributes=service.name=ot-java-agent-sample
      -Dotel.exporter.otlp.headers=Authentication=b590xxxxuqs@3a75d95xxxxx9b_b59xxxxguqs@53dxxxx2afe8301
      -Dotel.exporter.otlp.endpoint=http://tracing-analysis-dc-bj:8090
      -Dotel.metrics.exporter=none
    • If you want to use the OpenTelemetry Collector to forward trace data, remove -Dotel.exporter.otlp.headers=Authentication=<token> and replace <endpoint> with the URL of the service that is deployed on an on-premises machine.

Method 2: Use OpenTelemetry SDK for Java to manually instrument an application

The OpenTelemetry Java Agent is implemented based on OpenTelemetry SDK for Java. The SDK provides various custom features. If the instrumentation that is added by using the OpenTelemetry Java Agent no longer meets your business requirements or you want to add instrumentation based on your business requirements, perform the following steps:

  1. Add the following dependencies to the pom.xml file of a Maven project:

    <dependencies>
      <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-api</artifactId>
      </dependency>
      <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-sdk-trace</artifactId>
      </dependency>
      <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-exporter-otlp</artifactId>
      </dependency>
      <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-sdk</artifactId>
      </dependency>
      <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-semconv</artifactId>
        <version>1.23.0-alpha</version>
      </dependency>
    </dependencies>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.opentelemetry</groupId>
                <artifactId>opentelemetry-bom</artifactId>
                <version>1.23.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
  2. Obtain an OpenTelemetry tracer.

    • <logical-service-name> specifies the name of the service, and <host-name> specifies the hostname. Specify the values based on your business requirements.

    • If you want to directly submit trace data, replace <token> with the token that you obtained in the "Connect to Tracing Analysis and authenticate clients" topic. Then, replace <endpoint> with the endpoint of the region to which you want to submit the trace data.

    package com.alibaba.arms.brightroar.console.util;
    
    import io.opentelemetry.api.OpenTelemetry;
    import io.opentelemetry.api.common.Attributes;
    import io.opentelemetry.api.trace.Tracer;
    import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
    import io.opentelemetry.context.propagation.ContextPropagators;
    import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
    import io.opentelemetry.sdk.OpenTelemetrySdk;
    import io.opentelemetry.sdk.resources.Resource;
    import io.opentelemetry.sdk.trace.SdkTracerProvider;
    import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
    import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
    
    public class OpenTelemetrySupport {
    
        static {
            // Obtain an OpenTelemetry tracer.
            Resource resource = Resource.getDefault()
                    .merge(Resource.create(Attributes.of(
                            ResourceAttributes.SERVICE_NAME, "<logical-service-name>",
                            ResourceAttributes.HOST_NAME, "<host-name>"
                    )));
    
            SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
                    .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder()
                            .setEndpoint("<endpoint>")
                            .addHeader("Authentication", "<token>")
                            .build()).build())
                    .setResource(resource)
                    .build();
    
            OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
                    .setTracerProvider(sdkTracerProvider)
                    .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
                    .buildAndRegisterGlobal();
    
            tracer = openTelemetry.getTracer("<your_tracer_name>", "1.0.0");
        }
    
        private static Tracer tracer;
    
        public static Tracer getTracer() {
            return tracer;
        }
    
    }
  3. Modify the controller code and service code.

    • Sample controller code:

      package com.alibaba.arms.brightroar.console.controller;
      
      import com.alibaba.arms.brightroar.console.service.UserService;
      import com.alibaba.arms.brightroar.console.util.OpenTelemetrySupport;
      import io.opentelemetry.api.GlobalOpenTelemetry;
      import io.opentelemetry.api.OpenTelemetry;
      import io.opentelemetry.api.trace.Span;
      import io.opentelemetry.api.trace.StatusCode;
      import io.opentelemetry.api.trace.Tracer;
      import io.opentelemetry.context.Context;
      import io.opentelemetry.context.Scope;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      
      /**
       * References:
       * 1. https://opentelemetry.io/docs/java/manual_instrumentation/
       */
      @RestController
      @RequestMapping("/user")
      public class UserController {
      
          @Autowired
          private UserService userService;
      
          private ExecutorService es = Executors.newFixedThreadPool(5);
      
          private void biz() {
              Tracer tracer = OpenTelemetrySupport.getTracer();
              Span span = tracer.spanBuilder("biz (manual)")
                      .setParent(Context.current().with(Span.current())) // Optional. The system automatically configures the settings.
                      .startSpan();
      
              try (Scope scope = span.makeCurrent()) {
                  span.setAttribute("biz-id", "111");
      
                  es.submit(new Runnable() {
                      @Override
                      public void run() {
                          Span asyncSpan = tracer.spanBuilder("async")
                                  .setParent(Context.current().with(span))
                                  .startSpan();
                          try {
                              Thread.sleep(1000L); // some async jobs
                          } catch (Throwable e) {
                          }
                          asyncSpan.end();
                      }
                  });
      
                  Thread.sleep(1000); // fake biz logic
                  System.out.println("biz done");
                  OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();
                  openTelemetry.getPropagators();
              } catch (Throwable t) {
                  span.setStatus(StatusCode.ERROR, "handle biz error");
              } finally {
                  span.end();
              }
          }
      
          private void child(String userType) {
              Span span = OpenTelemetrySupport.getTracer().spanBuilder("child span").startSpan();
              try (Scope scope = span.makeCurrent()) {
                  span.setAttribute("user.type", userType);
                  System.out.println(userType);
                  biz();
              } catch (Throwable t) {
                  span.setStatus(StatusCode.ERROR, "handle child span error");
              } finally {
                  span.end();
              }
          }
      
          @RequestMapping("/async")
          public String async() {
              System.out.println("UserController.async -- " + Thread.currentThread().getId());
              Span span = OpenTelemetrySupport.getTracer().spanBuilder("parent span").startSpan();
              span.setAttribute("user.id", "123456");
              try (Scope scope = span.makeCurrent()) {
                  userService.async();
                  child("vip");
              } catch (Throwable t) {
                  span.setStatus(StatusCode.ERROR, "handle parent span error");
              } finally {
                  span.end();
              }
              return "async";
          }
      
      }
         
    • Sample service code:

      package com.alibaba.arms.brightroar.console.service;
      
      import org.springframework.scheduling.annotation.Async;
      import org.springframework.stereotype.Service;
      
      @Service
      public class UserService {
      
          @Async
          public void async() {
              System.out.println("UserService.async -- " + Thread.currentThread().getId());
              System.out.println("my name is async");
              System.out.println("UserService.async -- ");
          }
      }
  4. Start the application.
    Log on to the ARMS console. In the left-side navigation pane, choose Application Monitoring > Applications. On the Applications page, click the name of the application. On the page that appears, view the trace data.
    Note If the Java icon 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.

Method 3: Use the OpenTelemetry Java Agent and OpenTelemetry SDK for Java to instrument applications

You can use the OpenTelemetry Java Agent to perform automatic instrumentation and use OpenTelemetry SDK for Java to add instrumentation based on your business requirements.

  1. Download the OpenTelemetry Java Agent.

  2. Add the following dependencies to the pom.xml file of the Maven project in addition to the dependencies of Method 2:

    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-extension-annotations</artifactId>
    </dependency>
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
        <version>1.23.0-alpha</version>
    </dependency>
    Note

    In the preceding code, the opentelemetry-sdk-extension-autoconfigure dependency is used to automatically configure OpenTelemetry SDK for Java and transfer the settings of the OpenTelemetry Java Agent to the SDK.

    View the dependencies in the pom.xml file of the Maven project

    <dependencies>
        <dependency>
            <groupId>com.alibaba.arms</groupId>
            <artifactId>brightroar-dao</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-api</artifactId>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-sdk-trace</artifactId>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-extension-annotations</artifactId>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-exporter-otlp</artifactId>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-sdk</artifactId>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-semconv</artifactId>
            <version>1.23.0-alpha</version>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
            <version>1.23.0-alpha</version>
        </dependency>
    </dependencies>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.opentelemetry</groupId>
                <artifactId>opentelemetry-bom</artifactId>
                <version>1.23.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
  3. Obtain an OpenTelemetry tracer.

    If you use the OpenTelemetry Java Agent and OpenTelemetry SDK for Java to instrument applications, you do not need to use the OpenTelemetrySupport class used in Method 2 to obtain an OpenTelemetry tracer.

    OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();
    Tracer tracer = openTelemetry.getTracer("instrumentation-library-name", "1.0.0");
  4. Modify the controller code and service code.

    • We recommend that you use Method 1 and Method 2 in the following sample controller code:

      package com.alibaba.arms.brightroar.console.controller;
      
      import com.alibaba.arms.brightroar.console.service.UserService;
      import io.opentelemetry.api.GlobalOpenTelemetry;
      import io.opentelemetry.api.OpenTelemetry;
      import io.opentelemetry.api.trace.Span;
      import io.opentelemetry.api.trace.StatusCode;
      import io.opentelemetry.api.trace.Tracer;
      import io.opentelemetry.context.Context;
      import io.opentelemetry.context.Scope;
      import io.opentelemetry.extension.annotations.SpanAttribute;
      import io.opentelemetry.extension.annotations.WithSpan;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      
      /**
      * References:
      * 1. https://opentelemetry.io/docs/java/manual_instrumentation/
      */
      @RestController
          @RequestMapping("/user")
          public class UserController {
      
              @Autowired
              private UserService userService;
      
              private ExecutorService es = Executors.newFixedThreadPool(5);
      
              // Method 3: Use a tracer to manually instrument an application.
              private void biz() {
                  Tracer tracer = GlobalOpenTelemetry.get().getTracer("tracer");
                  Span span = tracer.spanBuilder("biz (manual)")
                      .setParent(Context.current().with(Span.current())) // Optional. The system automatically configures the settings.
                      .startSpan();
      
                  try (Scope scope = span.makeCurrent()) {
                      span.setAttribute("biz-id", "111");
      
                      es.submit(new Runnable() {
                          @Override
                          public void run() {
                              Span asyncSpan = tracer.spanBuilder("async")
                                  .setParent(Context.current().with(span))
                                  .startSpan();
                              try {
                                  Thread.sleep(1000L); // some async jobs
                              } catch (Throwable e) {
                              }
                              asyncSpan.end();
                          }
                      });
      
                      Thread.sleep(1000); // fake biz logic
                      System.out.println("biz done");
                      OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();
                      openTelemetry.getPropagators();
                  } catch (Throwable t) {
                      span.setStatus(StatusCode.ERROR, "handle biz error");
                  } finally {
                      span.end();
                  }
              }
      
              // Method 2: Instrument an application based on tags.
              @WithSpan
              private void child(@SpanAttribute("user.type") String userType) {
                  System.out.println(userType);
                  biz();
              }
      
              // Method 1: Perform automatic instrumentation on an application. Call an API operation to add information.
              @RequestMapping("/async")
              public String async() {
                  System.out.println("UserController.async -- " + Thread.currentThread().getId());
                  Span span = Span.current();
                  span.setAttribute("user.id", "123456");
                  userService.async();
                  child("vip");
                  return "async";
              }
      
          }
                                      
    • Sample service code:

      package com.alibaba.arms.brightroar.console.service;
      
      import org.springframework.scheduling.annotation.Async;
      import org.springframework.stereotype.Service;
      
      @Service
      public class UserService {
      
          @Async
          public void async() {
              System.out.println("UserService.async -- " + Thread.currentThread().getId());
              System.out.println("my name is async");
              System.out.println("UserService.async -- ");
          }
      }
  5. Modify the VM parameters in the Java startup configuration to submit trace data:

    -javaagent:/path/to/opentelemetry-javaagent.jar    // Replace the path with the URL that you use to download the OpenTelemetry Java Agent. 
    -Dotel.resource.attributes=service.name=<appName>     // Replace <appName> with an actual application name. 
    -Dotel.exporter.otlp.headers=Authentication=<token>
    -Dotel.exporter.otlp.endpoint=<endpoint>
    • If you want to directly submit trace data, replace <token> with the token that you obtained in the "Connect to Tracing Analysis and authenticate clients" topic. Then, replace <endpoint> with the endpoint of the region to which you want to submit the trace data.

      Example:

      -javaagent:/Users/carpela/Downloads/opentelemetry-javaagent.jar
      -Dotel.resource.attributes=service.name=ot-java-agent-sample
      -Dotel.exporter.otlp.headers=Authentication=b590xxxxuqs@3a75d95xxxxx9b_b59xxxxguqs@53dxxxx2afe8301
      -Dotel.exporter.otlp.endpoint=http://tracing-analysis-dc-bj:8090
    • If you want to use the OpenTelemetry Collector to forward trace data, remove -Dotel.exporter.otlp.headers=Authentication=<token> and replace <endpoint> with the URL of the service that is deployed on an on-premises machine.

  6. Start the application.
    Log on to the ARMS console. In the left-side navigation pane, choose Application Monitoring > Applications. On the Applications page, click the name of the application. On the page that appears, view the trace data.
    Note If the Java icon 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.