UNPKG

autotel

Version:
170 lines (166 loc) 5.19 kB
import { context } from '@opentelemetry/api'; /** * HTTP Instrumentation Helpers * * Optional import: Not included in main bundle * Import from: 'autotel/http' * * Provides decorators and utilities for HTTP client instrumentation. * Works with fetch, axios, and other HTTP clients. * * @example * ```typescript * import { HttpInstrumented } from 'autotel/http' * * @HttpInstrumented() * class ApiClient { * async getUser(id: string) { * return fetch(`/api/users/${id}`) * } * } * ``` */ interface HttpInstrumentedOptions { /** Service name for HTTP calls (default: 'http-client') */ serviceName?: string; /** Extract URL from method arguments (default: first arg) */ urlExtractor?: (args: unknown[]) => string | undefined; /** Extract HTTP method from method name or args */ methodExtractor?: (methodName: string, args: unknown[]) => string; /** Add custom attributes to spans */ attributesFromArgs?: (args: unknown[]) => Record<string, string | number>; /** Slow request threshold in milliseconds (adds warning attribute) - default: 3000ms */ slowRequestThresholdMs?: number; } /** * Decorator for auto-instrumenting HTTP client methods * * @example Basic usage * ```typescript * @HttpInstrumented() * class ApiClient { * async fetchUser(userId: string) { * const res = await fetch(`https://api.example.com/users/${userId}`) * return res.json() * } * * async createOrder(order: Order) { * const res = await fetch('https://api.example.com/orders', { * method: 'POST', * body: JSON.stringify(order) * }) * return res.json() * } * } * ``` * * @example Advanced usage with custom extractors * ```typescript * @HttpInstrumented({ * serviceName: 'payment-gateway', * urlExtractor: (args) => { * const config = args[0] as RequestConfig * return config.url * }, * attributesFromArgs: (args) => ({ * 'http.request_id': args[0]?.requestId, * 'http.retry_count': args[0]?.retryCount || 0 * }) * }) * class PaymentClient { * async charge(config: RequestConfig) { * return axios(config) * } * } * ``` */ declare function HttpInstrumented(options?: HttpInstrumentedOptions): <T extends { new (...args: any[]): {}; }>(target: T, _context: ClassDecoratorContext) => { new (...args: any[]): {}; } & T; /** * Helper: Trace a single HTTP request * * @example * ```typescript * import { traceHttpRequest } from 'autotel/http' * * const data = await traceHttpRequest( * 'GET /api/users', * () => fetch('https://api.example.com/users') * ) * ``` */ declare function traceHttpRequest<T>(spanName: string, fn: () => Promise<T>, attributes?: Record<string, string | number>): Promise<T>; /** * Inject trace context into HTTP headers (for distributed tracing) * * This includes W3C Trace Context (traceparent, tracestate) and W3C Baggage headers. * Uses OpenTelemetry's propagation system for full compatibility. * * @example * ```typescript * import { injectTraceContext } from 'autotel/http' * * const headers = injectTraceContext({ * 'Content-Type': 'application/json' * }) * * fetch('/api/users', { headers }) * ``` * * @example With baggage * ```typescript * import { trace, withBaggage, injectTraceContext } from 'autotel' * * export const createOrder = trace((ctx) => async (order: Order) => { * return await withBaggage({ * baggage: { 'tenant.id': order.tenantId }, * fn: async () => { * const headers = injectTraceContext(); * // Headers now include 'baggage' header with tenant.id * await fetch('/api/charge', { headers }); * }, * }); * }); * ``` */ declare function injectTraceContext(headers?: Record<string, string>): Record<string, string>; /** * Extract trace context from HTTP headers (for distributed tracing) * * This extracts W3C Trace Context (traceparent, tracestate) and W3C Baggage headers. * Uses OpenTelemetry's propagation system for full compatibility. * * Returns a context that can be used with context.with() to run code * with the extracted trace context and baggage. * * @example * ```typescript * import { extractTraceContext, trace } from 'autotel' * import { context } from 'autotel' * * // In Express middleware * app.use((req, res, next) => { * const extractedContext = extractTraceContext(req.headers); * context.with(extractedContext, () => { * next(); * }); * }); * ``` * * @example In a traced function * ```typescript * export const handleWebhook = trace((ctx) => async (req: Request) => { * const extractedContext = extractTraceContext(req.headers); * return await context.with(extractedContext, async () => { * // Now ctx.getBaggage() will return baggage from the incoming request * const tenantId = ctx.getBaggage('tenant.id'); * await processWebhook(req.body); * }); * }); * ``` */ declare function extractTraceContext(headers: Record<string, string | string[] | undefined>): ReturnType<typeof context.active>; export { HttpInstrumented, type HttpInstrumentedOptions, extractTraceContext, injectTraceContext, traceHttpRequest };