...
Distributed Tracing with OpenTelemetry and OSGi
TBD
Spring XML-Configuration
TBD
Accessing OpenTelemetry 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 OpenTelemetry 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 OpenTelemetry instrumentation for OpenFeign client through OpenTracing shim (as of today, OpenFeign client does not provide native support for OpenTelemetry).
Most of the distributed tracers compatible with OpenTelemetry 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_opentelemetry_osgi sample project, but here is the typical OSGi Blueprint snippet in case logging span exporter.
Code Block | ||||
---|---|---|---|---|
| ||||
<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
| ||||
Code Block | java | java | ||
final SdkTracerProvider sdkTracerProvider = SdkTracerProvider
.builder()
...
.build();
final OpenTelemetry openTelemetry = OpenTelemetrySdk
.builder()
.setTracerProvider(sdkTracerProvider)
...
.buildAndRegisterGlobal();
// Use OpenTelemetru OpenTracing shim for Feign OpenTracing integration
GlobalTracer.registerIfAbsent(OpenTracingShim.createTracerShim(openTelemetry)); | ||||
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))) .target(GoogleBooksApi.class, "https://www.googleapis.com"); final Response response = api.search(query); try (final Reader reader = response.body().asReader()) {http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd"> <bean id="tracingFeature" class="org.apache.cxf.tracing.opentelemetry.jaxrs.OpenTelemetryFeature"> return Json.createReader(reader).readObject(); } } |
The usage of tracer-specific APIs is not generally advisable (because of portability reasons) but in case there are no other options available, it is available.
Using non-JAX-RS clients
The Apache CXF uses native OpenTelemetry capabilities so the existing instrumentations for different HTTP clients work as expected. The usage of only JAX-RS client is not required. For example, the following snippet demonstrates the usage of traceble OkHttp client to call JAX-RS resources, backed by Apache CXF and OpenTelemetry OkHttp3 instrumentation.
...
<argument index="0">
<bean factory-ref="withPropagators" factory-method="build"/>
</argument>
<argument index="1" value="tracer" />
</bean>
<bean id="openTelemetrySdk" class="io.opentelemetry.sdk.OpenTelemetrySdk" factory-method="builder" />
<bean id="sdkTracerProvider" class="io.opentelemetry.sdk.trace.SdkTracerProvider" factory-method="builder" />
<bean id="withSampler" factory-ref="sdkTracerProvider" factory-method="setSampler">
<argument index="0">
<bean class="io.opentelemetry.sdk.trace.samplers.Sampler" factory-method="alwaysOn" />
</argument>
</bean>
<bean id="processor" class="io.opentelemetry.sdk.trace.export.BatchSpanProcessor" factory-method="builder">
<argument index="0">
<bean class="io.opentelemetry.exporter.logging.LoggingSpanExporter" factory-method="create" />
</argument>
</bean>
<bean id="withSpanProcessor" factory-ref="sdkTracerProvider" factory-method="addSpanProcessor">
<argument index="0">
<bean factory-ref="processor" factory-method="build"/>
</argument>
</bean>
<bean id="withTracerProvider" factory-ref="openTelemetrySdk" factory-method="setTracerProvider">
<argument index="0">
<bean factory-ref="withSpanProcessor" factory-method="build"/>
</argument>
</bean>
<bean id="withPropagators" factory-ref="withTracerProvider" factory-method="setPropagators">
<argument index="0">
<bean class="io.opentelemetry.context.propagation.ContextPropagators" factory-method="create">
<argument index="0">
<bean class="io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator" factory-method="getInstance" />
</argument>
</bean>
</argument>
</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, OpenTelemetry does not provide dedicated OSGi bundles and the service loader mechanism is not working very well. It is very likely that you may need to declare own span exporters. |
Accessing OpenTelemetry 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 OpenTelemetry 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 OpenTelemetry instrumentation for OpenFeign client through OpenTracing shim (as of today, OpenFeign client does not provide native support for OpenTelemetry).
Code Block | ||||
---|---|---|---|---|
| ||||
final SdkTracerProvider sdkTracerProvider = SdkTracerProvider
.builder()
...
.build();
final OpenTelemetry openTelemetry = OpenTelemetrySdk
.builder()
.setTracerProvider(sdkTracerProvider)
...
.buildAndRegisterGlobal();
// Use OpenTelemetru OpenTracing shim for Feign OpenTracing integration
GlobalTracer.registerIfAbsent(OpenTracingShim.createTracerShim(openTelemetry)); |
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)))
.target(GoogleBooksApi.class, "https://www.googleapis.com");
final Response response = api.search(query);
try (final Reader reader = response.body().asReader()) {
return Json.createReader(reader).readObject();
}
} |
The usage of tracer-specific APIs is not generally advisable (because of portability reasons) but in case there are no other options available, it is available.
Using non-JAX-RS clients
The Apache CXF uses native OpenTelemetry capabilities so the existing instrumentations for different HTTP clients work as expected. The usage of only JAX-RS client is not required. For example, the following snippet demonstrates the usage of traceble OkHttp client to call JAX-RS resources, backed by Apache CXF and OpenTelemetry OkHttp3 instrumentation.
Code Block | ||||
---|---|---|---|---|
| ||||
final SdkTracerProvider sdkTracerProvider = SdkTracerProvider
.builder()
...
.build();
final OpenTelemetry openTelemetry = OpenTelemetrySdk
.builder()
.setTracerProvider(sdkTracerProvider)
...
.buildAndRegisterGlobal();
final OkHttpClient client = OkHttpClient.Builder().build();
final Call.Factory factory = OkHttpTelemetry.builder(openTelemetry).build().newCallFactory(client));
final Request request = new Request.Builder()
.url("http://localhost:9000/catalog")
.header("Accept", "application/json")
.build();
try (final Response response = factory.newCall(request).execute()) {
// Do something with response.body()
} |
Samples
- https://github.com/apache/cxf/tree/3.6.x-fixes/distribution/src/main/release/samples/jax_rs/tracing_opentelemetry_osgi
- https://github.com/apache/cxf/tree/main/distribution/src/main/release/samples/jax_rs/tracing_opentelemetry
- https://github.com/apache/cxf/tree/main/distribution/src/main/release/samples/jax_rs/tracing_opentelemetry_camel