Reporting Java Application Data Using OpenTelemetry
Huawei Cloud APM is compatible with OpenTelemetry and can directly receive the trace data reported using the OpenTelemetry SDK or Agent. This section describes how to use OpenTelemetry to connect a Java application to APM and report trace data.
Demo
Use Spring Boot to implement a simple dice roller application.
- Compile service code and initialize a Spring Boot project.
Create a RollDice.java file:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.Optional; import java.util.concurrent.ThreadLocalRandom; @RestController public class RollDice { @GetMapping("/rolldice") public String rollDiceAndSave(@RequestParam("player") Optional<String> player) { int result = 0; //Roll the dice. try { Thread.sleep(100); result = ThreadLocalRandom.current().nextInt(1, 7); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } saveResult(player.orElse("Anonymous player"), result); return Integer.toString(result); } private void saveResult(String player, int dicePoint) { //Simulate the time required for performing operations on the database. try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }Content of application.properties:
server.port=8080
- Run the startup command:
java -jar otel-demo-0.0.1-SNAPSHOT.jar & curl http://localhost:8080/rolldice?player=Alex
Using Java Agent for Auto Tracking
The OpenTelemetry Java Agent supports non-intrusive tracking for some common libraries/frameworks. For details, see the Libraries/Frameworks supported by auto tracking.
- Obtain the Agent.
- Add Agent startup parameters and restart the application. Command:
java -javaagent: Agent installation path \ -Dotel.exporter.otlp.protocol=grpc \ -Dotel.exporter.otlp.traces.endpoint= Reporting address \ -Dotel.exporter.otlp.headers=Authentication= Authentication information \ -Dotel.service.name= Application name.Component name.Environment name \ -Dotel.metrics.exporter=none \ -Dotel.logs.exporter=none \ -jar <yourApp>.jar & curl http://localhost:8080/rolldice?player=Alex
- Log in to the APM console.
- Click
on the left and choose Management & Governance > Application Performance Management. - In the navigation pane, choose Link Trace > Metrics.
- In the navigation tree on the left, click an environment, and then click Overview. On the displayed page, view the monitoring data of the instance. For details, see Metrics.
Using Java SDK for Manual Tracking
If auto tracking does not meet service requirements or you need to create custom tracking logic, use the OpenTelemetry SDK for manual tracking.
- Add Maven dependencies.
Add OpenTelemetry dependencies to the pom.xml file.
<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.30.0-alpha</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-bom</artifactId> <version>1.30.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> - Initialize the OpenTelemetry SDK.
- Write a tool class to configure and create an OpenTelemetry instance.
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 the OpenTelemetry tracer. Resource resource = Resource.getDefault() .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "Application name.Component name.Environment name", // For Application name, use the name of the OpenTelemetry application created in APM. For Component name and Environment name, enter any value. ResourceAttributes.SERVICE_VERSION, "1.0.0", // Version number. ResourceAttributes.DEPLOYMENT_ENVIRONMENT, "test", // Deployment environment. Enter any value. ResourceAttributes.HOST_NAME, "127.0.0.1" // Replace ${host-name} with your host name or enter any value. ))); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(BatchSpanProcessor.builder( OtlpGrpcSpanExporter.builder().setEndpoint("Access address") // Access address. .addHeader("Authentication", "Application authentication information") // Application authentication information. .build()).build()) .setResource(resource) .build(); OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal(); tracer = openTelemetry.getTracer("OpenTelemetry Tracer", "1.0.0"); } private static Tracer tracer; public static Tracer getTracer() { return tracer; } } - Create spans.
import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.Optional; import java.util.concurrent.ThreadLocalRandom; @RestController public class RollDice { @GetMapping("/rolldice") public String rollDiceAndSave(@RequestParam("player") Optional<String> player) { int result = 0; Span span = OpenTelemetrySupport.getTracer().spanBuilder("rolldice").setSpanKind(SpanKind.SERVER).startSpan(); try (Scope scope = span.makeCurrent()) { span.setStatus(StatusCode.OK); span.setAttribute("dice.player", player.orElse("Anonymous player")); span.addEvent("ev", Attributes.builder().put("event1", "value1").build()); // event1 and value1 will be displayed on the trace span details page. span.setAttribute("http.target", "rolldice"); // This field is mandatory when the service serves as the server. span.setAttribute("http.method", "GET"); // This field is mandatory when the service serves as the server. span.setAttribute("http.route", "{path }/**"); // Optional. span.setAttribute("http.status_code", 200); // Optional. Attributes attributes = Attributes.builder() .put("exception.type", "NullPoint") .put("exception.message", "I am exception message") .build(); // (Optional) This field is displayed on the trace span details page. span.addEvent("exception", attributes); //Roll the dice. try { Thread.sleep(100); result = ThreadLocalRandom.current().nextInt(1, 7); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } saveResult(player.orElse("Anonymous player"), result, span); } catch (Throwable t) { span.setStatus(StatusCode.ERROR, "handle parent span error"); } finally { span.end(); } return Integer.toString(result); } private void saveResult(String player, int dicePoint, Span parentSpan) { Span span = OpenTelemetrySupport.getTracer() .spanBuilder("saveResult") .setSpanKind(SpanKind.CLIENT) // CLIENT indicates that an external service (such as a database) is called. .setParent(Context.current().with(parentSpan)) // Parent span. This helps establish the parent-child relationship and form a complete distributed tracing tree. .startSpan(); try (Scope scope = span.makeCurrent()) { span.setAttribute("db.system", "mysql"); // Database type, which is MySQL. span.setAttribute("db.statement", "INSERT INTO dice_roll (player_name, dice_point) VALUES (" + player + ", " + dicePoint + ")"); // SQL statement. span.setAttribute("db.connection_string", "127.0.0.1:3306:mysql"); // Connected database. //Simulate the time required for performing operations on the database. try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } catch (Throwable t) { span.recordException(t); span.setStatus(StatusCode.ERROR, "handle child span error"); } finally { span.end(); } } }
- Write a tool class to configure and create an OpenTelemetry instance.
- Log in to the APM console.
- Click
on the left and choose Management & Governance > Application Performance Management. - In the navigation pane, choose Link Trace > Metrics.
- In the navigation tree on the left, click an environment, and then click Overview. On the displayed page, view the monitoring data of the instance. For details, see Metrics.
What is your overall rating for this page?
Thank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
For any further questions, feel free to contact us through the chatbot.
Chatbot