Skip to content

Latest commit

 

History

History
462 lines (351 loc) · 13.9 KB

README.adoc

File metadata and controls

462 lines (351 loc) · 13.9 KB

microprofile-opentracing: MicroProfile OpenTracing QuickStart

The microprofile-opentracing quickstart demonstrates the use of the MicroProfile OpenTracing specification in {productName}.

What is it?

MicroProfile OpenTracing allows users to track requests across service boundaries which is necessary in the microservices architecture. It is based on https://opentracing.io/. The MicroProfile OpenTracing provides a way to instrument services with the distributed tracing function, given an existing distributed tracing system in the environment (e.g. Jaeger or Zipkin).

Architecture

In this quickstart, we have a collection of CDI beans and REST endpoints that expose functionalities of the MicroProfile OpenTracing specification.

Solution

Creating the Maven Project

mvn archetype:generate \
    -DgroupId=org.wildfly.quickstarts \
    -DartifactId=microprofile-opentracing \
    -DinteractiveMode=false \
    -DarchetypeGroupId=org.apache.maven.archetypes \
    -DarchetypeArtifactId=maven-archetype-webapp
cd microprofile-opentracing

Open the project in your favourite IDE.

The first thing to do is to setup our dependencies. Add the following section to your pom.xml:

<dependencyManagement>
  <dependencies>
    <!-- importing the microprofile BOM adds MicroProfile specs -->
    <dependency>
        <groupId>org.wildfly.bom</groupId>
        <artifactId>wildfly-microprofile</artifactId>
        <version>${version.server.bom}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

where ${version.server.bom} is the version of your {productName}, in our case "{productVersion}".

Now we need to add the following dependencies:

<!-- Import the MicroProfile OpenTracing API, we use provided scope as the API is included in the server -->
<dependency>
  <groupId>org.eclipse.microprofile.opentracing</groupId>
  <artifactId>microprofile-opentracing-api</artifactId>
  <scope>provided</scope>
</dependency>
<!-- Import the CDI API, we use provided scope as the API is included in the server -->
<dependency>
  <groupId>jakarta.enterprise</groupId>
  <artifactId>jakarta.enterprise.cdi-api</artifactId>
  <scope>provided</scope>
</dependency>
<!-- Import the Jakarta REST API, we use provided scope as the API is included in the server -->
<dependency>
  <groupId>org.jboss.spec.javax.ws.rs</groupId>
  <artifactId>jboss-jaxrs-api_2.1_spec</artifactId>
  <scope>provided</scope>
</dependency>

All dependencies can have provided scope.

As we are going to be deploying this application to the {productName} server, let’s also add a maven plugin that will simplify the deployment operations (you can replace the generated build section):

<build>
  <!-- Set the name of the archive -->
  <finalName>${project.artifactId}</finalName>
  <plugins>
    <!-- Allows to use mvn wildfly:deploy -->
    <plugin>
      <groupId>org.wildfly.plugins</groupId>
      <artifactId>wildfly-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>

As this is a Jakarta REST application we need to also create an application class. Create org.wildfly.quickstarts.microprofile.opentracing.JaxRsApplication with the following content:

Note
The new file should be created in src/main/java/org/wildfly/quickstarts/microprofile/opentracing/JaxRsApplication.java.
package org.wildfly.quickstarts.microprofile.opentracing;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/")
public class JaxRsApplication extends Application {
}

Now we are ready to start working with MicroProfile OpenTracing.

Running the Jaeger service

To collect the traces from our application we will be using the Jaeger tracing system. To run the Jaeger service we will use its Docker container.

Note
If you don’t have Docker installed on your machine please follow the instructions at https://www.docker.com/get-started.

Run the following command:

docker run --rm --name jaeger -p6831:6831/udp -p16686:16686 jaegertracing/all-in-one:1.16.0
Note
This can take a minute.

Now you can access http://localhost:16686 in your browser to see the Jaeger UI console.

Now we can start adding our custom spans from our application.

Implicit tracing of REST resources

The MicroProfile OpenTracing specification provides an implicit tracing of all JAX-RS resources. That means that an implementation of MicroProfile OpenTracing will automatically:

  • extract the Span context from the incoming JAX-RS request

  • start a new Span on incoming JAX-RS request and close it when the request is completed

  • inject Span context to any outgoing JAX-RS request

  • start a Span for any outgoing JAX-RS request and finish the Span when the request is completed

Let’s create a new JAX-RS resource to demonstrate this. Create a new class org.wildfly.quickstarts.microprofile.opentracing.TracedResource:

package org.wildfly.quickstarts.microprofile.opentracing;

import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
@ApplicationScoped
public class TracedResource {

    @GET
    @Path("/traced")
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "hello";
    }
}

That’s it. There is no tracing code included in the application. All requests to this resource will be traced.

Let’s invoke our resource several times, so we can observe the created spans in the Jaeger console:

Build and deploy the application

$ mvn clean package wildfly:deploy

and make a few requests to the TracedResource by accessing http://localhost:8080/microprofile-opentracing/hello/traced in your browser or by curl http://localhost:8080/microprofile-opentracing/hello/traced. You will see the spans created in the Jaeger console (http://localhost:16686) under the service microprofile-opentracing.war.

Congratulations! We already have tracing with no instrumentation in the code. Let’s now dive into how we can fine tune the tracing in our applications.

The @Traced annotation

The @Traced annotation can be used for:

  • disabling the implicit instrumentation in JAX-RS resources

  • define a custom operation name

  • using tracing explicitly in non JAX-RS classes (see the next section)

To disable implicit tracing you can specify @Traced(false) on any JAX-RS resource method to exclude it from distributed traces. Add the following method to the TracedResource class:

@GET
@Path("/notTraced")
@Produces(MediaType.TEXT_PLAIN)
@Traced(false)
public String notTraced() {
    return "notTraced";
}

And rebuild and deploy the application

$ mvn clean package wildfly:deploy
Note
Because of WFLY-13080 it is also necessary to restart the server now (stop the server and rerun it again).

and make a few requests to the new endpoint by accessing http://localhost:8080/microprofile-opentracing/hello/notTraced in your browser or by curl http://localhost:8080/microprofile-opentracing/hello/notTraced. You will see that the spans for these invocations are not created in the Jaeger console (http://localhost:16686) under the service microprofile-opentracing.war. However, if you repeat some calls to http://localhost:8080/microprofile-opentracing/hello/traced they will appear in the collected spans again.

To define a custom operation name we can pass it as an operationName parameter. Update the TracedResource class:

@GET
@Path("/traced")
@Produces(MediaType.TEXT_PLAIN)
@Traced(operationName = "hello-operation")
public String hello() {
    return "hello";
}

And rebuild and deploy the application

$ mvn clean package wildfly:deploy
Note
Because of WFLY-13080 it is also necessary to restart the server now (stop the server and rerun it again).

and make a few requests to the endpoint by accessing http://localhost:8080/microprofile-opentracing/hello/traced in your browser or by curl http://localhost:8080/microprofile-opentracing/hello/traced. You will see that the spans for these invocations are created with the custom name in the Jaeger console (http://localhost:16686) under the service microprofile-opentracing.war.

Explicit tracing with the @Traced annotation

By default, only the JAX-RS resources are traced. However, the @Traced annotation is a CDI interceptor so we can use it in any CDI bean for more granular tracing inside the service invocation. Create a new class org.wildfly.quickstarts.microprofile.opentracing.ExplicitlyTracedBean:

package org.wildfly.quickstarts.microprofile.opentracing;

import org.eclipse.microprofile.opentracing.Traced;

import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class ExplicitlyTracedBean {

    @Traced
    public String getHello() {
        return "hello";
    }
}

Note the explicit @Traced annotation on the getHello() method.

And update the TracedResource to use our newly defined bean:

@Inject
private ExplicitlyTracedBean tracedBean;

@GET
@Path("/cdi-trace")
@Produces(MediaType.TEXT_PLAIN)
public String cdiHello() {
    return tracedBean.getHello();
}

Build and redeploy the application

$ mvn clean package wildfly:deploy
Note
Because of WFLY-13080 it is also necessary to restart the server now (stop the server and rerun it again).

and repeat a few requests to the TracedResource by accessing http://localhost:8080/microprofile-opentracing/hello/cdi-trace in your browser or by curl http://localhost:8080/microprofile-opentracing/hello/cdi-trace. You will see the two created spans in the Jaeger console (http://localhost:16686) under the service microprofile-opentracing.war. One for the JAX-RS call and one for the CDI bean invocation.

Tracer injection

For even more granular tracing, the MicroProfile OpenTracing allows you to inject directly the configured io.opentracing.Tracer object.

To use io.opentracing.Tracer in our application we need to add one more maven dependency providing the OpenTracing API:

<!-- Import the OpenTracing API for the use of io.opentracing.Tracer -->
<dependency>
  <groupId>io.opentracing</groupId>
  <artifactId>opentracing-api</artifactId>
  <version>0.31.0</version>
</dependency>

Now we can update the ExplicitlyTracedBean:

package org.wildfly.quickstarts.microprofile.opentracing;

import io.opentracing.Span;
import io.opentracing.Tracer;
import org.eclipse.microprofile.opentracing.Traced;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

@ApplicationScoped
public class ExplicitlyTracedBean {

    @Inject
    private Tracer tracer;

    @Traced
    public String getHello() {
        Span prepareHelloSpan = tracer.buildSpan("prepare-hello").start();

        String hello = "hello";

        Span processHelloSpan = tracer.buildSpan("process-hello").start();

        hello = hello.toUpperCase();

        processHelloSpan.finish();
        prepareHelloSpan.finish();

        return hello;
    }
}

Build and redeploy the application

$ mvn clean package wildfly:deploy
Note
Because of WFLY-13080 it is also necessary to restart the server now (stop the server and rerun it again).

and repeat a few requests to the TracedResource by accessing http://localhost:8080/microprofile-opentracing/hello/cdi-trace in your browser or by curl http://localhost:8080/microprofile-opentracing/hello/cdi-trace. You will see now four created spans in the Jaeger console (http://localhost:16686) under the service microprofile-opentracing.war. One for the JAX-RS call, one for the CDI bean invocation and two manually created spans in the ExplicitlyTracedBean.

Conclusion

MicroProfile OpenTracing provides the mechanisms for your application to participate in the distributed tracing with minimal effort on the application side. The JAX-RS resources are always traced by default but the specification allows you to control individual spans directly with the @Traced interceptor or with the CDI injection of the io.opentracing.Tracer.