Search code examples
node.jszipkinopencensus

Zipkin (Opencensus) - 2 Spans with same names instead of different


Prerequisites:
Node.js application
Opencensus library
Zipkin Exporter and local Zipkin service

app.js:

    const tracing = require('@opencensus/nodejs');
    const zipkin = require('@opencensus/exporter-zipkin');

    const ZIPKIN_ENDPOINT = process.env.ZIPKIN_ENDPOINT || "http://localhost:9411";

    const options = {
      url: `${ZIPKIN_ENDPOINT}/api/v2/spans`,
      serviceName: 'MyApplication'
    }
    const exporter = new zipkin.ZipkinTraceExporter(options);

    tracing.start({'exporter': exporter});
...

    app.use(..)
...

package.json:

 "dependencies": {
    "@opencensus/exporter-zipkin" : "0.0.19",
    "@opencensus/nodejs" : "0.0.19"
...

Zipkin server started locally with command:

docker run -d -p 9411:9411 openzipkin/zipkin

after triggering /service1 Zipkin Ui displays 2 spans for 2 different requests:
first /service1 incoming request that is configured in Node.js routers
second /external_service_2 is subsequent call to external service

Problem

The problem is that after triggering /service1:
1. Zipkin UI displays 2 spans with same name MyApplication(see image),
but expected 2 different span names
enter image description here

2. As far Zipkin UI displays 2 spans with same name,
service dependencies page contains one Service only(see image) enter image description here


Solution

  • I have tested this with the official opencensus-node example at github.

    Problem 1:

    Zipkin UI displays 2 spans with same name MyApplication(see image), but expected 2 different span names

    Just to be clear, MyApplication is the service name you set in your app.js, and the span names are those which you selected on the image /service1, /service1, /external_service_2.

    I think this is the intended behavior, you got one service (MyApplication), a root span (/service1) and a child span (/external_service_2). If you got multiple services connected to the same Zipkin server then you'll have multiple names for the services.

    OpenCensus example

    From the Zipkin's documentation:

    Span

    A set of Annotations and BinaryAnnotations that correspond to a particular RPC. Spans contain identifying information such as traceId, spanId, parentId, and RPC name.

    Trace

    A set of spans that share a single root span. Traces are built by collecting all Spans that share a traceId. The spans are then arranged in a tree based on spanId and parentId thus providing an overview of the path a request takes through the system.

    Problem 2:

    As far Zipkin UI displays 2 spans with same name, service dependencies page contains one Service only(see image)

    Again, this is the intended behavior, since you got only one service and the external request you made goes through it.

    Change span names:

    If you mean the framed names on the first image, at the top it shows only the root span you clicked on the previous screen. However, you can write custom span names after a little change in your code.

    From the tracing documentation (with your code):

    const options = {
      url: `${ZIPKIN_ENDPOINT}/api/v2/spans`,
      serviceName: 'MyApplication'
    }
    const tracer = tracing.start({samplingRate: 1}).tracer;
    tracer.registerSpanEventListener(new zipkin.ZipkinTraceExporter(options));
    

    Now you can use tracer.startRootSpan, I used it in the express sample with a request:

    tracer.startRootSpan({name: 'main'}, rootSpan => {
      rp('http://localhost:3000/sample').then(data => {
        res.send(data);
        rootSpan.end();
      }, err => {
        console.error(`${err.message}`);
        rootSpan.end();
      });
    });
    

    A span must be closed.

    For more information, check the test file of the tracer.