Zipkin Hapi Instrumentation

raw JSON →
0.22.0 verified Thu Apr 23 auth: no javascript

zipkin-instrumentation-hapi provides middleware for integrating Hapi.js applications with Zipkin for distributed tracing. It enables automatic span creation for incoming requests and outgoing responses, propagating trace context across service boundaries. The current stable version is 0.22.0, released as part of the broader zipkin-js monorepo. Releases appear to be somewhat frequent, often including bug fixes, new transport support (like AWS SQS in v0.21.0), and improvements to instrumentation across various libraries. Key differentiators include its adherence to the OpenZipkin specification and its tight integration within the zipkin-js ecosystem, offering consistent tracing across different frameworks and transport layers.

error Error: Must be valid TraceId instance
cause This error often relates to issues during transpilation or incorrect handling of trace identifiers.
fix
Ensure your build process correctly transpiles the zipkin-js library. This was notably fixed in v0.18.6.
error TypeError: Cannot read properties of undefined (reading 'register')
cause This typically occurs if `hapiInstrumentation` is not properly imported or if the `server.register` call is malformed.
fix
Verify that hapiInstrumentation is correctly imported and that the server.register call adheres to Hapi's plugin registration syntax, including wrapping the plugin in an object { plugin: hapiInstrumentation, options: {...} }.
breaking Node.js 8 support was dropped in version 0.21.0 due to its End-of-Life (EOL). Users on Node.js 8 will not receive updates or fixes.
fix Upgrade Node.js to a supported version (e.g., Node.js 10 or higher).
breaking Node.js 6 support was dropped in version 0.17.1. Applications running on Node.js 6 will fail or encounter issues.
fix Upgrade Node.js to a supported version (e.g., Node.js 8 or higher, preferably 10+).
gotcha When upgrading `zipkin-js` packages, ensure all related `zipkin-instrumentation-*` packages are also updated to compatible versions, as breaking changes in core components can affect instrumentations.
fix Use a consistent version range for all `zipkin-js` related packages, e.g., using `^` or `~` in `package.json`, or explicitly updating all to the latest major release.
gotcha The Hapi instrumentation requires a properly configured `Tracer` instance, which includes a `Recorder` and a `serviceName`. Incorrect configuration can lead to spans not being reported or trace context not propagating.
fix Always initialize `Tracer` with a `recorder` (e.g., `BatchRecorder` or `ConsoleRecorder`) and a descriptive `serviceName`.
breaking Prior to v0.17.1, Hapi 17 support was added. Older versions of the instrumentation may not be fully compatible with Hapi 17+
fix Upgrade `zipkin-instrumentation-hapi` to version 0.17.1 or newer for robust Hapi 17+ compatibility.
npm install zipkin-instrumentation-hapi
yarn add zipkin-instrumentation-hapi
pnpm add zipkin-instrumentation-hapi

This example sets up a basic Hapi server with Zipkin tracing enabled, using `hapiInstrumentation`. It demonstrates configuring a `Tracer` with `BatchRecorder` (for production) or `ConsoleRecorder` (for development), and registering the Hapi plugin. It also includes a basic route and an example of creating a custom child span.

import * as Hapi from '@hapi/hapi';
import { Tracer, BatchRecorder, ConsoleRecorder } from 'zipkin';
import { HttpLogger } from 'zipkin-transport-http';
import { hapiInstrumentation } from 'zipkin-instrumentation-hapi';

const ZIPKIN_URL = process.env.ZIPKIN_URL ?? 'http://localhost:9411';

const recorder = process.env.NODE_ENV === 'production'
  ? new BatchRecorder({
      logger: new HttpLogger({
        endpoint: `${ZIPKIN_URL}/api/v2/spans`,
        headers: { 'Content-Type': 'application/json' }
      })
    })
  : new ConsoleRecorder();

const tracer = new Tracer({
  recorder,
  serviceName: 'my-hapi-service'
});

const init = async () => {
  const server = Hapi.server({
    port: 3000,
    host: 'localhost'
  });

  await server.register({
    plugin: hapiInstrumentation,
    options: { tracer, serviceName: 'my-hapi-service' }
  });

  server.route({
    method: 'GET',
    path: '/hello',
    handler: (request, h) => {
      // Example of custom span creation
      const childSpan = tracer.startSpan('greet-user');
      tracer.scoped(() => {
        tracer.recordServiceName('my-hapi-service');
        tracer.recordRpc('GET');
        tracer.recordAnnotation(new tracer.Annotation.ServerRecv());
        // ... do some work ...
        tracer.recordAnnotation(new tracer.Annotation.ServerSend());
      }, childSpan);
      return 'Hello, Zipkin!';
    }
  });

  await server.start();
  console.log(`Server running on ${server.info.uri}`);
};

process.on('unhandledRejection', (err) => {
  console.log(err);
  process.exit(1);
});

init();