{"version":3,"sources":["../src/sampling.ts"],"names":["TraceFlags"],"mappings":"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","file":"chunk-VH77IPJN.cjs","sourcesContent":["/**\n * Sampling Strategies\n *\n * Provides intelligent sampling beyond simple random rates.\n * Helps reduce telemetry costs while capturing critical data.\n *\n * Key strategies:\n * - Always trace errors and slow requests (critical for debugging)\n * - Sample by user ID for consistent request tracing\n * - Adaptive sampling based on load\n * - Sample by feature flags for A/B testing correlation\n *\n * @example\n * ```typescript\n * import { AlwaysOnErrorSampler, UserIdSampler } from './sampling'\n *\n * @Instrumented({\n *   serviceName: 'user',\n *   sampler: new AlwaysOnErrorSampler(0.1) // 10% baseline, 100% on errors\n * })\n * class UserService { }\n * ```\n */\n\nimport type { Link, Attributes } from '@opentelemetry/api';\nimport { TraceFlags } from '@opentelemetry/api';\nimport { type Logger } from './logger';\n\n/**\n * Tail sampling attribute keys (autotel-internal, not OTel semconv)\n */\nexport const AUTOTEL_SAMPLING_TAIL_KEEP = 'autotel.sampling.tail.keep';\nexport const AUTOTEL_SAMPLING_TAIL_EVALUATED =\n  'autotel.sampling.tail.evaluated';\n\n/**\n * Sampler interface - return true to trace, false to skip\n */\nexport interface Sampler {\n  /**\n   * Decide whether to trace this operation\n   *\n   * @param context - Sampling context\n   * @returns true to trace, false to skip\n   */\n  shouldSample(context: SamplingContext): boolean;\n\n  /**\n   * Whether this sampler needs tail sampling (post-execution decision)\n   * If true, spans are always created and shouldKeepTrace() is called after execution\n   *\n   * @returns true if this sampler needs to evaluate after operation completes\n   */\n  needsTailSampling?(): boolean;\n\n  /**\n   * Re-evaluate sampling decision after operation completes (tail sampling)\n   * Only called if needsTailSampling() returns true\n   *\n   * @param context - Sampling context\n   * @param result - Operation result\n   * @returns true if this trace should be kept, false to drop it\n   */\n  shouldKeepTrace?(context: SamplingContext, result: OperationResult): boolean;\n}\n\n/**\n * Context information for sampling decisions\n */\nexport interface SamplingContext {\n  /** Operation name */\n  operationName: string;\n  /** Method arguments (for extracting user IDs, etc.) */\n  args: unknown[];\n  /** Optional metadata (e.g., feature flags, request headers) */\n  metadata?: Record<string, unknown>;\n  /** Optional span links for links-based sampling */\n  links?: Link[];\n}\n\n/**\n * Result of a trace operation (for post-execution sampling)\n */\nexport interface OperationResult {\n  /** Whether the operation succeeded */\n  success: boolean;\n  /** Duration in milliseconds */\n  duration: number;\n  /** Error if operation failed */\n  error?: Error;\n}\n\n/**\n * Simple random sampler\n *\n * @example\n * ```typescript\n * new RandomSampler(0.1) // Sample 10% of requests\n * ```\n */\nexport class RandomSampler implements Sampler {\n  constructor(private readonly sampleRate: number) {\n    if (sampleRate < 0 || sampleRate > 1) {\n      throw new Error('Sample rate must be between 0 and 1');\n    }\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  shouldSample(_context: SamplingContext): boolean {\n    return Math.random() < this.sampleRate;\n  }\n}\n\n/**\n * Always sample (100% tracing)\n */\nexport class AlwaysSampler implements Sampler {\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  shouldSample(_context: SamplingContext): boolean {\n    return true;\n  }\n}\n\n/**\n * Never sample (0% tracing)\n */\nexport class NeverSampler implements Sampler {\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  shouldSample(_context: SamplingContext): boolean {\n    return false;\n  }\n}\n\n/**\n * Adaptive sampler that always traces errors and slow requests\n *\n * This is the recommended sampler for production use.\n * It ensures you never miss critical issues while keeping costs down.\n *\n * Strategy:\n * - Always trace errors (critical for debugging)\n * - Always trace slow requests (performance issues)\n * - Use baseline sample rate for successful fast requests\n *\n * **IMPORTANT - Tail Sampling Requirement:**\n * This sampler uses tail sampling (makes decisions AFTER execution).\n * You MUST use TailSamplingSpanProcessor for it to work correctly:\n *\n * - If using initInstrumentation(): TailSamplingSpanProcessor is auto-configured\n * - If using custom TracerProvider: You MUST manually register TailSamplingSpanProcessor\n *\n * Without TailSamplingSpanProcessor, ALL spans are exported (defeating the cost savings).\n *\n * @see TailSamplingSpanProcessor\n * @see README.md \"Tail Sampling with Custom Providers\" section\n *\n * @example\n * ```typescript\n * new AdaptiveSampler({\n *   baselineSampleRate: 0.1,    // 10% of normal requests\n *   slowThresholdMs: 1000,       // Requests > 1s are \"slow\"\n *   alwaysSampleErrors: true,    // Always trace errors\n *   alwaysSampleSlow: true       // Always trace slow requests\n * })\n * ```\n */\nexport class AdaptiveSampler implements Sampler {\n  private baselineSampleRate: number;\n  private slowThresholdMs: number;\n  private alwaysSampleErrors: boolean;\n  private alwaysSampleSlow: boolean;\n  private linksBased: boolean;\n  private linksRate: number;\n  private logger?: Logger;\n\n  // Track whether we should sample this request\n  private readonly samplingDecisions = new WeakMap<unknown[], boolean>();\n  // Track operation results to enable post-execution decision\n  private readonly operationResults = new WeakMap<unknown[], OperationResult>();\n\n  constructor(\n    options: {\n      baselineSampleRate?: number;\n      slowThresholdMs?: number;\n      alwaysSampleErrors?: boolean;\n      alwaysSampleSlow?: boolean;\n      /** Enable links-based sampling for event-driven architectures */\n      linksBased?: boolean;\n      /** Sampling rate for spans linked to sampled spans (0.0-1.0) */\n      linksRate?: number;\n      logger?: Logger;\n    } = {},\n  ) {\n    this.baselineSampleRate = options.baselineSampleRate ?? 0.1;\n    this.slowThresholdMs = options.slowThresholdMs ?? 1000;\n    this.alwaysSampleErrors = options.alwaysSampleErrors ?? true;\n    this.alwaysSampleSlow = options.alwaysSampleSlow ?? true;\n    this.linksBased = options.linksBased ?? false;\n    this.linksRate = options.linksRate ?? 1;\n    this.logger = options.logger;\n\n    if (this.baselineSampleRate < 0 || this.baselineSampleRate > 1) {\n      throw new Error('Baseline sample rate must be between 0 and 1');\n    }\n    if (this.linksRate < 0 || this.linksRate > 1) {\n      throw new Error('Links rate must be between 0 and 1');\n    }\n  }\n\n  needsTailSampling(): boolean {\n    // AdaptiveSampler ALWAYS needs tail sampling to implement error/slow capture\n    return true;\n  }\n\n  shouldSample(context: SamplingContext): boolean {\n    // For tail sampling, we optimistically create spans for all requests\n    // The real decision happens in shouldKeepTrace() after execution\n    // We still store the baseline decision for shouldKeepTrace() to use\n    const baselineDecision = Math.random() < this.baselineSampleRate;\n    this.samplingDecisions.set(context.args, baselineDecision);\n\n    // Always return true to create the span (tail sampling will decide if we keep it)\n    return true;\n  }\n\n  /**\n   * Check if any links point to sampled spans.\n   *\n   * A span is considered linked to a sampled span if any of its links\n   * have trace_flags with the sampled bit set (0x01).\n   *\n   * @param links - Array of span links to check\n   * @returns true if any linked span is sampled, false otherwise\n   */\n  hasSampledLink(links: Link[]): boolean {\n    if (!links || links.length === 0) {\n      return false;\n    }\n    return links.some(\n      (link) =>\n        link.context && (link.context.traceFlags & TraceFlags.SAMPLED) !== 0,\n    );\n  }\n\n  /**\n   * Re-evaluate sampling decision after operation completes\n   *\n   * This allows us to always capture errors and slow requests,\n   * even if they weren't initially sampled.\n   *\n   * @param context - Sampling context\n   * @param result - Operation result\n   * @returns true if this operation should be kept (not discarded)\n   */\n  shouldKeepTrace(context: SamplingContext, result: OperationResult): boolean {\n    const baselineDecision = this.samplingDecisions.get(context.args) ?? false;\n\n    // Always keep errors\n    if (this.alwaysSampleErrors && !result.success) {\n      if (!baselineDecision) {\n        this.logger?.debug(\n          {\n            operation: context.operationName,\n            error: result.error?.message,\n          },\n          'Adaptive sampling: Keeping error trace',\n        );\n      }\n      return true;\n    }\n\n    // Always keep slow requests\n    if (this.alwaysSampleSlow && result.duration >= this.slowThresholdMs) {\n      if (!baselineDecision) {\n        this.logger?.debug(\n          {\n            operation: context.operationName,\n            duration: result.duration,\n          },\n          'Adaptive sampling: Keeping slow trace',\n        );\n      }\n      return true;\n    }\n\n    // Check for sampled links (links-based sampling for event-driven systems)\n    if (\n      this.linksBased &&\n      context.links &&\n      this.hasSampledLink(context.links)\n    ) {\n      // Use linksRate to decide whether to keep the linked span\n      const keepLinked = Math.random() < this.linksRate;\n      if (keepLinked && !baselineDecision) {\n        this.logger?.debug(\n          {\n            operation: context.operationName,\n            linkCount: context.links.length,\n          },\n          'Adaptive sampling: Keeping trace due to sampled link',\n        );\n      }\n      return keepLinked;\n    }\n\n    // Otherwise, use baseline decision\n    return baselineDecision;\n  }\n}\n\n/**\n * User-based sampler for consistent tracing\n *\n * Always samples requests from specific user IDs.\n * Useful for debugging specific user issues or monitoring VIP users.\n *\n * @example\n * ```typescript\n * new UserIdSampler({\n *   baselineSampleRate: 0.01,      // 1% of normal users\n *   alwaysSampleUsers: ['vip_123'], // Always trace VIP users\n *   extractUserId: (args) => args[0]?.userId // Extract user ID from first arg\n * })\n * ```\n */\nexport class UserIdSampler implements Sampler {\n  private baselineSampleRate: number;\n  private alwaysSampleUsers: Set<string>;\n  private extractUserId: (args: unknown[]) => string | undefined;\n  private logger?: Logger;\n\n  constructor(options: {\n    baselineSampleRate?: number;\n    alwaysSampleUsers?: string[];\n    extractUserId: (args: unknown[]) => string | undefined;\n    logger?: Logger;\n  }) {\n    this.baselineSampleRate = options.baselineSampleRate ?? 0.1;\n    this.alwaysSampleUsers = new Set(options.alwaysSampleUsers || []);\n    this.extractUserId = options.extractUserId;\n    this.logger = options.logger;\n  }\n\n  shouldSample(context: SamplingContext): boolean {\n    const userId = this.extractUserId(context.args);\n\n    // Always sample specific users\n    if (userId && this.alwaysSampleUsers.has(userId)) {\n      this.logger?.debug(\n        {\n          operation: context.operationName,\n          userId,\n        },\n        'Sampling user request',\n      );\n      return true;\n    }\n\n    // For consistent per-user sampling, hash the user ID\n    if (userId) {\n      const hash = this.hashString(userId);\n      return hash < this.baselineSampleRate;\n    }\n\n    // Fallback to random sampling if no user ID\n    return Math.random() < this.baselineSampleRate;\n  }\n\n  /**\n   * Add user IDs to always-sample list\n   */\n  addAlwaysSampleUsers(...userIds: string[]): void {\n    for (const userId of userIds) {\n      this.alwaysSampleUsers.add(userId);\n    }\n  }\n\n  /**\n   * Remove user IDs from always-sample list\n   */\n  removeAlwaysSampleUsers(...userIds: string[]): void {\n    for (const userId of userIds) {\n      this.alwaysSampleUsers.delete(userId);\n    }\n  }\n\n  /**\n   * Simple hash function for consistent user sampling\n   */\n  private hashString(str: string): number {\n    let hash = 0;\n    for (let i = 0; i < str.length; i++) {\n      const char = str.codePointAt(i) ?? 0;\n      hash = (hash << 5) - hash + char;\n      hash = hash & hash; // Convert to 32-bit integer\n    }\n    return Math.abs(hash) / 2_147_483_647; // Normalize to 0-1\n  }\n}\n\n/**\n * Composite sampler that combines multiple samplers\n *\n * Samples if ANY of the child samplers returns true.\n *\n * @example\n * ```typescript\n * new CompositeSampler([\n *   new UserIdSampler({ extractUserId: (args) => args[0]?.userId }),\n *   new AdaptiveSampler({ baselineSampleRate: 0.1 })\n * ])\n * ```\n */\nexport class CompositeSampler implements Sampler {\n  constructor(private readonly samplers: Sampler[]) {\n    if (samplers.length === 0) {\n      throw new Error('CompositeSampler requires at least one child sampler');\n    }\n  }\n\n  shouldSample(context: SamplingContext): boolean {\n    return this.samplers.some((sampler) => sampler.shouldSample(context));\n  }\n}\n\n/**\n * Feature flag sampler\n *\n * Always samples requests with specific feature flags enabled.\n * Perfect for correlating A/B test experiments with metrics.\n *\n * @example\n * ```typescript\n * new FeatureFlagSampler({\n *   baselineSampleRate: 0.01,\n *   alwaysSampleFlags: ['new_checkout', 'experimental_ui'],\n *   extractFlags: (args, metadata) => metadata?.featureFlags\n * })\n * ```\n */\nexport class FeatureFlagSampler implements Sampler {\n  private baselineSampleRate: number;\n  private alwaysSampleFlags: Set<string>;\n  private extractFlags: (\n    args: unknown[],\n    metadata?: Record<string, unknown>,\n  ) => string[] | undefined;\n  private logger?: Logger;\n\n  constructor(options: {\n    baselineSampleRate?: number;\n    alwaysSampleFlags?: string[];\n    extractFlags: (\n      args: unknown[],\n      metadata?: Record<string, unknown>,\n    ) => string[] | undefined;\n    logger?: Logger;\n  }) {\n    this.baselineSampleRate = options.baselineSampleRate ?? 0.1;\n    this.alwaysSampleFlags = new Set(options.alwaysSampleFlags || []);\n    this.extractFlags = options.extractFlags;\n    this.logger = options.logger;\n  }\n\n  shouldSample(context: SamplingContext): boolean {\n    const flags = this.extractFlags(context.args, context.metadata);\n\n    // Always sample if any monitored flag is enabled\n    if (flags && flags.some((flag) => this.alwaysSampleFlags.has(flag))) {\n      this.logger?.debug(\n        {\n          operation: context.operationName,\n          flags,\n        },\n        'Sampling feature flag request',\n      );\n      return true;\n    }\n\n    // Fallback to random sampling\n    return Math.random() < this.baselineSampleRate;\n  }\n\n  /**\n   * Add feature flags to always-sample list\n   */\n  addAlwaysSampleFlags(...flags: string[]): void {\n    for (const flag of flags) {\n      this.alwaysSampleFlags.add(flag);\n    }\n  }\n\n  /**\n   * Remove feature flags from always-sample list\n   */\n  removeAlwaysSampleFlags(...flags: string[]): void {\n    for (const flag of flags) {\n      this.alwaysSampleFlags.delete(flag);\n    }\n  }\n}\n\n// ============================================================================\n// Sampling Presets\n// ============================================================================\n\n/**\n * Named sampling presets for common environments.\n * Use with `init({ sampling: 'production' })` or directly via factories.\n */\nexport type SamplingPreset =\n  | 'development'\n  | 'errors-only'\n  | 'production'\n  | 'off';\n\n/**\n * Sampling preset factories.\n *\n * For most users, the string shorthand on `init()` is simpler:\n * ```typescript\n * init({ service: 'my-app', sampling: 'production' })\n * ```\n *\n * Use factories when you need to customize:\n * ```typescript\n * init({ service: 'my-app', sampler: samplingPresets.production({ baselineSampleRate: 0.05 }) })\n * ```\n */\nexport const samplingPresets = {\n  /** Capture everything — best for local development and debugging */\n  development: () => new AlwaysSampler(),\n\n  /** Only bad outcomes — zero baseline, errors always kept */\n  errorsOnly: () =>\n    new AdaptiveSampler({\n      baselineSampleRate: 0,\n      alwaysSampleErrors: true,\n    }),\n\n  /**\n   * Balanced production defaults — 10% baseline + errors + slow traces.\n   * Pass overrides to tune (uses the same option names as AdaptiveSampler).\n   */\n  production: (overrides?: {\n    baselineSampleRate?: number;\n    slowThresholdMs?: number;\n    alwaysSampleErrors?: boolean;\n    alwaysSampleSlow?: boolean;\n  }) =>\n    new AdaptiveSampler({\n      baselineSampleRate: 0.1,\n      alwaysSampleErrors: true,\n      alwaysSampleSlow: true,\n      slowThresholdMs: 1000,\n      ...overrides,\n    }),\n\n  /** Disable sampling entirely */\n  off: () => new NeverSampler(),\n};\n\n/**\n * Resolve a preset string to a Sampler instance.\n * Used internally by `init()` when `sampling` string is provided.\n *\n * @throws Error if preset is not recognized\n */\nexport function resolveSamplingPreset(preset: SamplingPreset): Sampler {\n  switch (preset) {\n    case 'development':\n      return samplingPresets.development();\n    case 'errors-only':\n      return samplingPresets.errorsOnly();\n    case 'production':\n      return samplingPresets.production();\n    case 'off':\n      return samplingPresets.off();\n    default:\n      throw new Error(\n        `Unknown sampling preset: \"${preset}\". Valid presets: development, errors-only, production, off`,\n      );\n  }\n}\n\n// ============================================================================\n// Link Helper Functions\n// ============================================================================\n\n/**\n * Create a Link from W3C trace context headers (e.g., from a message queue).\n *\n * This is useful for message consumers that need to link to the producer span.\n * The headers should contain at least a `traceparent` header in W3C format.\n *\n * @param headers - Dictionary containing traceparent/tracestate headers\n * @param attributes - Optional attributes for the link\n * @returns Link object if context could be extracted, null otherwise\n *\n * @example\n * ```typescript\n * // In a Kafka consumer\n * const headers = { traceparent: '00-abc123...-def456...-01' };\n * const link = createLinkFromHeaders(headers);\n * if (link) {\n *   // Use with tracer.startActiveSpan options or ctx.addLink()\n *   tracer.startActiveSpan('process.message', { links: [link] }, span => { ... });\n * }\n * ```\n */\nexport function createLinkFromHeaders(\n  headers: Record<string, string>,\n  attributes?: Attributes,\n): Link | null {\n  // Parse W3C traceparent header directly for reliability\n  // Format: version-traceId-spanId-traceFlags (e.g., 00-abc123...-def456...-01)\n  const traceparent = headers.traceparent || headers['traceparent'];\n  if (!traceparent) {\n    return null;\n  }\n\n  const spanContext = parseTraceparent(traceparent);\n  if (!spanContext || !isValidSpanContext(spanContext)) {\n    return null;\n  }\n\n  return {\n    context: spanContext,\n    attributes: attributes ?? {},\n  };\n}\n\n/**\n * Extract Links from a batch of messages for fan-in scenarios.\n *\n * Useful for batch processing where multiple producer spans should be linked.\n * This enables tracing causality in event-driven architectures where a single\n * consumer processes messages from multiple producers.\n *\n * @param messages - List of message objects\n * @param headersKey - Key in each message containing trace headers (default: 'headers')\n * @returns List of Link objects for all valid trace contexts\n *\n * @example\n * ```typescript\n * // Processing a batch of SQS/Kafka messages\n * const messages = [\n *   { body: '...', headers: { traceparent: '...' } },\n *   { body: '...', headers: { traceparent: '...' } },\n * ];\n * const links = extractLinksFromBatch(messages);\n *\n * tracer.startActiveSpan('process.batch', { links }, span => {\n *   for (const msg of messages) {\n *     processMessage(msg);\n *   }\n * });\n * ```\n */\nexport function extractLinksFromBatch(\n  messages: Array<{ [key: string]: unknown }>,\n  headersKey: string = 'headers',\n): Link[] {\n  const links: Link[] = [];\n\n  for (const msg of messages) {\n    const msgHeaders = msg[headersKey];\n    if (msgHeaders && typeof msgHeaders === 'object' && msgHeaders !== null) {\n      const link = createLinkFromHeaders(msgHeaders as Record<string, string>, {\n        'messaging.batch.message_index': links.length,\n      });\n      if (link) {\n        links.push(link);\n      }\n    }\n  }\n\n  return links;\n}\n\n/**\n * Parse W3C traceparent header into SpanContext\n * Format: version-traceId-spanId-traceFlags (e.g., 00-abc123...-def456...-01)\n *\n * @see https://www.w3.org/TR/trace-context/#traceparent-header\n */\nfunction parseTraceparent(\n  traceparent: string,\n): import('@opentelemetry/api').SpanContext | null {\n  // W3C traceparent format: version-traceId-parentId-traceFlags\n  // Example: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01\n  const TRACEPARENT_REGEX =\n    /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/i;\n\n  const match = traceparent.match(TRACEPARENT_REGEX);\n  if (!match || match.length < 5) {\n    return null;\n  }\n\n  const version = match[1];\n  const traceId = match[2];\n  const spanId = match[3];\n  const flags = match[4];\n\n  // Validate all parts are present (TypeScript narrowing)\n  if (!version || !traceId || !spanId || !flags) {\n    return null;\n  }\n\n  // Version 00 is currently the only version, but we should be forward compatible\n  if (version === 'ff') {\n    // Version ff is invalid according to spec\n    return null;\n  }\n\n  return {\n    traceId,\n    spanId,\n    traceFlags: Number.parseInt(flags, 16),\n    isRemote: true,\n  };\n}\n\n/**\n * Check if a SpanContext is valid (has non-zero trace and span IDs)\n */\nfunction isValidSpanContext(\n  spanContext: import('@opentelemetry/api').SpanContext | null,\n): spanContext is import('@opentelemetry/api').SpanContext {\n  if (!spanContext) return false;\n  // TraceId should not be all zeros (00000000000000000000000000000000)\n  // SpanId should not be all zeros (0000000000000000)\n  return (\n    spanContext.traceId !== '00000000000000000000000000000000' &&\n    spanContext.spanId !== '0000000000000000'\n  );\n}\n"]}