Tracers

Setting up your Tracer

A Tracer is the actual implementation that will record the Spans and publish them somewhere. How your application handles the actual Tracer is up to you: either consume it directly throughout your application or store it in the GlobalTracer for easier usage with instrumented frameworks.

Different Tracer implementations vary in how and what parameters they receive at initialization time, such as:

  • Component name for this application’s traces.
  • Tracing endpoint.
  • Tracing credentials.
  • Sampling strategy.

For example, initializing the Tracer implementation of Jaeger might look like this:

  1. import io.opentracing.Tracer;
  2. SamplerConfiguration samplerConfig = new SamplerConfiguration("const", 1);
  3. ReporterConfiguration reporterConfig = new ReporterConfiguration(true, null, null, null, null);
  4. Configuration config = new Configuration(service, samplerConfig, reporterConfig);
  5. // Get the actual OpenTracing-compatible Tracer.
  6. Tracer tracer = config.getTracer();

If your Tracer supports it, the TracerResolver can also be used. With this approach, there’s no Tracer-specific initialization code in your application:

  1. Tracer tracer = TracerResolver.resolveTracer();

Once a Tracer instance is obtained, it can be used to manually create Span, or pass it to existing instrumentation for frameworks and libraries:

  1. // OpenTracing Redis client. It can be *any* OT-compatible tracer.
  2. Tracer tracer = ...;
  3. new TracingJedis(tracer);

Global Tracer

In order to not force the user to keep around a Tracer, the io.opentracing.util artifact includes a helper GlobalTracer class implementing the io.opentracing.Tracer interface, which, as the name implies, acts as as a global instance that can be used from anywhere. It works by forwarding all operations to another underlying Tracer, that will get registered at some future point.

By default, the underlying Tracer is a no-nop implementation.

  1. import io.opentracing.util.GlobalTracer;
  2. // As part of initialization, pass it as an actual Tracer
  3. // to code that will create Spans in the future.
  4. new TracingJedis(GlobalTracer.get());
  5. // Eventually register it, so all the calls to GlobalTracer.get()
  6. // are forwarded to this object. Registration can happen only once.
  7. Tracer tracer = new CustomTracer(...);
  8. GlobalTracer.register(tracer);
  9. ...
  10. // Create a Span as usually. This Span creation will happen
  11. // using your CustomTracer.
  12. Span span = GlobalTracer.get().buildSpan("foo").start();

Using Tracer specific features

For using Tracer-specific features, the instance needs to be casted back to the original type:

  1. ((CustomTracer)tracer).customFeature(100);

GlobalTracer does not expose the original Tracer, and thus is not possible to use Tracer-specific features through it.