Elastic APM and openTracing

Am I right in assuming that one of the primary objectives of openTracing is to make instrumentation of traces within application code agnostic to the specific tracer being used? In other words, I should be able to swap out Jaeger or Zipkin for Elastic APM without any required code changes (other than imports).

I was looking at some openTracing tutorials at https://github.com/yurishkuro/opentracing-tutorial/tree/master/java and I can't see how this could possibly work without code changes. Here is the Java example:

package lesson01.solution;

import com.google.common.collect.ImmutableMap;
import io.jaegertracing.internal.JaegerTracer;
import io.opentracing.Span;
import io.opentracing.Tracer;
import lib.Tracing;

public class Hello {

private final Tracer tracer;

private Hello(Tracer tracer) {
    this.tracer = tracer;
}

private void sayHello(String helloTo) {
    Span span = tracer.buildSpan("say-hello").start();
    span.setTag("hello-to", helloTo);

    String helloStr = String.format("Hello, %s!", helloTo);
    span.log(ImmutableMap.of("event", "string-format", "value", helloStr));

    System.out.println(helloStr);
    span.log(ImmutableMap.of("event", "println"));

    span.finish();
}

public static void main(String[] args) {
    if (args.length != 1) {
        throw new IllegalArgumentException("Expecting one argument");
    }

    String helloTo = args[0];
    try (JaegerTracer tracer = Tracing.init("hello-world")) {
        new Hello(tracer).sayHello(helloTo);
    }
 }

Unless I'm missing something, I can't see how this could be switched to elastic APM without code changes?

Yes, that's the idea behind the API. There is one part that you'll need to change in your application: constructing the Tracer object. In this example, that would be the tracer value that's passed into new Hello(tracer). More concretely:

  • remove import io.jaegertracing.internal.JaegerTracer; (it's not needed anyway)
  • add import co.elastic.apm.opentracing.ElasticApmTracer;
  • pass a Tracer constructed using new ElasticApmTracer() into new Hello(...)

Other than that, follow https://www.elastic.co/guide/en/apm/agent/java/current/opentracing-bridge.html and https://www.elastic.co/guide/en/apm/agent/java/current/setup.html to add the build and runtime dependencies.

So there are some changes required, but note that it's restricted to initialising the Tracer. After that, the instrumentation code is all the same: i.e. the calls to tracer inside Hello.sayHello in the example.

Thanks! that worked well for the example above. However, how would I convert to elastic APM this piece of code that's specific to Jaeger:

@Path("/publish")
@Produces(MediaType.TEXT_PLAIN)
public class PublisherResource {

    @GET
    public String format(@QueryParam("helloStr") String helloStr, @Context HttpHeaders httpHeaders) {
        try (Scope scope = Tracing.startServerSpan(tracer, httpHeaders, "publish")) {
            System.out.println(helloStr);
            scope.span().log(ImmutableMap.of("event", "println", "value", helloStr));
            return "published";
        }
    }
}

Is Tracing.startServerSpan an OpenTracing API?
In any case, your imports are not included in this code snippet, but assuming the tracer here is of type io.opentracing.Tracer, you wouldn't need to change anything in this specific code, as long as you make sure that tracer you are using here is an instance of co.elastic.apm.opentracing.ElasticApmTracer, as @axw instructed above.

I guess I am not clear on how to pass context to the openTracing API using the elastic APM bridge. Jaeger imports a tracing package:

    try (Scope scope = Tracing.startServerSpan(tracer, httpHeaders, "publish")) {
        System.out.println(helloStr);
        scope.span().log(ImmutableMap.of("event", "println", "value", helloStr));
        return "published";
    }

In this case, I can't just replace the Jaeger tracing package with the elastic APM tracer, or can I?

The Tracing class is just a utility class in the same project: https://github.com/yurishkuro/opentracing-tutorial/blob/c3b5f28cbbc1bc40d90cc84758b3229426825869/java/src/main/java/lib/Tracing.java#L42. This method does not depend on Jaeger internals (in contrast to other methods in this class).

Thanks! Adding the tracing class (minus the init method) allows the code to remain as is.

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.