All Products
Search
Document Center

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

Last Updated:Sep 03, 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 use an agent or OpenTelemetry SDK for Java to automatically or manually instrument a Java application and report the trace data of the Java application.

Background information

The following table describes the Java frameworks that the OpenTelemetry Java agent can automatically instrument. For more information, see Supported libraries, frameworks, application servers, and JVMs.

Supported Java frameworks

Framework

Framework version

Akka Actors

2.5 or later

Akka HTTP

10.0 or later

Apache Axis2

1.6 or later

Apache Camel

2.20 or later (excluding 3.x)

Apache DBCP

2.0 or later

Apache CXF JAX-RS

3.2 or later

Apache CXF JAX-WS

3.0 or later

Apache Dubbo

2.7 or later

Apache HttpAsyncClient

4.1 or later

Apache HttpClient

2.0 or later

Apache Kafka Producer/Consumer API

0.11 or later

Apache Kafka Streams API

0.11 or later

Apache MyFaces

1.2 or later (excluding 3.x)

Apache Pulsar

2.8 or later

Apache RocketMQ gRPC/Protobuf-based Client

5.0 or later

Apache RocketMQ Remoting-based Client

4.8 or later

Apache Struts 2

2.3 or later

Apache Tapestry

5.4 or later

Apache Wicket

8.0 or later

Armeria

1.3 or later

AsyncHttpClient

1.9 or later

AWS Lambda

1.0 or later

AWS SDK

1.11.x and 2.2 or later

Azure Core

1.14 or later

Cassandra Driver

3.0 or later

Couchbase Client

2.0 or later and 3.1 or later

c3p0

0.9.2 or later

Dropwizard Metrics

4.0 or later (disabled by default)

Dropwizard Views

0.7 or later

Eclipse Grizzly

2.3 or later

Eclipse Jersey

2.0 or later (excluding 3.x)

Eclipse Jetty HTTP Client

9.2 or later (excluding 10 or later)

Eclipse Metro

2.2 or later

Eclipse Mojarra

1.2 or later (excluding 3.x)

Elasticsearch API Client

7.16 or later and 8.0 or later

Elasticsearch REST Client

5.0 or later

Elasticsearch Transport Client

5.0 or later

Finatra

2.9 or later

Geode Client

1.4 or later

Google HTTP Client

1.19 or later

Grails

3.0 or later

GraphQL Java

12.0 or later

gRPC

1.6 or later

Guava ListenableFuture

10.0 or later

GWT

2.0 or later

Hibernate

3.3 or later

Hibernate Reactive

1.0 or later

HikariCP

3.0 or later

HttpURLConnection

Java 8 or later

Hystrix

1.4 or later

Java Executors

Java 8 or later

Java Http Client

Java 11 or later

java.util.logging

Java 8 or later

Java Platform

Java 8 or later

JAX-RS

0.5 or later

JAX-RS Client

1.1 or later

JAX-WS

2.0 or later (excluding 3.x)

JBoss Log Manager

1.1 or later

JDBC

Java 8 or later

Jedis

1.4 or later

JMS

1.1 or later

Jodd Http

4.2 or later

JSP

2.3 or later

Kotlin Coroutines

1.0 or later

Ktor

1.0 or later

Kubernetes Client

7.0 or later

Lettuce

4.0 or later

Log4j 1

1.2 or later

Log4j 2

2.11 or later

Logback

1.0 or later

Micrometer

1.5 or later

MongoDB Driver

3.1 or later

Netty

3.8 or later

OkHttp

2.2 or later

Oracle UCP

11.2 or later

OSHI

5.3.1 or later

Play

2.4 or later

Play WS

1.0 or later

Quartz

2.0 or later

R2DBC

1.0 or later

RabbitMQ Client

2.7 or later

Ratpack

1.4 or later

Reactor

3.1 or later

Reactor Netty

0.9 or later

Rediscala

1.8 or later

Redisson

3.0 or later

RESTEasy

3.0 or later

Restlet

1.0 or later

RMI

Java 8 or later

RxJava

1.0 or later

Scala ForkJoinPool

2.8 or later

Servlet

2.2 or later

Spark Web Framework

2.3 or later

Spring Boot

N/A

Spring Batch

3.0 or later (excluding 5.0 or later)

Spring Cloud Gateway

2.0 or later

Spring Data

1.8 or later

Spring Integration

4.1 or later (excluding 6.0 or later)

Spring JMS

2.0 or later

Spring Kafka

2.7 or later

Spring RabbitMQ

1.0 or later

Spring Scheduling

3.1 or later

Spring RestTemplate

3.1 or later

Spring Web MVC

3.1 or later

Spring Web Services

2.0 or later

Spring WebFlux

5.3 or later

Spymemcached

2.12 or later

Tomcat JDBC Pool

8.5 or later

Twilio

6.6 or later (excluding 8.x)

Undertow

1.4 or later

Vaadin

14.2 or later

Vert.x Web

3.0 or later

Vert.x HttpClient

3.0 or later

Vert.x Kafka Client

3.6 or later

Vert.x RxJava2

3.5 or later

Vert.x SQL Client

4.0 or later

Vibur DBCP

11.0 or later

ZIO

2.0 or later

Sample code

Download the sample code from java-opentelemetry-demo.

Method 1: Use the OpenTelemetry Java agent to automatically instrument an application

The OpenTelemetry Java agent allows you to connect OpenTelemetry to Managed Service for OpenTelemetry in a non-intrusive manner. The OpenTelemetry Java agent can be used to automatically upload trace data in hundreds of Java frameworks. For more information about the supported Java frameworks, see Supported libraries, frameworks, application servers, and JVMs.

  1. Download the OpenTelemetry Java agent.

  2. Modify the JVM parameters in the Java startup configuration to report 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 report trace data, replace <token> with the token that you obtained in the prerequisites and <endpoint> with the endpoint of the region to which you want to report 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 custom 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.

    • In the following code, <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 report trace data, replace <token> with the token that you obtained in the prerequisites and <endpoint> with the endpoint of the region to which you want to report 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 image 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 custom 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>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 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";
              }
      
              // Method 2: Instrument an application based on tags.
              @WithSpan
              private void child(@SpanAttribute("user.type") String userType) {
                  System.out.println(userType);
                  biz();
              }
      
              // 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();
                  }
              }
      
          }
      
                                      
    • 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 JVM parameters in the Java startup configuration to report 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 report trace data, replace <token> with the token that you obtained in the prerequisites and <endpoint> with the endpoint of the region to which you want to report 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 image 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.