Bridge between OpenTracing and Brave
Clone or download

README.md

Build Status Released Version

OpenTracing Java Bridge for Zipkin

This library is a Java bridge between the Brave/Zipkin Api and OpenTracing. It allows its users to write portable (in the OpenTracing sense) instrumentation that's translated into Brave instrumentation transparently.

Required Reading

In order to understand OpenTracing Api, one must first be familiar with the OpenTracing project and terminology more generally.

To understand how Zipkin and Brave work, you can look at Zipkin Architecture and Brave Api documentation.

Setup

Firstly, you need a Tracer, configured to report to Zipkin.

// Configure a reporter, which controls how often spans are sent
//   (the dependency is io.zipkin.reporter2:zipkin-sender-okhttp3)
sender = OkHttpSender.create("http://127.0.0.1:9411/api/v2/spans");
spanReporter = AsyncReporter.create(sender);

// If you want to support baggage, indicate the fields you'd like to
// whitelist, in this case "country-code" and "user-id". On the wire,
// they will be prefixed like "baggage-country-code"
propagationFactory = ExtraFieldPropagation.newFactoryBuilder(B3Propagation.FACTORY)
                                .addPrefixedFields("baggage-", Arrays.asList("country-code", "user-id"))
                                .build();

// Now, create a Brave tracing component with the service name you want to see in Zipkin.
//   (the dependency is io.zipkin.brave:brave)
braveTracing = Tracing.newBuilder()
                      .localServiceName("my-service")
                      .propagationFactory(propagationFactory)
                      .spanReporter(spanReporter)
                      .build();

// use this to create an OpenTracing Tracer
tracer = BraveTracer.create(braveTracing);

// You can later unwrap the underlying Brave Api as needed
braveTracer = tracer.unwrap();

Note: if you haven't updated to a server running the Zipkin v2 api, you can use the old Zipkin format like this:

sender = OkHttpSender.json("http://127.0.0.1:9411/api/v1/spans");
spanReporter = AsyncReporter.builder(sender).build(SpanEncoder.JSON_V1);

Usage

Some example code demonstrating how the OpenTracing Api is to be used.

Code in the first process…

    // start a span
    try ( Span span0 = tracer.buildSpan("span-0")
            .withTag("description", "top level initial span in the original process")
            .start() ) {

        // do something

        // start another span
        try ( Span span1 = tracer.buildSpan("span-1")
                .asChildOf(span0)
                .withTag("description", "the first inner span in the original process")
                .start() ) {

            // do something

            // start another span
            try ( Span span2 = tracer.buildSpan("span-2")
                    .asChildOf(span1)
                    .withTag("description", "the second inner span in the original process")
                    .start() ) {

                // do something

                // cross process boundary
                Map<String,String> map = new HashMap<>();
                tracer.inject(span2.context(), Format.Builtin.HTTP_HEADERS, new TextMapInjectAdapter(map));

                // request.addHeaders(map);
                // request.doGet();
            }
        }
    }

Code in the second process

    // Map<String,String> map = request.getHeaders();

    try ( Span span3 = tracer.buildSpan("span-3")
            .asChildOf(tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapExtractAdapter(map)))
            .withTag("description", "the third inner span in the second process")
            .start() ) {

        // do something

        // start another span
        try ( Span span4 = tracer.buildSpan("span-4")
                .asChildOf(span3)
                .withTag("description", "the fourth inner span in the second process")
                .start() ) {

            // do something

            // cross process boundary
            map = new HashMap<>();
            tracer.inject(span4.context(), Format.Builtin.HTTP_HEADERS, new TextMapInjectAdapter(map));

            // request.addHeaders(map);
            // request.doGet();
        }
    }

This code repeats from process to process, as far through the stack as required.