autotel
Version:
Write Once, Observe Anywhere
172 lines (170 loc) • 7.33 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_node_require = require('./node-require-CZ_PU448.cjs');
const require_init = require('./init-BXiuPK6j.cjs');
const require_tail_sampling_processor = require('./tail-sampling-processor.cjs');
let _opentelemetry_sdk_node = require("@opentelemetry/sdk-node");
let _opentelemetry_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
let _opentelemetry_resources = require("@opentelemetry/resources");
let _opentelemetry_sdk_metrics = require("@opentelemetry/sdk-metrics");
let _opentelemetry_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
let _opentelemetry_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
let _opentelemetry_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
let _opentelemetry_sdk_logs = require("@opentelemetry/sdk-logs");
let _opentelemetry_semantic_conventions_incubating = require("@opentelemetry/semantic-conventions/incubating");
//#region src/instrumentation.ts
/**
* Parse OTLP headers string into object format
* @param headersString - Headers as "key1=value1,key2=value2" or "Authorization=Basic ..."
* @returns Headers object for OTLP exporters
*/
function parseOtlpHeaders(headersString) {
if (!headersString) return {};
const headers = {};
const pairs = headersString.split(",");
for (const pair of pairs) {
const [key, ...valueParts] = pair.split("=");
if (key && valueParts.length > 0) headers[key.trim()] = valueParts.join("=").trim();
}
return headers;
}
/**
* Parse resource attributes string into object format
* @param attributesString - Attributes as "key1=value1,key2=value2"
* @returns Resource attributes object
*/
function parseResourceAttributes(attributesString) {
if (!attributesString) return {};
const attributes = {};
const pairs = attributesString.split(",");
for (const pair of pairs) {
const [key, ...valueParts] = pair.split("=");
if (key && valueParts.length > 0) attributes[key.trim()] = valueParts.join("=").trim();
}
return attributes;
}
/**
* Initialize OpenTelemetry instrumentation with OTLP exporters
*
* This sets up:
* - Traces (OTLP HTTP)
* - Metrics (OTLP HTTP)
* - Logs (OTLP HTTP)
* - Auto-instrumentation for common Node.js libraries
*
* @example
* // Call this at the very start of your application
* import { initInstrumentation } from '@your-org/otel-decorators'
*
* initInstrumentation({
* serviceName: 'my-service' }
* serviceVersion: '1.0.0',
* deploymentEnvironment: 'production',
* otlpEndpoint: 'http://localhost:4318'
* })
*
* // Or with async resource detection (top-level await required)
* await initInstrumentation({
* serviceName: 'my-service' }
* detectResources: true
* })
*/
let currentSDK = null;
let shutdownHandlerRegistered = false;
/**
* Shutdown the OpenTelemetry SDK gracefully
* Call this before process exit or during hot-reloads
*/
async function shutdownInstrumentation(sdk) {
const sdkToShutdown = sdk || currentSDK;
if (!sdkToShutdown) {
require_init.getLogger().warn({}, "No SDK to shutdown");
return;
}
try {
await sdkToShutdown.shutdown();
require_init.getLogger().info({}, "OpenTelemetry terminated successfully");
if (sdkToShutdown === currentSDK) currentSDK = null;
} catch (error) {
require_init.getLogger().error({ err: error instanceof Error ? error : void 0 }, "Error terminating OpenTelemetry");
throw error;
}
}
async function initInstrumentation(config) {
if (currentSDK) {
require_init.getLogger().info({}, "Shutting down existing OpenTelemetry SDK before reinitializing...");
await shutdownInstrumentation(currentSDK);
}
const otlpHeaders = parseOtlpHeaders(config.headers);
const customResourceAttributes = parseResourceAttributes(config.resourceAttributes);
let resource;
const detectors = [_opentelemetry_resources.processDetector, _opentelemetry_resources.hostDetector];
try {
const awsDetectors = await import("@opentelemetry/resource-detector-aws");
detectors.push(awsDetectors.awsEc2Detector, awsDetectors.awsEcsDetector, awsDetectors.awsEksDetector);
} catch {}
try {
const gcpDetectors = await import("@opentelemetry/resource-detector-gcp");
detectors.push(gcpDetectors.gcpDetector);
} catch {}
try {
const containerDetectors = await import("@opentelemetry/resource-detector-container");
detectors.push(containerDetectors.containerDetector);
} catch {}
if (config.detectResources) resource = (await (0, _opentelemetry_resources.detectResources)({ detectors })).merge((0, _opentelemetry_resources.resourceFromAttributes)({
[_opentelemetry_semantic_conventions_incubating.ATTR_SERVICE_NAME]: config.serviceName,
[_opentelemetry_semantic_conventions_incubating.ATTR_SERVICE_VERSION]: config.serviceVersion || "1.0.0",
"deployment.environment": config.deploymentEnvironment || "development",
...customResourceAttributes
}));
else resource = (0, _opentelemetry_resources.resourceFromAttributes)({
[_opentelemetry_semantic_conventions_incubating.ATTR_SERVICE_NAME]: config.serviceName,
[_opentelemetry_semantic_conventions_incubating.ATTR_SERVICE_VERSION]: config.serviceVersion || "1.0.0",
"deployment.environment": config.deploymentEnvironment || "development",
...customResourceAttributes
});
let instrumentations = config.instrumentations || [];
if (config.selectiveInstrumentation === false) instrumentations = [require_node_require.requireModule("@opentelemetry/auto-instrumentations-node").getNodeAutoInstrumentations()];
const spanProcessor = new require_tail_sampling_processor.TailSamplingSpanProcessor(new _opentelemetry_sdk_trace_base.BatchSpanProcessor(new _opentelemetry_exporter_trace_otlp_http.OTLPTraceExporter({
url: `${config.otlpEndpoint || "http://localhost:4318"}/v1/traces`,
headers: otlpHeaders
})));
const sdk = new _opentelemetry_sdk_node.NodeSDK({
resource,
spanProcessor,
metricReader: new _opentelemetry_sdk_metrics.PeriodicExportingMetricReader({ exporter: new _opentelemetry_exporter_metrics_otlp_http.OTLPMetricExporter({
url: `${config.otlpEndpoint || "http://localhost:4318"}/v1/metrics`,
headers: otlpHeaders
}) }),
logRecordProcessors: [new _opentelemetry_sdk_logs.BatchLogRecordProcessor(new _opentelemetry_exporter_logs_otlp_http.OTLPLogExporter({
url: `${config.otlpEndpoint || "http://localhost:4318"}/v1/logs`,
headers: otlpHeaders
}))],
instrumentations
});
try {
await sdk.start();
require_init.getLogger().info({}, "OpenTelemetry instrumentation started successfully");
} catch (error) {
require_init.getLogger().error({ err: error instanceof Error ? error : void 0 }, "Failed to start OpenTelemetry SDK");
throw error;
}
currentSDK = sdk;
if (!shutdownHandlerRegistered) {
shutdownHandlerRegistered = true;
const shutdownHandler = () => {
shutdownInstrumentation().then(() => {
process.exit(0);
}).catch((error) => {
require_init.getLogger().error({ err: error instanceof Error ? error : void 0 }, "Shutdown error");
process.exit(1);
});
};
process.on("SIGTERM", shutdownHandler);
process.on("SIGINT", shutdownHandler);
}
return sdk;
}
//#endregion
exports.initInstrumentation = initInstrumentation;
exports.shutdownInstrumentation = shutdownInstrumentation;
//# sourceMappingURL=instrumentation.cjs.map