autotel
Version:
Write Once, Observe Anywhere
235 lines (231 loc) • 6.96 kB
TypeScript
import { AttributeValue, SpanContext } from '@opentelemetry/api';
import { ConsumerContext, ProducerContext } from './messaging.js';
import './trace-context-t5X1AP-e.js';
/**
* Pre-built adapter configurations for common messaging systems.
*
* These adapters provide ready-to-use hook configurations for systems
* not explicitly supported by the core messaging module. Use them with
* traceProducer/traceConsumer to get system-specific attributes.
*
* @example NATS consumer
* ```typescript
* import { traceConsumer } from 'autotel/messaging';
* import { natsAdapter } from 'autotel/messaging/adapters';
*
* const processMessage = traceConsumer({
* system: 'nats',
* destination: 'orders',
* ...natsAdapter.consumer,
* })(ctx => async (msg) => {
* // msg.subject, msg.info.stream are now captured as span attributes
* await handleOrder(msg.data);
* });
* ```
*
* @example Datadog context propagation
* ```typescript
* import { traceConsumer } from 'autotel/messaging';
* import { datadogContextExtractor } from 'autotel/messaging/adapters';
*
* const processMessage = traceConsumer({
* system: 'kafka',
* destination: 'events',
* customContextExtractor: datadogContextExtractor,
* })(ctx => async (msg) => {
* // Parent span from Datadog trace headers is linked
* });
* ```
*
* @module
*/
/**
* Producer adapter configuration
*/
interface ProducerAdapter {
/**
* Hook to add system-specific attributes to producer spans
*/
customAttributes?: (ctx: ProducerContext, args: unknown[]) => Record<string, AttributeValue>;
/**
* Hook to inject custom headers beyond W3C traceparent
*/
customHeaders?: (ctx: ProducerContext) => Record<string, string>;
}
/**
* Consumer adapter configuration
*/
interface ConsumerAdapter {
/**
* Extract headers from the message for trace context propagation
*/
headersFrom?: (msg: unknown) => Record<string, string> | undefined;
/**
* Hook to add system-specific attributes to consumer spans
*/
customAttributes?: (ctx: ConsumerContext, msg: unknown) => Record<string, AttributeValue>;
/**
* Hook to extract parent span context from non-W3C header formats
*/
customContextExtractor?: (headers: Record<string, string>) => SpanContext | null;
}
/**
* Combined producer and consumer adapter
*/
interface MessagingAdapter {
producer?: ProducerAdapter;
consumer?: ConsumerAdapter;
}
/**
* NATS JetStream adapter
*
* Captures NATS-specific attributes following NATS observability conventions.
*
* @example Producer
* ```typescript
* const publishOrder = traceProducer({
* system: 'nats',
* destination: 'orders.created',
* ...natsAdapter.producer,
* })(ctx => async (subject, payload, opts) => {
* const headers = ctx.getTraceHeaders();
* await nc.publish(subject, payload, { headers });
* });
* ```
*
* @example Consumer
* ```typescript
* const processOrder = traceConsumer({
* system: 'nats',
* destination: 'orders.created',
* consumerGroup: 'order-processor',
* ...natsAdapter.consumer,
* })(ctx => async (msg: JsMsg) => {
* await handleOrder(msg.data);
* msg.ack();
* });
* ```
*/
declare const natsAdapter: MessagingAdapter;
/**
* Temporal adapter
*
* Captures Temporal-specific attributes for workflow activities.
* Use this when instrumenting Temporal activity handlers.
*
* @example Activity handler
* ```typescript
* const processOrder = traceConsumer({
* system: 'temporal',
* destination: 'order-activities',
* ...temporalAdapter.consumer,
* })(ctx => async (info: ActivityInfo, input: OrderInput) => {
* // Temporal attributes are captured automatically
* return processOrderLogic(input);
* });
* ```
*
* @example Workflow signal/query
* ```typescript
* const sendSignal = traceProducer({
* system: 'temporal',
* destination: 'order-signals',
* ...temporalAdapter.producer,
* })(ctx => async (workflowId, signalName, payload) => {
* await client.workflow.signal(workflowId, signalName, payload);
* });
* ```
*/
declare const temporalAdapter: MessagingAdapter;
/**
* Cloudflare Queues adapter
*
* Captures Cloudflare Queue-specific attributes.
*
* @example Queue consumer
* ```typescript
* export default {
* async queue(batch: MessageBatch, env: Env) {
* for (const msg of batch.messages) {
* await processMessage(msg);
* }
* },
* };
*
* const processMessage = traceConsumer({
* system: 'cloudflare_queues',
* destination: 'my-queue',
* ...cloudflareQueuesAdapter.consumer,
* })(ctx => async (msg: Message) => {
* await handleMessage(msg.body);
* msg.ack();
* });
* ```
*/
declare const cloudflareQueuesAdapter: MessagingAdapter;
/**
* Datadog trace context extractor
*
* Extracts parent span context from Datadog-format trace headers.
* Converts Datadog's decimal IDs to OpenTelemetry's hex format.
*
* Note: Datadog sends trace/span IDs as decimal strings, not hex.
* This extractor converts decimal -> hex before formatting for OTel.
*
* @example
* ```typescript
* const processMessage = traceConsumer({
* system: 'kafka',
* destination: 'events',
* customContextExtractor: datadogContextExtractor,
* })(ctx => async (msg) => {
* // Links to parent Datadog span automatically
* });
* ```
*/
declare function datadogContextExtractor(headers: Record<string, string>): SpanContext | null;
/**
* B3 (Zipkin) trace context extractor
*
* Extracts parent span context from B3 format headers.
* Supports both single-header (b3) and multi-header formats.
*
* @see https://github.com/openzipkin/b3-propagation
*
* @example Single-header format
* ```typescript
* // Header: b3: 80f198ee56343ba864fe8b2a57d3eff7-e457b5a2e4d86bd1-1
* const processMessage = traceConsumer({
* system: 'rabbitmq',
* destination: 'events',
* customContextExtractor: b3ContextExtractor,
* })(ctx => async (msg) => {
* // Links to parent Zipkin span
* });
* ```
*
* @example Multi-header format
* ```typescript
* // Headers: X-B3-TraceId, X-B3-SpanId, X-B3-Sampled
* ```
*/
declare function b3ContextExtractor(headers: Record<string, string>): SpanContext | null;
/**
* AWS X-Ray trace context extractor
*
* Extracts parent span context from AWS X-Ray trace header.
* Format: Root=1-{timestamp}-{random};Parent={parent-id};Sampled={0|1}
*
* @example
* ```typescript
* const processMessage = traceConsumer({
* system: 'sqs',
* destination: 'my-queue',
* customContextExtractor: xrayContextExtractor,
* })(ctx => async (msg) => {
* // Links to parent X-Ray trace
* });
* ```
*/
declare function xrayContextExtractor(headers: Record<string, string>): SpanContext | null;
export { type ConsumerAdapter, type MessagingAdapter, type ProducerAdapter, b3ContextExtractor, cloudflareQueuesAdapter, datadogContextExtractor, natsAdapter, temporalAdapter, xrayContextExtractor };