autotel
Version:
Write Once, Observe Anywhere
170 lines (166 loc) • 5.19 kB
text/typescript
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 };