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. |
...
Most of the distributed tracers compatible with OpenTracing API could be deployed into OSGi container and as such, the integration is fully available for Apache CXF services running inside the container. For a complete example please take a look on jax_rs_tracing_opentracing_osgi sample project, but here is the typical OSGi Blueprint snippet in case of Jaeger.
Code Block | ||
---|---|---|
| ||
<?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
- https://github.com/apache/cxf/tree/3.2.x-fixes/distribution/src/main/release/samples/jax_rs/tracing_opentracing
- https://github.com/apache/cxf/tree/3.2.x-fixes/distribution/src/main/release/samples/jax_rs/tracing_opentracing_camel
- https://github.com/apache/cxf/tree/3.2.x-fixes/distribution/src/main/release/samples/jax_rs/tracing_opentracing_osgi
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:
...
Most of the distributed tracers compatible with OpenTracing API could be deployed into OSGi container and as such, the integration is fully available for Apache CXF services running inside the container. For a complete example please take a look on jax_rs_tracing_opentracing_osgi sample project, but here is the typical OSGi Blueprint snippet in case of Jaeger.
Code Block | ||||
---|---|---|---|---|
| ||||
<?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
- https://github.com/apache/cxf/tree/master/distribution/src/main/release/samples/jax_rs/tracing_opentracing
- https://github.com/apache/cxf/tree/master/distribution/src/main/release/samples/jax_rs/tracing_opentracing_camel
- https://github.com/apache/cxf/tree/3.6.x-fixes/distribution/src/main/release/samples/jax_rs/tracing_opentracing_osgi
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 | ||||
---|---|---|---|---|
| ||||
@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>} } |