How to: Microprofile Opentracing with Jaeger

In this post I will explain how can we use Microprofile OpenTracing with Jaeger. This post will be practical and will not explain about Microprofile OpenTracing concept deeply. If you wanna know more about this concept you can access my post here.

To use OpenTracing in our application, we need to do two steps, these steps are:

  1. Prepare the application to expose the data in compliance with OpenTracing.
  2. Configure a monitor to get those data and expose information about application ( in this post we’ll use Jaeger).

Preparing the Application

First of all, to make the application able to communicating with Jaeger, we need configure the environment of the application. To do that we need configure some environment’s variable. Below we have some environment’s variable:

$ export JAEGER_AGENT_HOST=jaeger
$ export JAEGER_SERVICE_NAME=speaker
$ export JAEGER_REPORTER_LOG_SPANS=true
$ export JAEGER_SAMPLER_TYPE=const
$ export JAEGER_SAMPLER_PARAM=1

In example above, we are making a configuration to connect the service called speaker into Jaeger.

Now, we need to configure our JAX-RS resource and JAX-RS client (or RestClient starting at Microprofile OpenTracing 1.3) to propagate trace information across services. To do that we need uses an annotation called @Trace on JAX-RS resource (and Rest Client when use Microprofile OpenTracing 1.3). Below we have an example of that.

Configuring the JAX-RS endpoint to be traced

@Path("speakers")
@Traced
public class SpeakerEndpoint {

...

}

Configuring the JAX-RS Client

When we call another service, the information of tracing need be propagated to it service (service called). With this, we need to configure the JAX-RS Client to propagate the information of tracing. To do that, we need registering the JAX-RS Client to OpenTracing.

public Speaker findById( String speakerId ){
    Client client = ClientTracingRegistrar
                      .configure(ClientBuilder.newBuilder())
                      .build();
    Speaker response = null;
    try {
       response = client.target(path)
               .path("/speakers/"+speakerId)
               .request()
               .get(Speaker.class);

    }
    finally {
       client.close();
    }
    return response;
}

Configuring the Rest Client (OpenTracing 1.3)

Since version 1.3 Microprofile OpenTracing integrates with RestClient . With this, you can use the @Traced to configure its RestClient interfaces to be traced. Thus, the information about tracing is propagated to service that was called.

@Path("/speakers")
@RegisterRestClient
@Traced
public interface SpeakerClientService {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Speaker findById( String speakerId );
}

 

Configuring Jaeger

Now, we need to configure the Jaeger. When the Jaeger is configured and started. Then the applications send information about tracing to Jaeger and the Jaeger cover those information with an UI. In our example we’ll use docker to start the Jaeger. Below we have a Docker command.

$ docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14268:14268 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.11

Then, access http://localhost:16686 to see the Jaeger UI. Below we have a figure with Jaeger UI screem used in our example.

Screenshot from 2019-02-09 19-13-22

When you start  Jaeger, it’ll start to receive service’s data and show in its UI. With this, each access to your services will be shown there.

Conclusion

Using Microprofile Opentracing we can use distributed trace with easier way, without write several line codes and connecting to Jaeger to shows these traces with a good UI. If you want to know more about this Microprofile spec click here.

To see the complete example used here access: https://github.com/rhuan080/microprofile-example

 

Introduction: Observability with Microprofile

Microservice architecture is an approach that is very compliant with the cloud environment, permitting us the ability to create a cloud native application. With microservice architecture, we promote resilience, fault tolerance and scale. However, this approach has different challenges than monolithic applications.

In a monolithic application, all code and business role is inside one application. With this, all transactions occur inside the same application. However, the microservice architecture breaks the monolithic application into services that are packaged independently and have an independent life. With this, we have several cross cutting concerns that occur in several services. In other words, we have several processes, concerns or logic that act with distributed way. One of these concerns is about monitoring and logging. With this, we have the concept of Observability.

What is Observability?

The concept of Observability is a concept that came from the control theory, that is a math theory.

Formally, a system is said to be observable if, for any possible sequence of state and control vectors (the latter being variables whose values one can choose), the current state (the values of the underlying dynamically evolving variables) can be determined in finite time using only the outputs.

Wikipedia

Some developers define Observability in a microservice architecture as the set of metrics, logging and tracing tools, but I think observibility as a more generic concept. Metrics, logging and tracing is only a way to provide observability, but in the future we can use another way.

To me, observibility is the capacity of a system expose precise information about its states with easier and faster way. Differently from monitoring, observability is about the own system. When we say about monitoring, the focal point is the tools that will be used to monitoring the system, but the system can be easy or hard to monitor. When we say about observability, the focal point is the own system, that need to provide this information in a easier and faster way. Monitoring a system with observability is always easy, because the system exposes its information facilitating the monitoring.

Observability with Microprofile

With aim to promote a easy support to observability, the Microprofile has some specs to permit the developer to implement observability in our microservices. The Microprofile has 3 main specs to do that, those specs are:  Microprofile OpenTracing, Microprofile Metrics and Microprofile HealthCheck.

Screenshot from 2019-02-27 16-44-31

Microprofile OpenTracing

Microprofile OpenTracing is a spec that permits us to use distributed tracing using the OpenTracing API to trace  the flow of a request across service. This spec is compatible to Zipkin and compatible to Jaeger , and permits us to use Zipkin or Jaeger to show the information about the distributed tracing. Below we have an example of how to use Microprofile OpenTracing.

@Path("subjects")
@Traced
public class SubjectEndpoint {



}

 

Microprofile Metrics

Microprofile Metrics is a spec that permits us to expose metrics information about our applications. With this, we can expose precise metrics to be consumed with easier and faster ways. Below we have an example of how to use Microprofile Metrics.

@Counted
public CounterBean() {
}

Microprofile HealthCheck

Health Check is a spec that permit us expose if the application is up or down in our environment. It works as a boolean response (yes or no) to the question “Is my application still running ok?“. Below we have an example of how to use Microprofile HealthCheck.

@Health
@ApplicationScoped
public class ApplicationHealthCheck implements HealthCheck {

    @Override
    public HealthCheckResponse call() {
        return HealthCheckResponse
                .named("application-check").up()
                .withData("CPUAvailable", Runtime.getRuntime().availableProcessors())
                .withData( "MemoryFree", Runtime.getRuntime().freeMemory())
                .withData("TotalMemory", Runtime.getRuntime().totalMemory())
                .build();
    }
}

Conclusion

The Microprofile has been to promote several solutions to microservice challenges, and one of those solutions are the specs to promote observability in our microservices. With this, we can use microprofile with Jaeger, Zipkin, Prometheus and others to promote better observability and monitoring. This article was only a introduction and I will post more details of these specs in the next posts.

If you want to know more about Microprofile access microprofile.io .

Microprofile Config: Creating a Custom ConfigSource

In this post I’ll show you how can I create a custom ConfigSource to read properties from an external file. In this post I will not explain about what is Eclipse Microprofile Config, and if you want to know what is, access my last post Understanding Eclipse Microprofile Config .

The Eclipse Microprofile Config provide support to read configuration properties by a ConfigSource class. With this, if you need create a custom support to any configuration source (such as database, file system, service), you need create a custom ConfigSource class to provide this support.

In this example I create a ConfigSource to read configuration properties from an external file(outside of package), and the package will have only one property inside, that is the property to get the path of the file configuration. Bellow we have FileSystemConfigSource class that implementing ConfigSource.

public class FileSystemConfigSource implements ConfigSource {

    private final String FILE_CONFIG_PROPERTY = "net.rhuanrocha.mp-speaker.config.file.path";
    private final String CONFIG_SOURCE_NAME = "FileSystemConfigSource";
    private final int ORDINAL = 300;

    private String fileConfig;

    @Override
    public Map getProperties() {

        try(InputStream in = new FileInputStream( readPath() )){

            Properties properties = new Properties();
            properties.load( in );

            Map map = new HashMap();
            properties.stringPropertyNames()
                    .stream()
                    .forEach(key-> map.put(key, properties.getProperty(key)));

            return map;

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public Set getPropertyNames() {

        try(InputStream in = new FileInputStream( readPath() )){

            Properties properties = new Properties();
            properties.load( in );

            return properties.stringPropertyNames();

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public int getOrdinal() {
        return ORDINAL;
    }

    @Override
    public String getValue(String s) {

        try(InputStream in = new FileInputStream( readPath() )){

            Properties properties = new Properties();
            properties.load( in );

            return properties.getProperty(s);

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public String getName() {
        return CONFIG_SOURCE_NAME;
    }

    public String readPath(){

        if(Objects.nonNull(fileConfig)){
            return fileConfig;
        }

        final Config cfg = ConfigProvider.getConfig();
        return fileConfig = cfg.getValue(FILE_CONFIG_PROPERTY, String.class);
    }

}

Furthermore, we need create a property in META-INF/microprofile-config.properties with the path of the external file, and put the config_ordinal property inside META-INF/microprofile-config.properties major then the ordinal of the FileSystemConfigSource, because the FileSystemConfigSource read the property from META-INF/microprofile-config.properties. Below we have the example.

config_ordinal = 400
net.rhuanrocha.mp-speaker.config.file.path=/etc/mp-speaker/config/configuration.properties

Note: My suggest is insert in META-INF/microprofile-config.properties only the property to path of external file and the config_ordinal property.

If you want to see more about this example, access the repository on github by: https://github.com/rhuan080/microprofile-example

 

Creating New Project Using Microprofile 2.0

In this post I’ll show you how to create a new Microprofile 2.0 (based on Java EE 8) project using an archetype created by me. This archetype is on Maven Central and is an archetype that create a Microprofile project using thorntail with the following classes and dependencies.

Dependencies:

  • Microprofile 2.0
  • Thorntail 2.2.0

Classes:

  • MyEndpoint: An exemple of endpoint .
  • ApplicationHealthCheck: An example of health check.
  • ExceptionMapper: A class to create an exception mapper.
  • MicroProfileConfiguration: Class to configure a Microprofile.

 

To use this archetype run the following maven command:

mvn archetype:generate -DarchetypeGroupId=net.rhuanrocha -DarchetypeArtifactId=microprofile2.0-archetype -DarchetypeVersion=1.0.1 -DgroupId=<new project group id> -DartifactId=<new project artifact id>

After running this command, the project will be created on your current folder.

Understanding MicroProfile

To understand MicroProfile, first we need to understand the Java EE/ Jakarta EE and its challenges and goals.

In a real world, companies need to be able to response to new challenges faster and faster. With this, enterprise world has challenges different from non-enterprise world, because companies need to be able to change fast to correspond to innovate and provides solutions better and better. Furthermore, companies need be scalable to provide its service to a major number of users. With this, the IT began to split the problems and provides solutions in multiples applications that make a communications between them, and those applications began to share data. Then, a new set of problems began to appear in an enterprise world, such as problems about integrations and relationship between components. With this, a new set of patterns to solutions needed to be created to response to the new challenges.

Java EE and now Jakarta EE is an umbrella project that provide patterns solutions to common problems that occur in an enterprise world. It is a set of specs (such as CDI, JPA, JSF, EJB and others) to solve several enterprise problems, and permit that multiple vendors implements these specs. With this, developers can write an enterprise application with Java EE/ Jakarta EE using any vendor that provides the implementation of these specs.

However, with emergence of Cloud and the Cloud Native Application concept, new challenges emerged too and created a gap on Java EE. One gap created on Java EE was solutions to problems about Microservice architecture and solutions to implementing the 12 factors.

MicroProfile is an umbrella project with aim to be an extension of Java EE/ Jakarta EE to Microservice architecture. It contains a set of specs that is formed by some specs of Java EE and other own specs. With this, Microprofile has some specs to solve problems about Microservice architecture and to implementing the 12 factors. MicroProfile initiative with Jakarta EE has a promise to closer the Java to enterprise to Cloud Native Application, promoting a common solutions to explore the Cloud.

MicroProfile 1.4 is based on Java EE 7 and provide support to some specs of Java EE 7, and the MicroProfile 2.0 is based on Java EE 8 and provide support to some specs of Java EE 8. Below we have an image to illustrate that.

MicroProfile 1.4

1infoq-microprofile-1.4-1535583287095

MicroProfile 2.0

microprofile2-0withlegendpic

Note that the MicroProfile don’t have support to all specs of Java EE/Jakarta EE. The aim is over time, other Java EE/Jakarta EE spec will be inserted to MicroProfile.

If you want to know more about MicroProfile, access this link MicroProfile.