2.6 Application Tracing

Inspecting the tracing setup.

OpenTracing with Jaeger Tracing

We use OpenTracing for the distributed tracing. Our tracing backend is Jaeger.

Dependencies

Our application includes the following dependencies in the pom.xml.

GroupId ArtifactId Description Detailed information
io.quarkus quarkus-smallrye-opentracing MicroProfile OpenTracing implementation MicroProfile OpenTracing
io.opentracing.contrib opentracing-jdbc Provides traces for database queries. Using OpenTracing

Configuration

The following configurations need to be made in the application.properties to setup the tracing:

1
2
3
4
quarkus.jaeger.endpoint=http://jaeger:14268/api/traces
quarkus.jaeger.service-name=monolith-application
quarkus.jaeger.sampler-type=const
quarkus.jaeger.sampler-param=1
  • endpoint: defines where we will send our metrics
  • service-name: the name of the current service
  • sampler-type: const defines a constant sampling
  • sampler-param: percentage of request which are sampled. 1 defines that we want to sample all requests.

Further we need to change our database driver to the tracing enabled driver.

1
2
3
4
quarkus.datasource.db-kind=postgresql
quarkus.datasource.jdbc.url=jdbc:tracing:postgresql://application-db:5432/admin
quarkus.datasource.jdbc.driver=io.opentracing.contrib.jdbc.TracingDriver
quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQLDialect

Last we change the Quarkus log format to include the traceId and spanId in the logs. This is not necessary but will help troubleshooting.

1
quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId}, spanId=%X{spanId}, sampled=%X{sampled} [%c{2.}] (%t) %s%e%n

full source application.properties

Application code

Using the configuration made is basically everything which is needed to get traces from our application. By default all requests to RESTful endpoints are traced. Using the TracingDriver provides spans for all database queries.

If you want to customize the tracing you can annotate any class or method with the @Traced annotation. You may also disable the default tracing with @Traced(false). Further you may inject the Tracer to your application code. Using this tracer you can create custom spans in business methods or add tags to span.

This snipped is from class ShopOrderService.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@ApplicationScoped
public class ShopOrderService {
    // ...

    @Inject
    Tracer tracer;

    @Traced(operationName = "createOrder")
    public ShopOrder createOrder(ShopOrderDTO shopOrderDTO) {
        ShopOrder shopOrder = new ShopOrder();
        // ...
        shopOrder.persist();

        tracer.activeSpan().setTag("order.id", shopOrder.id);

        return shopOrder;
    }
}

This will create a span for the method createOrder and name it accordingly. Using the injected Tracer we tag the span with the just created order.id.

full source ShopOrderService.java

Task 2.6.1 - Inspect the application traces

Start up your environment if not already running and point your browser to the Jaeger UI at http://localhost:16686/

Issue requests as described in section 2.4

  • Do you find traces for created orders? You may list all traces or use the tag filter order.id=X
  • How do traces look like if the operationName is not set?
  • Do you see the tag order.id on the span?
  • What happens if you inject an exception as described in section 2.4?
Task Hint

Traces from application code with no explicit name are named by their class and method. If an exception is thrown, there will be a tag error=true on the span. The Jaeger UI will flag such spans with an exclamation mark.