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.
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.
Download the OpenTelemetry Java agent.
Modify the JVM parameters in the Java startup configuration to report trace data.
If you want to directly report trace data, replace
<token>
and<endpoint>
with the information that you obtained in the prerequisites.NoteThe HTTP method does not require setting a token. You need to set only the endpoints.
HTTP
java -javaagent:/path/to/opentelemetry-javaagent.jar //Change the path to the address for downloading the file. -Dotel.exporter.otlp.protocol=http/protobuf \ -Dotel.exporter.otlp.traces.endpoint=<traces.endpoint> \ //Specify the trace endpoint that you obtained in the prerequisites. -Dotel.exporter.otlp.metrics.endpoint=<metrics.endpoint> \ //Specify the metric endpoint that you obtained in the prerequisites. -Dotel.logs.exporter=none \ -jar /path/to/your/app.jar
Example:
java -javaagent:/path/to/opentelemetry-javaagent.jar \ -Dotel.exporter.otlp.protocol=http/protobuf \ -Dotel.exporter.otlp.traces.endpoint=http://tracing-analysis-dc-hz-internal.aliyuncs.com/adapt_ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe****/api/otlp/traces \ -Dotel.exporter.otlp.metrics.endpoint=http://tracing-analysis-dc-hz-internal.aliyuncs.com/adapt_ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe****/api/otlp/metrics \ -Dotel.logs.exporter=none \ -jar /path/to/your/app.jar
gRPC
java -javaagent:/path/to/opentelemetry-javaagent.jar \ //Change the path to the address for downloading the file. -Dotel.exporter.otlp.protocol=grpc \ -Dotel.exporter.otlp.headers=Authentication=<token> \ //Specify the token that you obtained in the prerequisites. -Dotel.exporter.otlp.endpoint=<endpoint> \ //Specify the endpoint that you obtained in the prerequisites. -Dotel.logs.exporter=none \ -jar /path/to/your/app.jar
Example:
java -javaagent:/path/to/opentelemetry-javaagent.jar \ -Dotel.exporter.otlp.protocol=grpc \ -Dotel.exporter.otlp.headers=Authentication=ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe**** \ -Dotel.exporter.otlp.endpoint=http://tracing-analysis-dc-hz-internal.aliyuncs.com:8090 \ -Dotel.logs.exporter=none \ -jar /path/to/your/app.jar
NoteIf 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:
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>
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; } }
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 -- "); } }
Start the application.
On the Applications page of the Managed Service for OpenTelemetry console, click the name of the application. On the page that appears, view the trace data.
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.
Download the OpenTelemetry Java agent.
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>
NoteIn 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.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");
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 -- "); } }
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.
Start the application.
On the Applications page of the Managed Service for OpenTelemetry console, click the name of the application. On the page that appears, view the trace data.