Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Overview

OpenTracing is a vendor-neutral open standard for distributed tracing. Essentially, for Java-based projects the specification exists as a set of Java APIs which any distributed tracing solution is welcome to implement. There are quite a few distributed tracing frameworks available which are compatible with OpenTracing, notably Zipkin (via community contributions like bridge from Brave to OpenTracing ), Lightstep and Jaeger. Starting from 3.2.1 release, Apache CXF fully supports integration (through cxf-integration-tracing-opentracing module) with any distributed tracer that provides OpenTracing Java API implementation.

...

The actual invocation of the request by the client (with service name tracer-client) and consequent invocation of the service on the server side (service name traceser-server) is going to generate the following sample traces (taken from Jaeger UI):

 


Info

Please notice that timelines are treated as logs events in Jaeger.

...

Code Block
languagexml
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cxf="http://cxf.apache.org/blueprint/core"
       xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"

       xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
                           http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
                           http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd">

    <bean id="tracingFeature" class="org.apache.cxf.tracing.opentracing.jaxrs.OpenTracingFeature">
        <argument index="0">
            <bean factory-ref="builder" factory-method="build" />
        </argument>
    </bean>
    
    <bean id="metrics" class="com.uber.jaeger.metrics.Metrics">
        <argument index="0">
            <bean class="com.uber.jaeger.metrics.StatsFactoryImpl">
                <argument index="0">
                    <bean class="com.uber.jaeger.metrics.NullStatsReporter" />
                </argument>
            </bean>
        </argument>
    </bean>
    
    <bean id="builder" class="com.uber.jaeger.Tracer.Builder">
        <argument index="0" value="cxf-server" />
        <argument index="1">
            <bean class="com.uber.jaeger.reporters.RemoteReporter">
                <argument index="0" ref="sender" />
                <argument index="1" value="1000"/>
                <argument index="2" value="100"/>
                <argument index="3" ref="metrics"/>
            </bean>
        </argument>
        <argument index="2">
            <bean class="com.uber.jaeger.samplers.ConstSampler">
                <argument index="0" value="true" />
            </bean>
        </argument>
    </bean>
    
    <bean id="sender" class="com.uber.jaeger.senders.HttpSender">
        <argument index="0" value="http://localhost:14268/api/traces" />
    </bean>
    
    <cxf:bus>
        <cxf:features>
            <cxf:logging />
        </cxf:features>
    </cxf:bus>

    <jaxrs:server id="catalogServer" address="/">
        <jaxrs:serviceBeans>
            ...
        </jaxrs:serviceBeans>
        <jaxrs:providers>
            <ref component-id="tracingFeature" />
        </jaxrs:providers>
    </jaxrs:server>
</blueprint>

OpenTracing API v0.31.0 and Apache CXF 3.3.x

Configuring Client

In this section and below, all the code snippets are going to be based on Jaeger distributed tracing framework (release 0.30.3+), although everything we are going to discuss is equally applicable to any other existing alternatives. Essentially, the only dependency Apache CXF integration relies on is the Tracer instance. Jaeger uses service Java's ServiceLoader mechanism to determine the instance of the tracer to use, so it is necessary to provide META-INF/services/io.jaegertracing.spi.SenderFactory binding, for example:

Code Block
io.jaegertracing.thrift.internal.senders.ThriftSenderFactory

Samples

OpenTracing API v0.31.0 and Apache CXF 3.3.x

Configuring Client

In this section and below, all the code snippets are going to be based on Jaeger distributed tracing framework (release 0.30.3+), although everything we are going to discuss is equally applicable to any other existing alternatives. Essentially, the only dependency Apache CXF integration relies on is the Tracer instance. Jaeger uses service Java's ServiceLoader mechanism to determine the instance of the tracer to use, so it is necessary to provide META-INF/services/io.jaegertracing.spi.SenderFactory binding, for example:

Code Block
io.jaegertracing.thrift.internal.senders.ThriftSenderFactory

Alternatively, Alternatively, you may just provide own implementation of the SenderConfiguration with the override getSender method, for example:

...

Code Block
xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cxf="http://cxf.apache.org/blueprint/core"
       xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"

       xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
                           http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
                           http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd">

    <bean id="tracingFeature" class="org.apache.cxf.tracing.opentracing.jaxrs.OpenTracingFeature">
        <argument index="0">
            <bean factory-ref="withReporter" factory-method="getTracer" />
        </argument>
    </bean>

    <bean id="samplerBuilder" class="io.jaegertracing.Configuration.SamplerConfiguration" />
    
    <bean id="withType" factory-ref="samplerBuilder" factory-method="withType">
        <argument index="0" value="const"/>
    </bean>
    
    <bean id="sampler" factory-ref="withType" factory-method="withParam">
        <argument index="0">
            <bean class="java.lang.Integer">
                <argument value="1" />
            </bean>
        </argument>
    </bean>
    
    <bean id="senderBuilder" class="io.jaegertracing.Configuration.SenderConfiguration" />
    
    <bean id="sender" factory-ref="senderBuilder" factory-method="withEndpoint">
        <argument index="0" value="http://localhost:14268/api/traces"/>
    </bean>
    
    <bean id="reporterBuilder" class="io.jaegertracing.Configuration.ReporterConfiguration" />
    
    <bean id="reporter" factory-ref="reporterBuilder" factory-method="withSender">
        <argument index="0" ref="sender"/>
    </bean>
    
    <bean id="builder" class="io.jaegertracing.Configuration">
        <argument index="0" value="cxf-server" />
    </bean>

    <bean id="withSampler" factory-ref="builder" factory-method="withSampler">
        <argument index="0" ref="sampler"/>
    </bean>
    
    <bean id="withReporter" factory-ref="withSampler" factory-method="withReporter">
        <argument index="0" ref="reporter"/>
    </bean>
    
    <cxf:bus>
        <cxf:features>
            <cxf:logging />
        </cxf:features>
    </cxf:bus>

    <jaxrs:server id="catalogServer" address="/">
        <jaxrs:serviceBeans>"/>
    </bean>
    
    <cxf:bus>
        <cxf:features>
            <cxf:logging />
        </cxf:features>
    </cxf:bus>

    <jaxrs:server id="catalogServer" address="/">
        <jaxrs:serviceBeans>
            ...
        </jaxrs:serviceBeans>
        <jaxrs:providers>
            <ref component-id="tracingFeature" />
        </jaxrs:providers>
    </jaxrs:server>
</blueprint>


Info

As of now, Jaeger tracer does not provide OSGi bundles and the service loader mechanism is not working very well. It is very likely that you may need to declare own sender configuration instance (overriding getSender method) or use system properties to pick the right one.

Samples

Accessing OpenTracing APIs

The Apache CXF  abstracts as much of the tracer-specific APIs behind TracerContext as possible. However, sometimes there is a need to get access to OpenTracing APIs in order to leverages the rich set of available instrumentations. To make it possible, TracerContext has a dedicated unwrap method which returns underlying Tracer instance. The snippet below shows off how to use this API and use OpenTracing instrumentation for OpenFeign client.

Code Block
java
java
@GET
@Path("/search")
@Produces(MediaType.APPLICATION_JSON)
public JsonObject search(@QueryParam("q") final String query, @Context final TracerContext tracing) throws Exception {
    final GoogleBooksApi api = Feign.builder()
        .client(new TracingClient(new ApacheHttpClient(),  tracing...
unwrap(Tracer.class)))
         </jaxrs:serviceBeans>.target(GoogleBooksApi.class, "https://www.googleapis.com");

    final Response response  <jaxrs:providers>= api.search(query);
    try (final Reader reader =    <ref component-id="tracingFeature" />
response.body().asReader()) {
         </jaxrs:providers>return Json.createReader(reader).readObject();
    </jaxrs:server>
</blueprint>}
}