Tracing a Node.js micro-service with OCI Application Performance Monitoring (APM) AND Zipkin


OCI Application Performance Monitoring provides a comprehensive set of features to monitor applications and diagnose performance issues.

Application Performance Monitoring integrates with open-source tracing system tools (open-source tracers) such as Jaeger and Zipkin and enables you to upload trace data. It also supports context propagation between Application Performance Monitoring agents and open-source tracers.

STEP 1: Configure APM

Go to APM->Administration, click in [Create APM Domain] button and provide the information requested in popup window.

STEP 2: Grab domain details

In the APM domain details you created, get the [Data Upload Endpoint] URL and the auto_generated_public_datakey values, we’ll need them in step 3

STEP 3: Configure your Node.js app

Follow steps here to configure Zipkin in your app. Here the doco from OCI APM with detailled instructions for the OCI part. If you want to use an example use this, it is the code we are going to use for this post. Clone the repo and edit file web/recorder.js by adding the code in bold and removing the text

/* eslint-env browser */
const {
  BatchRecorder,
  jsonEncoder: {JSON_V2}
} = require('zipkin');
const {HttpLogger} = require('zipkin-transport-http');
const CLSContext = require('zipkin-context-cls');

const debug = 'undefined' !== typeof window
  ? window.location.search.indexOf('debug') !== -1
  : process.env.DEBUG;

// Send spans to Zipkin asynchronously over HTTP
const zipkinBaseUrl = 'http://localhost:9411';

// data upload endpoint example is something like https://aaaa...aaapi.apm-agt.eu-frankfurt-1.oci.oraclecloud.com/20200101/observations/public-span?dataFormat=zipkin&dataFormatVersion=2&dataKey=QM...3D

const httpLogger = new HttpLogger({
  endpoint: '<domain data upload endpoint in step 2>/20200101/observations/public-span?dataFormat=zipkin&dataFormatVersion=2&dataKey=<public data key in step 2>',
  jsonEncoder: JSON_V2
})

const httpLogger = new HttpLogger({
  endpoint: `${zipkinBaseUrl}/api/v2/spans`,
  jsonEncoder: JSON_V2
});

// Setup the tracer
const tracer = new Tracer({
  ctxImpl: new CLSContext('zipkin'), // implicit in-process context
  recorder: new BatchRecorder({
    logger: httpLogger
  }), // batched http recorder
  localServiceName: 'mytest', // name of this application
  supportsJoin: false //Span join disable setting
});

function recorder(serviceName) {
  return debug ? debugRecorder(serviceName) : new BatchRecorder({logger: httpLogger});
}

function debugRecorder(serviceName) {
  // This is a hack that lets you see the data sent to Zipkin!
  const logger = {
    logSpan: (span) => {
      const json = JSON_V2.encode(span);
      console.log(`${serviceName} reporting: ${json}`);
      httpLogger.logSpan(span);
    }
  };

  const batchRecorder = new BatchRecorder({logger});

  // This is a hack that lets you see which annotations become which spans
  return ({
    record: (rec) => {
      const {spanId, traceId} = rec.traceId;
      console.log(`${serviceName} recording: ${traceId}/${spanId} ${rec.annotation.toString()}`);
      batchRecorder.record(rec);
    }
  });
}
module.exports.recorder = recorder; 

STEP 4: Restart your node app

STEP 5: APM TRACE EXPLORER

Go to APM Trace explorer and run a query

Traces can be observed in the list

That’s all, hope it helps!! 🙂

2 Comments

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.