© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
D. R. HeffelfingerPayara Micro Revealedhttps://doi.org/10.1007/978-1-4842-8161-1_9

9. Request Tracing

David R. Heffelfinger1  
(1)
Fairfax, VA, USA
 

A typical microservices architecture consists of several microservices. These services send output to a log file; traditionally, each service sends output to its own log file. When looking at log files across server instances, it is almost never trivial to follow a single trace of execution across our microservices; for example, let’s say we have two services, A and B, and that service A serves as a client for service B. Typically, we will see several calls to service B from service A in the logs, but it is seldom trivial to match which calls from service A match which calls received from service B. Additionally, it is possible service B may be called from clients other than service A, making following a single trace of execution in our application a challenging task. This is where the MicroProfile OpenTracing API comes in; this API generates spans and traces that allow us to trace execution across Payara Micro instances; each span and trace has a unique ID that does not change across instances, allowing us to link log entries from one instance of Payara Micro to another.

Before we can use the MicroProfile OpenTracing API, it needs to be enabled in Payara Micro.

Enabling Request Tracing in Payara Micro

The easiest way to enable request tracing in Payara Micro is via the --enableRequestTracing command line argument, for example:
java -jar payara-micro-5.2021.8.jar --enableRequestTracing --deploy /path/to/my.war

By default, any request taking longer than 30 seconds will be traced. Output is sent to the Payara Micro console in JSON format.

If we wish to override the default minimum amount of time a request must take before it is traced, we can do so via the --thresholdValue and --thresholdUnit command-line arguments, for example, to trace any request taking longer than 100 milliseconds:
java -jar payara-micro-5.2021.8.jar --enableRequestTracing --requestTracingThresholdValue 100 --requestTracingThresholdUnit milliseconds --deploy /path/to/my.war
The --requestTracingThresholdUnit command-line argument accepts the following time units:
  • NANOSECONDS

  • MICROSECONDS

  • MILLISECONDS

  • SECONDS

  • MINUTES

  • HOURS

  • DAYS

    All values for --requestTracingThresholdUnit are case insensitive.

Additionally, --enableRequestTracing accepts an optional value indicating the minimum amount of time a request must take in order to be traced, for example:
java -jar payara-micro-5.2021.8.jar --enableRequestTracing 100ms --deploy /path/to/my.war

The preceding command is an alternative way to configure request tracing so that any request taking longer than 100 milliseconds is traced. The optional value of --enableRequestTracing must be an integer value followed by a unit of time, without any spaces between them.

Valid values for units of time could be the spelled-out unit of time (i.e., “nanoseconds”), or the equivalent abbreviation (i.e., “ns”).

Table 9-1 lists valid values for the unit of time portion of the --enableRequestTracing optional parameter.
Table 9-1

Request Tracing Units of Time

Unit of Time

Spelled-Out Value (Case Insensitive)

Abbreviated Value

Nanoseconds

nanoseconds

ns

Microseconds

microseconds

us or μs

Milliseconds

milliseconds

ms

Seconds

seconds

s

Minutes

minutes

m

Hours

hours

h

Days

days

d

All spelled-out values also accept their singular counterparts (nanosecond, microsecond, etc.).

Spans and Traces

A span represents an individual unit of work, typically a single HTTP request; by default, Payara Micro logs spans in JSON format to its console output.

A trace is a collection of related spans; for example, we could send an HTTP request to a microservice, which in turn sends two more requests to two additional microservices; all three requests in this case would have unique span IDs, but all would share the same trace ID; by looking at the trace ID of each span, we can find out which requests are related. Trace IDs are unique and match even across Payara Micro instances, making it possible to relate log entries in one Payara Micro instance to another.

Let’s look at an example; when discussing programmatic application metrics in Chapter 6, we developed a service to hire or fire employees; additionally, we developed a client service that would hire three employees from a single endpoint; for reference, here is the relevant code for the service implementing the logic to hire employees (metrics specific code removed for simplicity):
package com.ensode.requesttracing;
//imports omitted
@ApplicationScoped
@Path("employeeservice")
public class EmployeeResource {
  private List<Employee> employeeList = new CopyOnWriteArrayList<>(); //thread safe
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  public void hireEmployee(Employee employee) throws InterruptedException {
    //simulate slow processing
    Thread.sleep(100);
    employeeList.add(employee);
  }
}

To slow down processing a bit and make sure our hireEmployee() method gets traces, we added a 100-ms delay to the method.

Via the MicroProfile REST client API, the client service sends three HTTP PUT requests to the preceding service, generating three related HTTP requests.
package com.ensode.requesttracing.client;
//imports omitted
@ApplicationScoped
@Path("employeeclient")
public class EmployeeClientResource {
  @Inject
  @RestClient
  private EmployeeResourceClient employeeResourceClient;
  private List<Employee> employeesToHire;
  @PostConstruct
  public void init() {
    Employee employee1 = new Employee("Jose", "Jimenez");
    Employee employee2 = new Employee("Meera", "Patel");
    Employee employee3 = new Employee("David", "Heffelfinger");
    employeesToHire = List.of(employee1, employee2, employee3);
  }
  @Path("hire")
  @POST
  public void hireEmployees() {
    employeesToHire.forEach(emp →
      employeeResourceClient.hireEmployee(emp));
  }
}

If we enable request tracing with a threshold of 100 ms and send an HTTP POST request to http://localhost:8081/requesttracingclient/webresources/employeeclient/hire, we can see all generated spans on the Payara Micro output for both instances of Payara Micro: the one running the employee client service and the one running the employee service.

On the employee client service Payara Micro instance, we would see output similar to the following:
[2021-11-12T13:18:40.472-0500] [] [INFO] [] [fish.payara.nucleus.notification.log.LogNotifier] [tid: _ThreadID=89 _ThreadName=log-notifier-1] [timeMillis: 1636741120472] [levelValue: 800] [[
  Request execution time: 914(ms) exceeded the acceptable threshold - {"traceSpans":[
{"operationName":"processContainerRequest","spanContext":{"spanId":"e6749770-ab55-4260-887f-520997aab357","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"startTime":"2021-11-12T13:18:39.554501-05:00[America/New_York]","endTime":"2021-11-12T13:18:40.469-05:00[America/New_York]","traceDuration":"914499000","spanTags":[{"Server": "server"},{"Domain": "domain1"}]},
{"operationName":"processWebserviceRequest","spanContext":{"spanId":"4661adac-0ae8-4a97-a303-8eae965fa8f0","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"startTime":"2021-11-12T13:18:39.594981-05:00[America/New_York]","endTime":"2021-11-12T13:18:40.468138-05:00[America/New_York]","traceDuration":"873154000","spanTags":[{"ResponseStatus": "204"},{"host": "[localhost:8081]"},{"Method": "POST"},{"URL": "http://localhost:8081/requesttracingclient/webresources/employeeclient/hire"},{"user-agent": "[curl/7.68.0]"},{"accept": "[*/*]"}],"references":[{"spanContext":{"spanId":"e6749770-ab55-4260-887f-520997aab357","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"relationshipType":"ChildOf"}]},
{"operationName":"POST:com.ensode.requesttracing.client.EmployeeClientResource.hireEmployees","spanContext":{"spanId":"6ae72f1e-a103-4f26-9945-a4b35bbcc49a","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"startTime":"2021-11-12T13:18:39.643-05:00[America/New_York]","endTime":"2021-11-12T13:18:40.467588-05:00[America/New_York]","traceDuration":"824584000","spanTags":[{"http.status_code": "204"},{"component": "jaxrs"},{"span.kind": "server"},{"http.url": "http://localhost:8081/requesttracingclient/webresources/employeeclient/hire"},{"http.method": "POST"}],"references":[{"spanContext":{"spanId":"4661adac-0ae8-4a97-a303-8eae965fa8f0","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"relationshipType":"ChildOf"}]},
{"operationName":"PUT","spanContext":{"spanId":"82ce9de2-239c-4854-aa07-ff2f7c2b388e","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"startTime":"2021-11-12T13:18:39.887-05:00[America/New_York]","endTime":"2021-11-12T13:18:40.244796-05:00[America/New_York]","traceDuration":"357791000","spanTags":[{"http.status_code": "204"},{"component": "jaxrs"},{"span.kind": "client"},{"http.url": "http://localhost:8080/requesttracing/webresources/employeeservice"},{"http.method": "PUT"}],"references":[{"spanContext":{"spanId":"6ae72f1e-a103-4f26-9945-a4b35bbcc49a","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"relationshipType":"ChildOf"}]},
{"operationName":"PUT","spanContext":{"spanId":"715d1e55-82de-4176-82b2-d0bd5309d315","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"startTime":"2021-11-12T13:18:40.248-05:00[America/New_York]","endTime":"2021-11-12T13:18:40.357046-05:00[America/New_York]","traceDuration":"109037000","spanTags":[{"http.status_code": "204"},{"component": "jaxrs"},{"span.kind": "client"},{"http.url": "http://localhost:8080/requesttracing/webresources/employeeservice"},{"http.method": "PUT"}],"references":[{"spanContext":{"spanId":"6ae72f1e-a103-4f26-9945-a4b35bbcc49a","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"relationshipType":"ChildOf"}]},
{"operationName":"PUT","spanContext":{"spanId":"f026af13-61cc-4767-bfc6-c123eb142ac5","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"startTime":"2021-11-12T13:18:40.357-05:00[America/New_York]","endTime":"2021-11-12T13:18:40.463478 -05:00[America/New_York]","traceDuration":"106473000","spanTags":[{"http.status_code": "204"},{"component": "jaxrs"},{"span.kind": "client"},{"http.url": "http://localhost:8080/requesttracing/webresources/employeeservice"},{"http.method": "PUT"}],"references":[{"spanContext":{"spanId":"6ae72f1e-a103-4f26-9945-a4b35bbcc49a","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"relationshipType":"ChildOf"}]}
]}]]

This is JSON-formatted trace with six spans; each span has useful data such as the operation name, span ID, trace ID, start and end times, and trace duration.

The first two spans in the output, with operation names of “processContainerRequest” and “processWebserviceRequest”, are internal Payara Micro calls that get added to the trace.

Notice that in the output, each individual span has a unique ID; however, the trace ID is identical in each one of them; this trace ID is what we can use to link individual requests to a single trace of execution.

If we inspect the output of the Payara Micro instance, we can see output similar to the following:
[[2021-11-12T13:18:40.234-0500] [] [INFO] [] [fish.payara.nucleus.notification.log.LogNotifier] [tid: _ThreadID=85 _ThreadName=log-notifier-1] [timeMillis: 1636741120234] [levelValue: 800] [[
  Request execution time: 293(ms) exceeded the acceptable threshold - {"traceSpans":[
{"operationName":"processContainerRequest","spanContext":{"spanId":"d07f7f93-17f5-4372-a64f-4501d8c63a62","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"startTime":"2021-11-12T13:18:39.936441-05:00[America/New_York]","endTime":"2021-11-12T13:18:40.230-05:00[America/New_York]","traceDuration":"293559000","spanTags":[{"Server": "server"},{"Domain": "domain1"}],"references":[{"spanContext":{"spanId":"e6749770-ab55-4260-887f-520997aab357","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"relationshipType":"ChildOf"}]},
{"operationName":"processWebserviceRequest","spanContext":{"spanId":"bc56a4e5-3347-42d5-895f-99c2c94cc4cf","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"startTime":"2021-11-12T13:18:39.983108-05:00[America/New_York]","endTime":"2021-11-12T13:18:40.229562-05:00[America/New_York]","traceDuration":"246449000","spanTags":[{"traceid": "[a1155558-7068-4c7e-a8b8-2175ba104233]"},{"content-length": "[41]"},{"Method": "PUT"},{"URL": "http://localhost:8080/requesttracing/webresources/employeeservice"},{"payara-tracing-traceid": "[10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f]"},{"accept": "[application/json]"},{"payara-tracing-relationshiptype": "[ChildOf]"},{"spanid": "[82ce9de2-239c-4854-aa07-ff2f7c2b388e]"},{"ResponseStatus": "204"},{"payara-tracing-parentid": "[e6749770-ab55-4260-887f-520997aab357]"},{"host": "[localhost:8080]"},{"content-type": "[application/json]"},{"connection": "[keep-alive]"},{"user-agent": "[Jersey/2.34.payara-p1 (HttpUrlConnection 11.0.12)]"}],"references":[{"spanContext":{"spanId":"d07f7f93-17f5-4372-a64f-4501d8c63a62","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"relationshipType":"ChildOf"}]},
{"operationName":"PUT:com.ensode.requesttracing.EmployeeResource.hireEmployee","spanContext":{"spanId":"19090bd3-6102-40fe-8cf2-b8831a572129","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"startTime":"2021-11-12T13:18:40.023-05:00[America/New_York]","endTime":"2021-11-12T13:18:40.228787-05:00[America/New_York]","traceDuration":"205780000","spanTags":[{"http.status_code": "204"},{"component": "jaxrs"},{"span.kind": "server"},{"http.url": "http://localhost:8080/requesttracing/webresources/employeeservice"},{"http.method": "PUT"}],"references":[{"spanContext":{"spanId":"82ce9de2-239c-4854-aa07-ff2f7c2b388e","traceId":"a1155558-7068-4c7e-a8b8-2175ba104233"},"relationshipType":"ChildOf"},{"spanContext":{"spanId":"bc56a4e5-3347-42d5-895f-99c2c94cc4cf","traceId":"10b36dfc-30ed-4f26-bf7f-c73d3d4bdb6f"},"relationshipType":"ChildOf"}]}
]}]]

In this case, we see only a single HTTP PUT request being traced; the reason we don’t see all three HTTP PUT requests is because we specified a threshold of 100 ms for request tracing when we started this instance of Payara Micro; the other two PUT requests took less than 100 ms; therefore, they were not traced. Note that the trace ID matches the value of the corresponding trace ID on the instance running the client service, allowing us to correlate the invocations.

Customizing Request Tracing

As seen in the previous section, by simply enabling request tracing and specifying a threshold, we get a lot of functionality, which will suffice for most cases. However, we can customize request tracing if the default functionality does not fit our needs.

The MicroProfile OpenTracing API includes a @Traced annotation that allows us to trace methods other than webservice endpoints; it also allows us to disable tracing for any method and to customize the operation name.

We can also further customize request tracing output via the Tracer annotation, which can be used to add additional information to spans, as well as to create additional spans not bound to a method.

Tracing Additional Methods

We can trace any method on a CDI bean by decorating it with the @Traced annotation.

Annotating a CDI bean with @Traced at the class level will result in all methods in the bean being traced.

For example, let’s say our EmployeeResource service fired a CDI event every time we hired an employee; we could have the method observing the event be traced by annotating it with @Traced.
package com.ensode.requesttracing;
//imports omitted
@ApplicationScoped
public class EmployeeEventHandler {
  private static final Logger LOGGER =
    Logger.getLogger(EmployeeEventHandler.class.getName());
  @Traced
  public void handleEmployeeEvent(@Observes Employee employee)
    LOGGER.log(Level.INFO,
      String.format("Hired %s %s",
      employee.getFirstName(), employee.getLastName()));
  }
}
The @Traced annotation would add a new span to the generated trace.
[2021-11-12T15:15:51.189-0500] [] [INFO] [] [fish.payara.nucleus.notification.log.LogNotifier] [tid: _ThreadID=84 _ThreadName=log-notifier-1] [timeMillis: 1636748151189] [levelValue: 800] [[
  Request execution time: 208(ms) exceeded the acceptable threshold - {"traceSpans":[
{"operationName":"processContainerRequest","spanContext":{"spanId":"a4cdd77f-edfd-4e88-8d23-ffe37f2bd8d0","traceId":"7ebf04e9-1a62-494e-867c-cd80cefa31d9"},"startTime":"2021-11-12T15:15:50.977342-05:00[America/New_York]","endTime":"2021-11-12T15:15:51.186-05:00[America/New_York]","traceDuration":"208658000","spanTags":[{"Server": "server"},{"Domain": "domain1"}],"references":[{"spanContext":{"spanId":"1d842a34-6b2b-43f2-a9b0-1dcb4c1b8629","traceId":"7ebf04e9-1a62-494e-867c-cd80cefa31d9"},"relationshipType":"ChildOf"}]},
{"operationName":"processWebserviceRequest","spanContext":{"spanId":"25d4e22e-eac2-4425-a274-f8ab703610ff","traceId":"7ebf04e9-1a62-494e-867c-cd80cefa31d9"},"startTime":"2021-11-12T15:15:50.977893-05:00[America/New_York]","endTime":"2021-11-12T15:15:51.186627-05:00[America/New_York]","traceDuration":"208733000","spanTags":[{"traceid": "[b5382f8d-de60-4aa8-9a24-39302747183b]"},{"content-length": "[47]"},{"Method": "PUT"},{"URL": "http://localhost:8080/requesttracing/webresources/employeeservice"},{"payara-tracing-traceid": "[7ebf04e9-1a62-494e-867c-cd80cefa31d9]"},{"accept": "[application/json]"},{"payara-tracing-relationshiptype": "[ChildOf]"},{"spanid": "[afdbae15-a93f-49c1-bcec-5e128a47af0d]"},{"ResponseStatus": "204"},{"payara-tracing-parentid": "[1d842a34-6b2b-43f2-a9b0-1dcb4c1b8629]"},{"host": "[localhost:8080]"},{"content-type": "[application/json]"},{"connection": "[keep-alive]"},{"user-agent": "[Jersey/2.34.payara-p1 (HttpUrlConnection 11.0.12)]"}]},
{"operationName":"PUT:com.ensode.requesttracing.EmployeeResource.hireEmployee","spanContext":{"spanId":"c909a51d-49dc-4882-8a20-ba399d23db01","traceId":"7ebf04e9-1a62-494e-867c-cd80cefa31d9"},"startTime":"2021-11-12T15:15:50.981-05:00[America/New_York]","endTime":"2021-11-12T15:15:51.186518-05:00[America/New_York]","traceDuration":"205514000","spanTags":[{"http.status_code": "204"},{"component": "jaxrs"},{"span.kind": "server"},{"http.url": "http://localhost:8080/requesttracing/webresources/employeeservice"},{"employee": "David Heffelfinger"},{"http.method": "PUT"}],"references":[{"spanContext":{"spanId":"afdbae15-a93f-49c1-bcec-5e128a47af0d","traceId":"b5382f8d-de60-4aa8-9a24-39302747183b"},"relationshipType":"ChildOf"},{"spanContext":{"spanId":"25d4e22e-eac2-4425-a274-f8ab703610ff","traceId":"7ebf04e9-1a62-494e-867c-cd80cefa31d9"},"relationshipType":"ChildOf"}]},
{"operationName":"com.ensode.requesttracing.EmployeeEventHandler.handleEmployeeEvent","spanContext":{"spanId":"3142e614-7203-4b5e-9c94-06979c031f89","traceId":"7ebf04e9-1a62-494e-867c-cd80cefa31d9"},"startTime":"2021-11-12T15:15:51.085-05:00[America/New_York]","endTime":"2021-11-12T15:15:51.185988-05:00[America/New_York]","traceDuration":"100983000","references":[{"spanContext":{"spanId":"c909a51d-49dc-4882-8a20-ba399d23db01","traceId":"7ebf04e9-1a62-494e-867c-cd80cefa31d9"},"relationshipType":"ChildOf"}]}
]}]]

Disabling Request Tracing

We can disable tracing of any web service endpoint by simply annotating it with @Traced(false), for example, in the hireEmployee() method of EmployeeResource:
 @Traced(false)
 @PUT
 @Consumes(MediaType.APPLICATION_JSON)
 public void hireEmployee(Employee employee)
   throws InterruptedException {
    //simulate slow processing
    Thread.sleep(100);
    employeeList.add(employee);
    employeeEvent.fire(employee);
  }

Customizing the Operation Name

By default, the generated operation name in a span is the fully qualified name of the method being invoked (if the method was invoked as the direct result of an HTTP request, then the method name is preceded by the HTTP request type (PUT, GET, POST, etc.).

If we wish to customize the operation name displayed on the span, we can do so by setting the operationName attribute on the @Traced annotation; for example, in the hireEmployee() method of EmployeeResource, we could do the following:
 @Traced(operationName = "employeeHire")
 @PUT
 @Consumes(MediaType.APPLICATION_JSON)
 public void hireEmployee(Employee employee)
   throws InterruptedException {
   //simulate slow processing
   Thread.sleep(100);
   employeeList.add(employee);
   employeeEvent.fire(employee);
  }
which would result in the following output in the Payara Micro console (for brevity, only the relevant span is shown):
{"operationName":"employeeHire","spanContext":{"spanId":"7647b911-4999-48ad-9c7b-a4eb87629a89","traceId":"1d50764c-848c-4f59-aa7e-902df1813fd8"},"startTime":"2021-11-12T15:31:21.145-05:00[America/New_York]","endTime":"2021-11-12T15:31:21.352779-05:00[America/New_York]","traceDuration":"207775000","spanTags":[{"http.status_code": "204"},{"component": "jaxrs"},{"span.kind": "server"},{"http.url": "http://localhost:8080/requesttracing/webresources/employeeservice"},{"http.method": "PUT"}],"references":[{"spanContext":{"spanId":"c8fbdf31-744a-455a-80c3-2488a8c5c1e9","traceId":"b45f2bd3-762f-42e5-9950-9553c05b67f8"},"relationshipType":"ChildOf"},{"spanContext":{"spanId":"46a5c1c2-4ae0-4395-ad6d-c2bc7fe03808","traceId":"1d50764c-848c-4f59-aa7e-902df1813fd8"},"relationshipType":"ChildOf"}]}

Adding Additional Information to Spans

Another way we can customize spans is by adding custom tags to the generated JSON strings. To do this, we need to add an additional dependency for the OpenTracing API; when using Maven, we can do this by adding an additional <dependency> tag to our pom.xml file, as in the following example (for brevity, only relevant parts of pom.xml are shown):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.ensode</groupId>
  <artifactId>request-tracing</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>request-tracing</name>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>fish.payara.api</groupId>
        <artifactId>payara-bom</artifactId>
        <version>${version.payara}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <!-- additionaldependencies removed for brevity -->
    <dependency>
      <groupId>io.opentracing</groupId>
      <artifactId>opentracing-api</artifactId>
    </dependency>
  </dependencies>
</project>

Most Maven projects for applications to be deployed to Payara Micro should include the payara-bom dependency in its <dependencyManagement> section.

A Maven Bill of Materials (BOM) dictates the correct version of dependencies to our project. By using a BOM, we can add a dependency to our project without specifying its version, the correct version that will work with our other dependencies is declared in the BOM.

payara-bom includes a dependency for opentracing-api in its <dependencyManagement> section; therefore, when adding this dependency to our project, we don’t need to specify a version, as seen in the preceding pom.xml file.

Once we have added the necessary dependency, we need to inject an instance of io.opentracing.Tracer into our code and use it to add custom tags to our spans.
package com.ensode.requesttracing;
import io.opentracing.Tracer;
//additional imports omitted
@ApplicationScoped
@Path("employeeservice")
public class EmployeeResource {
  @Inject
  private Tracer tracer;
  private List<Employee> employeeList = new CopyOnWriteArrayList<>(); //thread safe
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  public void hireEmployee(Employee employee) throws InterruptedException {
    //simulate slow processing
    Thread.sleep(100);
    tracer.activeSpan().setTag(
      "employee", String.format("%s %s", employee.getFirstName(),
       employee.getLastName()));
    employeeList.add(employee);
  }
}

As we can see in the example, we obtain an instance of io.opentracing.Span representing the current span by invoking Tracer.activeSpan(); from that, we invoke the setTag() method, which has two parameters: a String for the tag name, plus an additional parameter for the value. There are three overloaded versions of setTag(); the second parameter could be a String, a boolean, or a Number (any numeric value); in our example, we used the version with two Strings, since we are adding a tag containing the hired employee’s first and last names.

We can see our custom tag by invoking our RESTful web service as usual; our custom tag will be displayed in the JSON string for our span.
{"operationName":"PUT:com.ensode.requesttracing.EmployeeResource.hireEmployee","spanContext":{"spanId":"db583e67-b160-4acd-8e14-1543381848b1","traceId":"3410bb5f-016c-45c4-a0ef-fd67124af853"},"startTime":"2021-11-15T11:33:54.479-05:00[America/New_York]","endTime":"2021-11-15T11:33:54.680121-05:00[America/New_York]","traceDuration":"201116000","spanTags":[{"http.status_code": "204"},{"component": "jaxrs"},{"span.kind": "server"},{"http.url": "http://localhost:8080/requesttracing/webresources/employeeservice"},{"employee": "Jose Jimenez"},{"http.method": "PUT"}],"references":[{"spanContext":{"spanId":"b7b53629-7890-43d1-9dc4-1c736d21f1cc","traceId":"d5d2cca0-b1b4-4688-8c06-f545c256a1be"},"relationshipType":"ChildOf"},{"spanContext":{"spanId":"42a56b8d-183a-49ef-bc0b-0c322a81930f","traceId":"3410bb5f-016c-45c4-a0ef-fd67124af853"},"relationshipType":"ChildOf"}]}

Creating Additional Spans

We can add custom spans to the current trace by invoking Tracer.buildSpan(), as illustrated in the following example:
package com.ensode.requesttracing;
//imports omitted
@ApplicationScoped
@Path("employeeservice")
public class EmployeeResource
  @Inject
  private Tracer tracer;
  private List<Employee> employeeList = new CopyOnWriteArrayList<>(); //thread safe
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  public void hireEmployee(Employee employee) throws InterruptedException {
    Span customSpan;
    Tracer.SpanBuilder spanBuilder =
      tracer.buildSpan("customSpan");
    customSpan = spanBuilder.start();
    //simulate slow processing
    Thread.sleep(215);
    customSpan.finish();
    employeeList.add(employee);
  }
}

Tracer.buildSpan() creates an instance of the SpanBuilder class, which is an inner class of Tracer; this method takes a single argument, a String indicating the operation name of our custom span.

When we actually want to start our custom span, we need to invoke the start() method on the SpanBuilder instance we created when invoking buildSpan(); to stop our custom span, we invoke its finish() method; when we execute the endpoint containing our custom tag, we will be able to see it in the Payara Micro console output.
[2021-11-15T18:28:23.429-0500] [] [INFO] [] [fish.payara.nucleus.notification.log.LogNotifier] [tid: _ThreadID=90 _ThreadName=log-notifier-1] [timeMillis: 1637018903429] [levelValue: 800] [[
  Request execution time: 228(ms) exceeded the acceptable threshold - {"traceSpans":[
{"operationName":"processContainerRequest","spanContext":{"spanId":"c4d7a6ab-eb74-4bf1-9b72-db0408cbf782","traceId":"0e282189-a825-466e-8488-b2fe569f7a0f"},"startTime":"2021-11-15T18:28:23.199057-05:00[America/New_York]","endTime":"2021-11-15T18:28:23.428-05:00[America/New_York]","traceDuration":"228943000","spanTags":[{"Server": "server"},{"Domain": "domain1"}],"references":[{"spanContext":{"spanId":"0e608033-901d-48c5-8d13-839507128e23","traceId":"0e282189-a825-466e-8488-b2fe569f7a0f"},"relationshipType":"ChildOf"}]},
{"operationName":"processWebserviceRequest","spanContext":{"spanId":"17011bca-7418-42e6-8513-4a586752fb10","traceId":"0e282189-a825-466e-8488-b2fe569f7a0f"},"startTime":"2021-11-15T18:28:23.200232-05:00[America/New_York]","endTime":"2021-11-15T18:28:23.428209-05:00[America/New_York]","traceDuration":"227974000","spanTags":[{"traceid": "[2f61f32a-c96d-4521-8a82-64e97799f626]"},{"content-length": "[40]"},{"Method": "PUT"},{"URL": "http://localhost:8080/requesttracing/webresources/employeeservice"},{"payara-tracing-traceid": "[0e282189-a825-466e-8488-b2fe569f7a0f]"},{"accept": "[application/json]"},{"payara-tracing-relationshiptype": "[ChildOf]"},{"spanid": "[922671a9-9eae-4c97-ae30-36c71b4f13cb]"},{"ResponseStatus": "204"},{"payara-tracing-parentid": "[0e608033-901d-48c5-8d13-839507128e23]"},{"host": "[localhost:8080]"},{"content-type": "[application/json]"},{"connection": "[keep-alive]"},{"user-agent": "[Jersey/2.34.payara-p1 (HttpUrlConnection 11.0.12)]"}]},
{"operationName":"customSpan","spanContext":{"spanId":"7b3f24a2-1aa3-4b51-af46-019cdd905b3a","traceId":"0e282189-a825-466e-8488-b2fe569f7a0f"},"startTime":"2021-11-15T18:28:23.206-05:00[America/New_York]","endTime":"2021-11-15T18:28:23.422066-05:00[America/New_York]","traceDuration":"216057000","references":[{"spanContext":{"spanId":"81313aaa-d744-459c-99c5-aa00e8d679c9","traceId":"0e282189-a825-466e-8488-b2fe569f7a0f"},"relationshipType":"ChildOf"},{"spanContext":{"spanId":"17011bca-7418-42e6-8513-4a586752fb10","traceId":"0e282189-a825-466e-8488-b2fe569f7a0f"},"relationshipType":"ChildOf"}]},
{"operationName":"PUT:com.ensode.requesttracing.EmployeeResource.hireEmployee","spanContext":{"spanId":"81313aaa-d744-459c-99c5-aa00e8d679c9","traceId":"0e282189-a825-466e-8488-b2fe569f7a0f"},"startTime":"2021-11-15T18:28:23.206-05:00[America/New_York]","endTime":"2021-11-15T18:28:23.428083-05:00[America/New_York]","traceDuration":"222078000","spanTags":[{"http.status_code": "204"},{"component": "jaxrs"},{"span.kind": "server"},{"http.url": "http://localhost:8080/requesttracing/webresources/employeeservice"},{"http.method": "PUT"}],"references":[{"spanContext":{"spanId":"922671a9-9eae-4c97-ae30-36c71b4f13cb","traceId":"2f61f32a-c96d-4521-8a82-64e97799f626"},"relationshipType":"ChildOf"},{"spanContext":{"spanId":"17011bca-7418-42e6-8513-4a586752fb10","traceId":"0e282189-a825-466e-8488-b2fe569f7a0f"},"relationshipType":"ChildOf"}]}]]
We can add custom tags to our custom spans by invoking setTag(); in the preceding example, we could have added the following line:
customSpan.setTag("foo", "bar");

to add a tag labeled foo with a value of bar to our custom span.

Summary

In this chapter, we covered the request tracing capabilities of Payara Micro. We saw how to enable request tracing via a command-line argument to Payara Micro, which results in all of the RESTful web service endpoints in our application being automatically traced. We also covered how to trace additional methods in our applications via the @Traced annotation, as well as how to disable request tracing in places where it is not desired. Additionally, we covered how to customize the operation name in the spans generated by our applications, as well as how to add custom tags to our spans. Finally, we covered how to programmatically create spans in case we need more control than what is provided by the MicroProfile OpenTracing API.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.65.61