{"version":3,"sources":["../src/instrumentation.ts"],"names":["getLogger","processDetector","hostDetector","detectResources","resourceFromAttributes","ATTR_SERVICE_NAME","ATTR_SERVICE_VERSION","requireModule","OTLPTraceExporter","TailSamplingSpanProcessor","BatchSpanProcessor","NodeSDK","PeriodicExportingMetricReader","OTLPMetricExporter","BatchLogRecordProcessor","OTLPLogExporter"],"mappings":"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","file":"instrumentation.cjs","sourcesContent":["import { NodeSDK } from '@opentelemetry/sdk-node';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';\nimport { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';\nimport { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport { TailSamplingSpanProcessor } from './tail-sampling-processor';\nimport { getLogger } from './init';\nimport {\n  resourceFromAttributes,\n  detectResources,\n  processDetector,\n  hostDetector,\n  type Resource,\n  type ResourceDetector,\n} from '@opentelemetry/resources';\nimport {\n  ATTR_SERVICE_NAME,\n  ATTR_SERVICE_VERSION,\n} from '@opentelemetry/semantic-conventions/incubating';\nimport { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';\nimport { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';\nimport { requireModule } from './node-require';\n\n/**\n * Parse OTLP headers string into object format\n * @param headersString - Headers as \"key1=value1,key2=value2\" or \"Authorization=Basic ...\"\n * @returns Headers object for OTLP exporters\n */\nfunction parseOtlpHeaders(headersString?: string): Record<string, string> {\n  if (!headersString) return {};\n\n  const headers: Record<string, string> = {};\n  const pairs = headersString.split(',');\n\n  for (const pair of pairs) {\n    const [key, ...valueParts] = pair.split('=');\n    if (key && valueParts.length > 0) {\n      headers[key.trim()] = valueParts.join('=').trim();\n    }\n  }\n\n  return headers;\n}\n\n/**\n * Parse resource attributes string into object format\n * @param attributesString - Attributes as \"key1=value1,key2=value2\"\n * @returns Resource attributes object\n */\nfunction parseResourceAttributes(\n  attributesString?: string,\n): Record<string, string> {\n  if (!attributesString) return {};\n\n  const attributes: Record<string, string> = {};\n  const pairs = attributesString.split(',');\n\n  for (const pair of pairs) {\n    const [key, ...valueParts] = pair.split('=');\n    if (key && valueParts.length > 0) {\n      attributes[key.trim()] = valueParts.join('=').trim();\n    }\n  }\n\n  return attributes;\n}\n\nexport interface InstrumentationConfig {\n  serviceName: string;\n  serviceVersion?: string;\n  deploymentEnvironment?: string;\n  otlpEndpoint?: string;\n  /** Headers for authentication (e.g., Grafana Cloud, Honeycomb) */\n  headers?: string;\n  /** Resource attributes as comma-separated key=value pairs */\n  resourceAttributes?: string;\n  /** Enable async resource detection for process/host info (default: false) */\n  detectResources?: boolean;\n  /**\n   * Use selective instrumentation instead of full auto-instrumentation\n   * **Default: true** (performance-first)\n   *\n   * When true, auto-instrumentation is disabled. You can manually add\n   * specific instrumentations via the `instrumentations` field.\n   * This reduces overhead from ~81% to near-zero based on Platformatic benchmarks.\n   *\n   * Set to false to enable full auto-instrumentation (not recommended for production).\n   *\n   * @see https://blogger.platformatic.dev/the-hidden-cost-of-context\n   */\n  selectiveInstrumentation?: boolean;\n\n  /**\n   * Custom instrumentations to use (only when selectiveInstrumentation is true)\n   * @example\n   * ```typescript\n   * import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'\n   *\n   * initInstrumentation({\n   *   serviceName: 'api',\n   *   selectiveInstrumentation: true,\n   *   instrumentations: [new HttpInstrumentation()]\n   * })\n   * ```\n   */\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  instrumentations?: any[];\n}\n\n/**\n * Initialize OpenTelemetry instrumentation with OTLP exporters\n *\n * This sets up:\n * - Traces (OTLP HTTP)\n * - Metrics (OTLP HTTP)\n * - Logs (OTLP HTTP)\n * - Auto-instrumentation for common Node.js libraries\n *\n * @example\n * // Call this at the very start of your application\n * import { initInstrumentation } from '@your-org/otel-decorators'\n *\n * initInstrumentation({\n *   serviceName: 'my-service' }\n *   serviceVersion: '1.0.0',\n *   deploymentEnvironment: 'production',\n *   otlpEndpoint: 'http://localhost:4318'\n * })\n *\n * // Or with async resource detection (top-level await required)\n * await initInstrumentation({\n *   serviceName: 'my-service' }\n *   detectResources: true\n * })\n */\n// Enables graceful shutdown and prevents SDK leaks on hot-reload\nlet currentSDK: NodeSDK | null = null;\nlet shutdownHandlerRegistered = false;\n\n/**\n * Shutdown the OpenTelemetry SDK gracefully\n * Call this before process exit or during hot-reloads\n */\nexport async function shutdownInstrumentation(sdk?: NodeSDK): Promise<void> {\n  const sdkToShutdown = sdk || currentSDK;\n  if (!sdkToShutdown) {\n    getLogger().warn({}, 'No SDK to shutdown');\n    return;\n  }\n\n  try {\n    await sdkToShutdown.shutdown();\n    getLogger().info({}, 'OpenTelemetry terminated successfully');\n    if (sdkToShutdown === currentSDK) {\n      currentSDK = null;\n    }\n  } catch (error) {\n    getLogger().error(\n      {\n        err: error instanceof Error ? error : undefined,\n      },\n      'Error terminating OpenTelemetry',\n    );\n    throw error;\n  }\n}\n\nexport async function initInstrumentation(\n  config: InstrumentationConfig,\n): Promise<NodeSDK> {\n  // Prevents resource leaks on hot-reload or multiple init calls\n  if (currentSDK) {\n    getLogger().info(\n      {},\n      'Shutting down existing OpenTelemetry SDK before reinitializing...',\n    );\n    await shutdownInstrumentation(currentSDK);\n  }\n\n  // Parse headers and resource attributes\n  const otlpHeaders = parseOtlpHeaders(config.headers);\n  const customResourceAttributes = parseResourceAttributes(\n    config.resourceAttributes,\n  );\n\n  let resource: Resource;\n\n  // Dynamically load optional resource detectors\n  const detectors: ResourceDetector[] = [processDetector, hostDetector];\n  try {\n    const awsDetectors = await import('@opentelemetry/resource-detector-aws');\n    detectors.push(\n      awsDetectors.awsEc2Detector,\n      awsDetectors.awsEcsDetector,\n      awsDetectors.awsEksDetector,\n    );\n  } catch {\n    // ignore\n  }\n  try {\n    const gcpDetectors = await import('@opentelemetry/resource-detector-gcp');\n    detectors.push(gcpDetectors.gcpDetector);\n  } catch {\n    // ignore\n  }\n  try {\n    const containerDetectors =\n      await import('@opentelemetry/resource-detector-container');\n    detectors.push(containerDetectors.containerDetector);\n  } catch {\n    // ignore\n  }\n\n  if (config.detectResources) {\n    const detectedResource = await detectResources({\n      detectors,\n    });\n\n    resource = detectedResource.merge(\n      resourceFromAttributes({\n        [ATTR_SERVICE_NAME]: config.serviceName,\n        [ATTR_SERVICE_VERSION]: config.serviceVersion || '1.0.0',\n        'deployment.environment': config.deploymentEnvironment || 'development',\n        ...customResourceAttributes, // Merge custom resource attributes\n      }),\n    );\n  } else {\n    resource = resourceFromAttributes({\n      [ATTR_SERVICE_NAME]: config.serviceName,\n      [ATTR_SERVICE_VERSION]: config.serviceVersion || '1.0.0',\n      'deployment.environment': config.deploymentEnvironment || 'development',\n      ...customResourceAttributes, // Merge custom resource attributes\n    });\n  }\n\n  // Default to selective (near-zero overhead) vs full auto (~81% overhead)\n  // Lazy-load to avoid importing ~40+ packages at module evaluation time\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  let instrumentations: any[] = config.instrumentations || [];\n  if (config.selectiveInstrumentation === false) {\n    const mod = requireModule<{\n      getNodeAutoInstrumentations: () => unknown[];\n    }>('@opentelemetry/auto-instrumentations-node');\n    instrumentations = [mod.getNodeAutoInstrumentations()];\n  }\n\n  const traceExporter = new OTLPTraceExporter({\n    url: `${config.otlpEndpoint || 'http://localhost:4318'}/v1/traces`,\n    headers: otlpHeaders,\n  });\n\n  // Enables tail sampling via autotel.sampling.tail.keep attribute\n  const spanProcessor = new TailSamplingSpanProcessor(\n    new BatchSpanProcessor(traceExporter),\n  );\n\n  const sdk = new NodeSDK({\n    resource,\n    spanProcessor, // Use our wrapped processor instead of traceExporter directly\n    metricReader: new PeriodicExportingMetricReader({\n      exporter: new OTLPMetricExporter({\n        url: `${config.otlpEndpoint || 'http://localhost:4318'}/v1/metrics`,\n        headers: otlpHeaders,\n      }),\n    }),\n    logRecordProcessors: [\n      new BatchLogRecordProcessor(\n        new OTLPLogExporter({\n          url: `${config.otlpEndpoint || 'http://localhost:4318'}/v1/logs`,\n          headers: otlpHeaders,\n        }),\n      ),\n    ],\n    instrumentations,\n  });\n\n  try {\n    await sdk.start();\n    getLogger().info({}, 'OpenTelemetry instrumentation started successfully');\n  } catch (error) {\n    getLogger().error(\n      {\n        err: error instanceof Error ? error : undefined,\n      },\n      'Failed to start OpenTelemetry SDK',\n    );\n    throw error;\n  }\n\n  // Track current SDK for shutdown handler\n  currentSDK = sdk;\n\n  if (!shutdownHandlerRegistered) {\n    shutdownHandlerRegistered = true;\n\n    const shutdownHandler = () => {\n      shutdownInstrumentation()\n        .then(() => {\n          // eslint-disable-next-line unicorn/no-process-exit\n          process.exit(0);\n        })\n        .catch((error) => {\n          getLogger().error(\n            {\n              err: error instanceof Error ? error : undefined,\n            },\n            'Shutdown error',\n          );\n          // eslint-disable-next-line unicorn/no-process-exit\n          process.exit(1);\n        });\n    };\n\n    process.on('SIGTERM', shutdownHandler);\n    process.on('SIGINT', shutdownHandler);\n  }\n\n  return sdk;\n}\n"]}