Trace the JAX-RS2 Java application created in Jersey with Zipkin.

Install docker.
Linux installs docker-compose additionally. Mac and Windows are not required because they are included in the Docker installer.
sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
Clone docker-zipkin from github and run Zipkin server with docker
git clone https://github.com/openzipkin/docker-zipkin.git
cd docker-zipkin
docker-compose up -d
You can access the Zipkin web UI at the following URL
The application is made with Jersey as the title suggests. I uploaded the completed one to github.
It utilizes Jersey 2, a server-side JAX-RS2 reference implementation.
Note that groupId progressivecom.sun.jersey``, which often appears when googled with Jersey, is not compatible with Jersey 1 series.
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-server -->
<dependency>
  <groupId>org.glassfish.jersey.core</groupId>
  <artifactId>jersey-server</artifactId>
  <version>2.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.inject/jersey-hk2 -->
<dependency>
  <groupId>org.glassfish.jersey.inject</groupId>
  <artifactId>jersey-hk2</artifactId>
  <version>2.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-servlet -->
<dependency>
  <groupId>org.glassfish.jersey.containers</groupId>
  <artifactId>jersey-container-servlet</artifactId>
  <version>2.26</version>
</dependency>
The client-side JAX-RS2 also makes use of the reference implementation Jersey 2.
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-client -->
<dependency>
  <groupId>org.glassfish.jersey.core</groupId>
  <artifactId>jersey-client</artifactId>
  <version>2.26</version>
</dependency>
Web Application written in Java usually runs on Tomcat, Glassfish, Jetty, etc., but this time, for the sake of simplicity, use  jersey-container-jdk-http to implement the Http server. Embed directly in the application.
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-jdk-http -->
<dependency>
  <groupId>org.glassfish.jersey.containers</groupId>
  <artifactId>jersey-container-jdk-http</artifactId>
  <version>2.26</version>
</dependency>
A Zipkin Instrumentation library for JAX-RS2 Java applications that allows you to trace on a JAX-RS server / client.
<!-- https://mvnrepository.com/artifact/io.zipkin.brave/brave-instrumentation-jaxrs2 -->
<dependency>
  <groupId>io.zipkin.brave</groupId>
  <artifactId>brave-instrumentation-jaxrs2</artifactId>
  <version>4.3.1</version>
</dependency>
The collected tracing data must be sent to the Zipkin server. This library will send it to any destination.
<!-- https://mvnrepository.com/artifact/io.zipkin.reporter/zipkin-sender-urlconnection -->
<dependency>
  <groupId>io.zipkin.reporter</groupId>
  <artifactId>zipkin-sender-urlconnection</artifactId>
  <version>1.1.2</version>
</dependency>
JAX-RS2 allows you to plug in external libraries that implement the  javax.ws.rs.core.Feature IF.
Brave, a Zipkin library for Java applications, supports various Java frameworks. This time, we will use brave-instrumentation-jaxrs2 for JAX-RS2.
 brave.jaxrs2.TracingFeature is a Trace Instrumentation for JAX-RS2 that Creates Tracing Data (https://zipkin.io/pages/architecture.html). zipkin.reporter.AsyncReporter sends the tracing data collected on the application to the Zipkin server.package zipkin;
import brave.Tracing;
import brave.jaxrs2.TracingFeature;
import brave.sampler.Sampler;
import zipkin.reporter.AsyncReporter;
import zipkin.reporter.urlconnection.URLConnectionSender;
import javax.ws.rs.core.Feature;
public class ZipkinFeature {
    /**
     * @param localServiceName Service name displayed in Zipkin Web UI
     */
    public static Feature create(String localServiceName) {
        // create a zipkin reporter.
        AsyncReporter<Span> asyncReporter = AsyncReporter
                .builder(URLConnectionSender.create("http://localhost:9411/api/v1/spans"))
                .build();
        // create a zipkin tracing.
        Tracing tracing = Tracing.newBuilder()
                .reporter(asyncReporter)
                .localServiceName(localServiceName)
                .sampler(Sampler.ALWAYS_SAMPLE)
                .build();
        // create a JAX-RS feature.
        Feature tracingFeature = TracingFeature.create(tracing);
        return tracingFeature;
    }
}
Create a class that implements the server-side JAX-RS2 entry point  javax.ws.rs.core.Application IF. Here, the tracing function  brave.jaxrs2.TracingFeature generated earlier Register with server-side JAX-RS2.
package app;
import zipkin.ZipkinFeature;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Feature;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
@ApplicationPath("")
public class MyApplication extends Application {
    @Override
    public Set<Object> getSingletons() {
        // create a JAX-RS feature.
        Feature tracingFeature = ZipkinFeature.create("server");
        return new LinkedHashSet<>(Arrays.asList(tracingFeature));
    }
}
Create a resource class (API definition) for server-side JAX-RS2. Originally, I would like to deploy multiple services and check the operation of Zipkin, but for the sake of simplicity, define 3 APIs and client JAX. -Called in order by RS2.
Here, too, the tracing function  brave.jaxrs2.TracingFeature generated earlier is registered in the client JAX-RS2.
package resource;
import zipkin.ZipkinFeature;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("")
public class MyResource {
    /**
     * /front --> /mid --> /back
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("front")
    public Response front() {
        // create a JAX-RS feature.
        Feature tracingFeature = ZipkinFeature.create("client");
        // http client: GET /mid
        Response r = ClientBuilder.newClient()
                .register(tracingFeature)
                .target("http://localhost:8080/myapp/mid")
                .request()
                .get();
        return Response.fromResponse(r).build();
    }
    /**
     * /mid --> /back
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("mid")
    public Response mid() {
        // create a JAX-RS feature.
        Feature tracingFeature = ZipkinFeature.create("client");
        // http client: GET /back
        Response r = ClientBuilder.newClient()
                .register(tracingFeature)
                .target("http://localhost:8080/myapp/back")
                .request()
                .get();
        return Response.fromResponse(r).build();
    }
    /**
     * /back
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("back")
    public String back() {
        return "hello";
    }
}
We use jersey-container-jdk-http for the Http server implementation because we want it to work easily.
package main;
import app.MyApplication;
import com.sun.net.httpserver.HttpServer;
import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import java.net.URI;
public class Main {
    public static void main(String[] args) {
        // register JAX-RS Application class.
        ResourceConfig rc = ResourceConfig.forApplicationClass(MyApplication.class);
        // register a path of REST resources.
        rc.packages(true, "resource");
        // run a jersey server.
        URI uri = URI.create("http://localhost:8080/myapp/");
        HttpServer httpServer = JdkHttpServerFactory.createHttpServer(uri, rc);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> httpServer.stop(0)));
    }
}
Run the application. You can access it at the following URL.
Visit the Zipkin Web UI. You should be able to see the tracing data you just accessed.
