rouvy-observability-js v1.0.0
rouvy-observability-js
Provides tooling to reconstruct Datadog tracing context from Pub/Sub message attributes on the subscriber side. It lets you restore a trace in Node.js services so that Datadog sees the entire flow across service boundaries.
Installation
Install the package (and also
dd-trace
if not already installed):npm install --save rouvy-observability-js dd-trace
or
yarn add rouvy-observability-js
Initialize The tracing would work with the
./datadog-init
initialization, but```javascript const tracer = require('dd-trace').init({ // your dd-trace config }); ```
Publisher Usage
If automatic tracing is configured, datadog automatically injects attributes of PubSub message with Trace Context information. Hence no further configuration is needed.
Subscriber Usage
Reconstruction of the context obtained through Pub/Sub have to be configured. There are two main approaches:
1. Decorator: asyncTracePubsubDecorator
const { asyncTracePubsubDecorator } = require('rouvy-observability-js');
class PubSubHandler {
// Apply the decorator
@asyncTracePubsubDecorator({ resourceName: "/pubsub", topicName: "pubsub-topic" })
async handlePubSubMessage(ctx) {
// Your message-handling logic
return null;
}
}
// Instantiate the handler and use it to serve the /pubsub endpoint
const pubSubHandler = new PubSubHandler();
router.post("/pubsub", pubSubHandler.handlePubSubMessage);
In order for the decorator to work, tsconfig.json
has to be configured correctly. In the compilerOptions
objects, following attributes have to be set:
{
"compilerOptions": {
"target": "ES6", // Target has to be at least ES6 or newer
"experimentalDecorators": true, // Enable legacy decorators
"emitDecoratorMetadata": true, // Emit metadata for decorators
"useDefineForClassFields": false, // Use legacy field initialization
}
}
2. Higher-Order Function: asyncTracePubsubEndpoint
const tracedHandler = asyncTracePubsubEndpoint(handlePubSubMessage, { resourceName: "/pubsub", topicName: "pubsub-topic" });
router.post("/pubsub", tracedHandler)
3. Extraction of Pub/Sub Attributes
The rouvy-observability-js package provides flexibility in extracting tracing attributes from incoming messages. By default, it attempts to extract attributes from a predefined structure. However, you can define a custom extraction function to accommodate different message formats.
Default Extraction Logic:
The default extraction function targets the first argument (args0) and expects it to have the following structure:
interface CustomContext {
request: {
body?: {
message?: {
attributes?: Record<string, string>;
};
};
};
}
And the default extraction function is:
function customExtractAttributes(args: unknown[]): Record<string, string> | null {
const ctx = args[0] as { data?: { headers?: Record<string, string> } };
return ctx?.data?.headers || null;
}
You can define your very own function to extract the attributes, based on the needs of your function.
function.
Both asyncTracePubsubDecorator
and asyncTracePubsubEndpoint
can optionally be provided with such function.
import { asyncTracePubsubEndpoint, asyncTracePubsubDecorator } from 'rouvy-observability-js';
async function handleMessage(ctx: any): Promise<void> {
// Your message handling logic
}
const tracedHandler = asyncTracePubsubEndpoint(handleMessage, { resourceName: '/pubsub1' , topicName: "pubsub-topic"}, customExtractAttributes);
router.post("/pubsub1", pubSubHandler.handlePubSubMessage);
// Or
class PubSubHandler {
@asyncTracePubsubDecorator({ resourceName: "/pubsub2", topicName: "pubsub-topic" }, customExtractAttributes)
async handlePubSubMessage(ctx) {
// Your message-handling logic
return null;
}
}
const pubSubHandler = new PubSubHandler();
router.post("/pubsub2", pubSubHandler.handlePubSubMessage);
DataDog references: