Zipkin JS

repository·master·Indexed 20 days ago

https://github.com/openzipkin/zipkin-js

A collection of libraries for instrumenting Node.js and browser applications for distributed tracing. Includes the core zipkin package, context management via zipkin-context-cls (supporting CLS and async/await), and instrumentation packages for axios (zipkin-instrumentation-axiosjs), Connect/Express/Restify (zipkin-instrumentation-connect), the rest client (zipkin-instrumentation-cujojs-rest), Express middleware and HTTP Proxy (zipkin-instrumentation-express), and the Fetch API (zipkin-instrumentation-fetch).

Tokens
37.2K
Snippets
124
Records
146
Agent score
68%

What's inside zipkin-js

  1. Instrument request and request-promise with Zipkin

    master
    The zipkin-instrumentation-request-promise library adds Zipkin tracing to the request and request-promise libraries. It provides two ways to instrument your requests: a functional approach using wrapRequest and an object-oriented approach using the Request class. Internally, wrapRequest is a wrapper around the Request class, so they provide identical functionality.
  2. How CLSContext works

    master

    When you instantiate CLSContext('zipkin'), the package creates a namespace named 'zipkin' if it doesn't exist. Within this namespace, it sets the context using the key 'zipkin'.

    The namespace is tied to the specific call-chain. Data stored within that namespace is unique to that specific request and call-chain, ensuring that context is not overwritten across different concurrent requests.

  3. How explicit and implicit context work in Node.js

    master

    In Node.js, because of the non-blocking event loop, multiple operations happen concurrently. To correlate these operations to a specific trace, you must choose between two context models:

    1. Explicit Context: You manually pass a context object (ctx) through every layer of your application (e.g., from the HTTP handler down to the database client).
    2. Implicit Context: The context is managed transparently in the background, so you don't need to pass objects manually. In Node.js, this is typically achieved using zipkin-context-cls (Continuation Local Storage).
  4. Use Axios interceptors with Zipkin instrumentation

    master

    The instrumentation is compatible with standard Axios interceptors. You can add request or response interceptors to the wrapped instance to modify configurations or handle data before or after the tracing logic executes.

    // Add a request interceptor to the wrapped instance
    zipkinAxios.interceptors.request.use(function (config) {
        // Do something before request is sent
        return config;
      }, function (error) {
        // Do something with request error
        return Promise.reject(error);
      });
    
    // Add a response interceptor to the wrapped instance
    zipkinAxios.interceptors.response.use(function (response) {
        // Do something with response data
        return response;
      }, function (error) {
        // Do something with response error
        return Promise.reject(error);
      });
  5. Instrument a gRPC client with Zipkin

    master

    To instrument a gRPC client for Zipkin tracing, use the zipkin-instrumentation-grpc-client library to create a gRPC interceptor. This interceptor requires a Zipkin Tracer instance and the name of the remote service you are calling (remoteServiceName).

    When making a gRPC call, pass the interceptor in the interceptors array within the call options object.

    const grpc = require('grpc');
    const {Tracer, ExplicitContext, ConsoleRecorder} = require('zipkin');
    const grpcInstrumentation = require('zipkin-instrumentation-grpc-client');
    
    // 1. Setup Zipkin tracer
    const ctxImpl = new ExplicitContext();
    const recorder = new ConsoleRecorder();
    const localServiceName = 'service-a';
    const tracer = new Tracer({ctxImpl, recorder, localServiceName});
    
    // 2. Setup gRPC client (example setup)
    // ... (load proto and create client) ...
    const client = new weather.WeatherService('localhost:50051', grpc.credentials.createInsecure());
    
    // 3. Create the interceptor
    const remoteServiceName = 'weather-service';
    const interceptor = grpcInstrumentation(grpc, {tracer, remoteServiceName});
    
    // 4. Use the interceptor in a call
    client.getTemperature({ location: 'Tahoe'}, { interceptors: [interceptor] }, (error, response) => {
        console.info(`temprature in Tahoe is: ${response.temperature} `);
    });
  6. Instrument the request library with Zipkin

    master

    To add Zipkin tracing to the request library, use wrapRequest from zipkin-instrumentation-request. This function wraps the standard request module and requires a Zipkin Tracer instance and a remoteServiceName string. The wrapped function behaves identically to the original request function but automatically handles trace propagation and span creation for outgoing requests.

    const express = require('express');
    const {Tracer, ExplicitContext, ConsoleRecorder} = require('zipkin');
    const wrapRequest = require('zipkin-instrumentation-request');
    const request = require('request');
    
    const ctxImpl = new ExplicitContext();
    const recorder = new ConsoleRecorder();
    const localServiceName = 'service-a'; // name of this application
    const tracer = new Tracer({ctxImpl, recorder, localServiceName});
    
    const remoteServiceName = 'weather-api';
    const zipkinRequest = wrapRequest(request, {tracer, remoteServiceName});
    
    zipkinRequest({
        url: 'http://api.weather.com',
        method: 'GET',
      }, function(error, response, body) {
        console.log('error:', error);
        console.log('statusCode:', response && response.statusCode);
        console.log('body:', body);
      });
  7. Instrument axios using wrapAxios

    master

    Use the wrapAxios function to wrap either the global axios module or a specific axios instance. The resulting zipkinAxios object retains all original axios types, functions, and attributes, allowing it to be used interchangeably with the standard axios API.

    To instrument, provide an options object containing:

    • tracer: An instance of a Zipkin Tracer.
    • remoteServiceName (optional): The name of the remote application being called.
    const axios = require('axios');
    const wrapAxios = require('zipkin-instrumentation-axiosjs');
    const { Tracer, ExplicitContext, ConsoleRecorder } = require('zipkin');
    
    const ctxImpl = new ExplicitContext();
    const recorder = new ConsoleRecorder();
    const localServiceName = 'service-a';
    const tracer = new Tracer({ ctxImpl, recorder, localServiceName });
    
    const remoteServiceName = 'weather-api';
    const zipkinAxios = wrapAxios(axios, { tracer, remoteServiceName });
    
    // Use it just like axios
    zipkinAxios.get('/user?ID=12345')
      .then(function (response) {
        console.log(response);
      })
      .catch(function (error) {
        console.log(error);
      });
  8. Add Zipkin tracing to Express applications using middleware

    master

    Use the expressMiddleware function from zipkin-instrumentation-express to add Zipkin tracing to your Express application. This middleware requires a tracer instance (from the zipkin package) to manage trace context and recording.

    const express = require('express');
    const {Tracer, ExplicitContext, ConsoleRecorder} = require('zipkin');
    const zipkinMiddleware = require('zipkin-instrumentation-express').expressMiddleware;
    
    const ctxImpl = new ExplicitContext();
    const recorder = new ConsoleRecorder();
    const localServiceName = 'service-a'; // name of this application
    const tracer = new Tracer({ctxImpl, recorder, localServiceName});
    
    const app = express();
    
    // Add the Zipkin middleware
    app.use(zipkinMiddleware({tracer}));
  9. Enable async/await support in CLSContext

    master

    By default, CLSContext is not suitable for code that uses Promises. To enable experimental support for async/await and Promises, you can pass true as the second argument to the CLSContext constructor. This enables an implementation using the cls_hooked library (which utilizes Node.js async_hooks).

    Warning: Using async_hooks may have performance implications depending on your Node.js version.

    const CLSContext = require('zipkin-context-cls');
    const tracer = new Tracer({
      ctxImpl: new CLSContext('zipkin', true),
      recorder,
      localServiceName: 'service-a'
    });
  10. Basic Setup of a Zipkin Tracer

    master

    To start tracing, instantiate a zipkin.Tracer. The tracer requires a context implementation (ctxImpl), a recorder to send spans, a sampler to determine the sampling rate, and a localServiceName to identify your service in the trace graph.

    Common configuration options:

    • ctxImpl: The in-process context implementation (e.g., zipkin-context-cls for Node.js or zipkin.ExplicitContext for manual passing).
    • recorder: An implementation that handles sending spans (e.g., zipkin.ConsoleRecorder for debugging).
    • sampler: A strategy to decide which requests to trace (e.g., zipkin.sampler.CountingSampler).
    • traceId128Bit: Boolean; set to true to use 128-bit trace IDs instead of the default 64-bit.
    const zipkin = require('zipkin');
    const CLSContext = require('zipkin-context-cls');
    const ctxImpl = new CLSContext();
    
    const tracer = new zipkin.Tracer({
      ctxImpl,
      recorder: new zipkin.ConsoleRecorder(),
      sampler: new zipkin.sampler.CountingSampler(0.01),
      traceId128Bit: true,
      localServiceName: 'my-service'
    });
  11. Instrument a Memcached client with Zipkin

    master

    To add Zipkin tracing to your memcached client, use zipkin-instrumentation-memcached. This library wraps the standard memcached client and requires a Zipkin Tracer instance.

    To use it, pass your tracer and the Memcached constructor to the zipkin-instrumentation-memcached function. This returns a wrapped constructor that you can use to instantiate your client as usual.

    const {Tracer} = require('zipkin');
    const Memcached = require('memcached');
    const zipkinClient = require('zipkin-instrumentation-memcached');
    
    const localServiceName = 'service-a'; // name of this application
    const tracer = new Tracer({ctxImpl, recorder, localServiceName});
    
    const connectionString = 'localhost:11211';
    const options = {timeout: 1000};
    
    // Wrap the Memcached constructor with the tracer
    const memcached = new (zipkinClient(tracer, Memcached))(connectionString, options);
    
    // Your application code here
    memcached.get('foo', (err, data) => {
      console.log('got', data.foo);
    });