UNPKG

autotel

Version:
1 lines 8.54 kB
{"version":3,"sources":["../src/span-name-normalizer.ts"],"names":[],"mappings":"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","file":"chunk-IOYFAFHJ.cjs","sourcesContent":["/**\n * Span Name Normalizer\n *\n * Normalizes span names to reduce cardinality from dynamic path segments.\n * This is critical for observability backends that charge by unique span names\n * or have cardinality limits.\n *\n * @example Basic usage with custom function\n * ```typescript\n * init({\n * service: 'my-app',\n * spanNameNormalizer: (name) => {\n * return name.replace(/\\/[0-9]+/g, '/:id');\n * }\n * })\n * ```\n *\n * @example Using built-in preset\n * ```typescript\n * init({\n * service: 'my-app',\n * spanNameNormalizer: 'rest-api'\n * })\n * ```\n */\n\nimport type {\n SpanProcessor,\n ReadableSpan,\n} from '@opentelemetry/sdk-trace-base';\nimport type { Context } from '@opentelemetry/api';\nimport type { Span } from '@opentelemetry/sdk-trace-base';\n\n/**\n * Function to normalize a span name\n * @param name - The original span name\n * @returns The normalized span name\n */\nexport type SpanNameNormalizerFn = (name: string) => string;\n\n/**\n * Built-in normalizer preset names\n */\nexport type SpanNameNormalizerPreset = 'rest-api' | 'graphql' | 'minimal';\n\n/**\n * Normalizer config - either a function or a preset name\n */\nexport type SpanNameNormalizerConfig =\n | SpanNameNormalizerFn\n | SpanNameNormalizerPreset;\n\nexport interface SpanNameNormalizingProcessorOptions {\n /**\n * Normalizer function or preset name\n */\n normalizer: SpanNameNormalizerConfig;\n}\n\n/**\n * Built-in normalizer patterns\n */\nconst NORMALIZER_PATTERNS = {\n // Numeric IDs: /users/123 → /users/:id\n numericId: /\\/\\d+(?=\\/|$)/g,\n\n // UUIDs: /users/550e8400-e29b-41d4-a716-446655440000 → /users/:uuid\n uuid: /\\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?=\\/|$)/gi,\n\n // Short UUIDs (without dashes): /users/550e8400e29b41d4a716446655440000 → /users/:uuid\n shortUuid: /\\/[0-9a-f]{32}(?=\\/|$)/gi,\n\n // MongoDB ObjectIds: /docs/507f1f77bcf86cd799439011 → /docs/:objectId\n objectId: /\\/[0-9a-f]{24}(?=\\/|$)/gi,\n\n // Hashes (6+ hex chars): /assets/abc123def.js → /assets/:hash.js\n hash: /\\/[0-9a-f]{6,}(?=\\.[a-z]+$)/gi,\n\n // ISO dates: /logs/2024-01-15 → /logs/:date\n isoDate: /\\/\\d{4}-\\d{2}-\\d{2}(?=\\/|$)/g,\n\n // Timestamps: /events/1705334400 → /events/:timestamp\n timestamp: /\\/1[0-9]{9}(?=\\/|$)/g,\n\n // Email-like segments: /users/john@example.com → /users/:email\n email: /\\/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}(?=\\/|$)/g,\n} as const;\n\n/**\n * Built-in normalizer presets\n */\nconst NORMALIZER_PRESETS: Record<\n SpanNameNormalizerPreset,\n SpanNameNormalizerFn\n> = {\n /**\n * REST API preset - normalizes common REST path patterns\n * Handles: numeric IDs, UUIDs, ObjectIds, dates, timestamps, emails\n */\n 'rest-api': (name: string): string => {\n return name\n .replaceAll(NORMALIZER_PATTERNS.uuid, '/:uuid')\n .replaceAll(NORMALIZER_PATTERNS.shortUuid, '/:uuid')\n .replaceAll(NORMALIZER_PATTERNS.objectId, '/:objectId')\n .replaceAll(NORMALIZER_PATTERNS.isoDate, '/:date')\n .replaceAll(NORMALIZER_PATTERNS.timestamp, '/:timestamp')\n .replaceAll(NORMALIZER_PATTERNS.email, '/:email')\n .replaceAll(NORMALIZER_PATTERNS.numericId, '/:id');\n },\n\n /**\n * GraphQL preset - normalizes GraphQL operation names and paths\n * Keeps query/mutation names but normalizes embedded IDs\n */\n graphql: (name: string): string => {\n // For GraphQL, normalize both path-style and embedded IDs\n return name\n .replaceAll(NORMALIZER_PATTERNS.uuid, '/:uuid')\n .replaceAll(NORMALIZER_PATTERNS.numericId, '/:id');\n },\n\n /**\n * Minimal preset - only normalizes numeric IDs and UUIDs\n */\n minimal: (name: string): string => {\n return name\n .replaceAll(NORMALIZER_PATTERNS.uuid, '/:uuid')\n .replaceAll(NORMALIZER_PATTERNS.numericId, '/:id');\n },\n};\n\n/**\n * Resolve normalizer config to a function\n */\nfunction resolveNormalizer(\n config: SpanNameNormalizerConfig,\n): SpanNameNormalizerFn {\n if (typeof config === 'function') {\n return config;\n }\n\n const preset = NORMALIZER_PRESETS[config];\n if (!preset) {\n throw new Error(\n `Unknown span name normalizer preset: \"${config}\". ` +\n `Available presets: ${Object.keys(NORMALIZER_PRESETS).join(', ')}`,\n );\n }\n\n return preset;\n}\n\n/**\n * Span processor that normalizes span names to reduce cardinality.\n *\n * Normalization happens in onStart() when we have access to the mutable Span.\n * This allows us to call span.updateName() before the span is finalized.\n *\n * Common use cases:\n * - REST APIs: /users/123/posts/456 → /users/:id/posts/:id\n * - UUIDs: /items/550e8400-e29b-41d4-a716-446655440000 → /items/:uuid\n * - Dates: /logs/2024-01-15 → /logs/:date\n */\nexport class SpanNameNormalizingProcessor implements SpanProcessor {\n private readonly wrappedProcessor: SpanProcessor;\n private readonly normalizer: SpanNameNormalizerFn;\n\n constructor(\n wrappedProcessor: SpanProcessor,\n options: SpanNameNormalizingProcessorOptions,\n ) {\n this.wrappedProcessor = wrappedProcessor;\n this.normalizer = resolveNormalizer(options.normalizer);\n }\n\n /**\n * Normalize span name on start (when Span is mutable)\n */\n onStart(span: Span, parentContext: Context): void {\n try {\n const originalName = span.name;\n const normalizedName = this.normalizer(originalName);\n\n if (normalizedName !== originalName) {\n span.updateName(normalizedName);\n }\n } catch {\n // If normalizer throws, keep original name (fail-open)\n }\n\n this.wrappedProcessor.onStart(span, parentContext);\n }\n\n /**\n * Pass through onEnd unchanged\n */\n onEnd(span: ReadableSpan): void {\n this.wrappedProcessor.onEnd(span);\n }\n\n forceFlush(): Promise<void> {\n return this.wrappedProcessor.forceFlush();\n }\n\n shutdown(): Promise<void> {\n return this.wrappedProcessor.shutdown();\n }\n}\n\n/**\n * Export built-in patterns for advanced users who want to compose their own normalizers\n */\nexport { NORMALIZER_PATTERNS, NORMALIZER_PRESETS };\n"]}