zipkin-lite

0.1.1 • Public • Published

zipkin-lite

This is a very basic implementation of Zipkin for Node.js. It is currently intended for educational use, not for use in production.

It was created for use with “Distributed Node.js”, a book that hasn't yet been published. The goal is to require manual instrumentation to help users understand the Zipkin concept, require no third party dependencies, and provide an idiomatic Node.js interface.

For a production project, consider using the official zipkin npm module.

Note that currently this module only works with Fastify. It could very easily work with other servers (PRs appreciated) but in its current state it does not.

Usage

See server-deep.js, server-middle.js and server-shallow.js for example usage.

const Zipkin = require('zipkin-lite');
const zipkin = new Zipkin({
  zipkinHost: 'localhost:9411',
  serviceName: 'shallow-api',
  servicePort: PORT,
  serviceIp: HOST,
 
  // these three flags are required for "shallow" services
  sampleRate: 0.5,
  init: 'long', // 'long' | 'short' | false
  debug: true
});
 
const server = require('fastify')();
const fetch = require('node-fetch');
 
// Enable incoming request hooks
server.addHook('onRequest', zipkin.onRequest());
server.addHook('onResponse', zipkin.onResponse());
 
server.get('/widgets/:id', async (req, reply) => {
  console.log('CURRENT TRACE ID:', req.zipkin.trace);
  req.zipkin.setName('get_widget');
 
  // ...
 
  // Each outbound request requires prepare/complete calls
  const zreq = req.zipkin.prepare();
  const url = 'http://localhost:3003/deep/42';
  const result = await fetch(url, { headers: zreq.headers }); // pass headers
  zreq.complete('GET', url);
 
  // ...
 
  return result.text();
});
 
server.listen(PORT, HOST);

This example shows how to use a majority of the zipkin-lite features within an application. This code represents a service which is able to generate the initial traceId value for subsequent requests.

An instance of the Zipkin class, exported when requiring the zipkin-line module, needs to be configured and instantiated before being used. The following configuration flags are accepted:

Property Default Description
zipkinHost localhost:9411 The host and port of the Zipkin collection service
serviceName N/A The name of the currently running service
servicePort N/A The port of the service (as seen by clients)
serviceIp N/A The IP Address of the service (as seen by clients)
sampleRate 1 The rate at which request are logged to Zipkin
init false If this is a shallow service that should generate Trace IDs
debug false Whether the traces should pass debug flags to deeper services

Unfortunately, Zipkin requires IP addresses for logging; hostnames won't work. For that reason we need to specify the service's IP address. Both the IP address and the port should be what's used on the network, not necessarily what the service itself uses. For example, if your service lives inside a Docker container, and listens on 127.0.0.1:80, but Docker rewrites the ports, then the real value might be something like 192.168.20.10:12345.

The init value can be set to long to use 32 character IDs, short to use 16 character IDs, or false to be disabled entirely. true is an alias for short.

The onRequest and onResponse hooks are required to extend the req object, and to capture and report the timing information for the incoming request. The incoming request object is modified to have an added property, available at req.zipkin. This object has the following shape:

{
  // The start time of the request with pseudo-microsecond precision
  start: 1579463188658000,
 
  // The incoming Zipkin-related headers (you shouldn't need these)
  headers: {
    traceId: '64273ad10379e27f6ef33242096297fc',
    spanId: 'aba861e477551efc',
    parentSpanId: '936313062d7e3496',
    sampled: '0',
    flags: undefined
  },
 
  // Whether this is a debug request (if so, increase logging verbosity)
  debug: false,
 
  // Whether this request is being sent to the Zipkin server
  sampled: false,
 
  // The Trace ID for this and related requests. Use it in log messages for grouping
  trace: '64273ad10379e27f6ef33242096297fc',
 
  // Set the "name" of an endpoint, like "GET /widget/:id" could be "get_widget"
  setName(name),
 
  // A method to prepare a new outgoing request. Call once for each outgoing request.
  prepare()
}

Once you call the req.zipkin.prepare() method, a timing value will be captured and a new object will be returned.

This returned object represents an outgoing Zipkin request. It has a headers property, which is an object representing headers. These headers need to be passed into your outgoing request library and is how Zipkin data is propagated to upstream services.

The outgoing Zipin request object also has a complete(method, url) method attached. Call this method once the request to the outgoing service is complete. Once called, the method will send a message to the Zipkin service, containing information about the client request. The url argument is parsed and used by Zipkin, along with method, to describe the request.

Testing

Currently, this module can be tested by running the three included service instances, running Zipkin in a Docker container, and making a request to the shallowest of services. Such a flow looks like the following:

$ docker run -p 9411:9411 \
  -it --name distnode-zipkin \
  openzipkin/zipkin-slim:2.19
$ server-deep.js
$ server-middle.js
$ server-shallow.js
$ curl http://localhost:3001/

Unfortunately, I don't currently have the time to build a full test suite.

Supported Features

  • Transporting traces via HTTP
  • Generating initial TraceIDs
  • Extracting incoming Zipkin request headers for outgoing requests
  • Long and Short TraceID
  • Sampling
  • Debug flag

Unsupported Features

  • Transports for anything other than HTTP, e.g. gRPC
  • Batching of spans before transmitting
  • X-Forwarded-For / proxy IP address parsing
  • Blocking of outside zipkin headers for initial request (e.g. for bad actors)
  • Microsecond accuracy (uses millisecond * 1000)
  • Single b3 header mode (only multi-header support)
  • User-supplied tags (only opinionated http.method and http.path are supported)

Readme

Keywords

Package Sidebar

Install

npm i zipkin-lite

Weekly Downloads

2

Version

0.1.1

License

BSD-2-Clause

Unpacked Size

19.6 kB

Total Files

6

Last publish

Collaborators

  • tlhunter