"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__ΩIOtelOptions = void 0;
exports.init = init;
const tslib_1 = require("tslib");
const __ΩRecord = ['K', 'T', 'Record', 'l\'e#"Rb!b"Pde"!N#!w#y'];
function __assignType(fn, args) {
    fn.__type = args;
    return fn;
}
/* eslint-disable @typescript-eslint/no-require-imports */
const opentelemetry_instrumentation_bullmq_1 = require("@jenniferplusplus/opentelemetry-instrumentation-bullmq");
const api_1 = require("@opentelemetry/api");
const exporter_metrics_otlp_http_1 = require("@opentelemetry/exporter-metrics-otlp-http");
const exporter_prometheus_1 = require("@opentelemetry/exporter-prometheus");
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
const instrumentation_1 = require("@opentelemetry/instrumentation");
const instrumentation_dns_1 = require("@opentelemetry/instrumentation-dns");
const instrumentation_http_1 = require("@opentelemetry/instrumentation-http");
const instrumentation_ioredis_1 = require("@opentelemetry/instrumentation-ioredis");
const instrumentation_undici_1 = require("@opentelemetry/instrumentation-undici");
const resources_1 = require("@opentelemetry/resources");
const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
const opentelemetry_node_metrics_1 = tslib_1.__importDefault(require("opentelemetry-node-metrics"));
const os_1 = require("os");
const const_1 = require("../../app/const");
const package_1 = require("../../helpers/io/package");
const helpers_1 = require("./helpers");
const MariaDBInstrumentation_1 = require("./MariaDBInstrumentation");
const __ΩIHttpAttributeHook = ['request', () => __ΩRecord, 'AttributeValue', '', 'IHttpAttributeHook', 'P!2!&"w#o"#/$w%y'];
const __ΩIOtelOptions = ['Instrumentation', 'instrumentations', () => __ΩIHttpAttributeHook, 'httpIncomingRequestAttributeHook', 'enableMetricsEndpoint', 'IOtelOptions', 'P"w!F4"8n#4$8)4%8Mw&y'];
exports.__ΩIOtelOptions = __ΩIOtelOptions;
function init(options) {
    const shouldInstallTraces = !!(process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ?? process.env.OTEL_EXPORTER_OTLP_ENDPOINT);
    const shouldPushMetrics = !!(process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT ?? process.env.OTEL_EXPORTER_OTLP_ENDPOINT);
    const metricsEndpointEnv = process.env.OTEL_METRICS_ENDPOINT_ENABLED;
    const metricsEndpointExplicitlyEnabled = metricsEndpointEnv === 'true' || metricsEndpointEnv === '1' || options?.enableMetricsEndpoint === true;
    const metricsEndpointExplicitlyDisabled = metricsEndpointEnv === 'false' || metricsEndpointEnv === '0' || options?.enableMetricsEndpoint === false;
    let shouldEnableMetricsEndpoint = metricsEndpointExplicitlyEnabled
        ? true
        : metricsEndpointExplicitlyDisabled
            ? false
            : undefined;
    if (shouldPushMetrics) {
        shouldEnableMetricsEndpoint ??= true;
    }
    const shouldInstallMetrics = shouldPushMetrics || !!shouldEnableMetricsEndpoint;
    if (!shouldInstallTraces && !shouldInstallMetrics) {
        console.log('OTEL_EXPORTER_* not configured. Not installing OpenTelemetry.');
        return;
    }
    if (process.env.OTEL_DEBUG) {
        api_1.diag.setLogger(new api_1.DiagConsoleLogger(), api_1.DiagLogLevel.DEBUG);
    }
    const pkgJson = (0, package_1.getPackageJson)();
    const resource = (0, resources_1.resourceFromAttributes)({
        'service.name': pkgJson?.name ?? 'unk',
        'service.version': pkgJson?.version ?? 'unk',
        'deployment.environment': process.env.APP_ENV,
        'host.name': (0, os_1.hostname)(),
        'process.pid': process.pid
    });
    (0, instrumentation_1.registerInstrumentations)({
        instrumentations: [
            new instrumentation_http_1.HttpInstrumentation({
                startIncomingSpanHook: options?.httpIncomingRequestAttributeHook,
                ignoreIncomingRequestHook: __assignType((request) => request.url === '/healthz' || request.url === '/metrics', ['request', '', 'P!2!"/"']),
                ignoreOutgoingRequestHook: __assignType((request) => !!request.host?.match(/sentry\./), ['request', '', 'P!2!"/"'])
            }),
            new instrumentation_undici_1.UndiciInstrumentation({
                ignoreRequestHook: __assignType((request) => /(\/healthz|\/metrics|sentry\.)/.test(request.path), ['UndiciRequest', 'request', '', 'P"w!2""/#'])
            }),
            new instrumentation_dns_1.DnsInstrumentation(),
            new instrumentation_ioredis_1.IORedisInstrumentation(),
            new opentelemetry_instrumentation_bullmq_1.BullMQInstrumentation(),
            new MariaDBInstrumentation_1.MariaDBInstrumentation(),
            ...(options?.instrumentations ?? [])
        ]
    });
    installDkSqlTracer();
    if (shouldInstallTraces) {
        const exporter = new exporter_trace_otlp_http_1.OTLPTraceExporter();
        const spanProcessor = const_1.isDevelopment ? new sdk_trace_node_1.SimpleSpanProcessor(exporter) : new sdk_trace_node_1.BatchSpanProcessor(exporter);
        const tracerProvider = new sdk_trace_node_1.NodeTracerProvider({ resource, spanProcessors: [spanProcessor] });
        tracerProvider.register();
        api_1.trace.setGlobalTracerProvider(tracerProvider);
        helpers_1.OtelState.tracer = tracerProvider.getTracer('default');
        const { setHttpContextResolver } = require('../../http');
        setHttpContextResolver(() => ({
            traceId: (0, helpers_1.getTraceContext)()?.traceId
        }));
        const { LoggerContextProps } = require('../../services');
        LoggerContextProps.push('traceId');
    }
    if (shouldInstallMetrics) {
        const readers = [];
        if (shouldPushMetrics) {
            const otlpExporter = new exporter_metrics_otlp_http_1.OTLPMetricExporter();
            readers.push(new sdk_metrics_1.PeriodicExportingMetricReader({
                exporter: otlpExporter,
                exportIntervalMillis: 10_000
            }));
        }
        if (shouldEnableMetricsEndpoint) {
            const prometheusExporter = new exporter_prometheus_1.PrometheusExporter({ preventServerStart: true });
            readers.push(prometheusExporter);
            helpers_1.OtelState.prometheusExporter = prometheusExporter;
        }
        const meterProvider = new sdk_metrics_1.MeterProvider({
            resource,
            readers
        });
        api_1.metrics.setGlobalMeterProvider(meterProvider);
        (0, opentelemetry_node_metrics_1.default)(meterProvider);
    }
    console.log('OpenTelemetry installed.');
}
init.__type = [() => __ΩIOtelOptions, 'options', 'init', 'Pn!2"8"/#'];
function installDkSqlTracer() {
    if (require.cache[require.resolve('mariadb')]) {
        throw new Error('mariadb was loaded prior to SQL instrumentation injection. Please correct dependency load order.');
    }
    const { Database } = require('@deepkit/orm');
    const originalTransaction = Database.prototype.transaction;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    Database.prototype.transaction = __assignType(function (callback) {
        return (0, helpers_1.withSpan)('sql.transaction', () => originalTransaction.call(this, callback));
    }, ['session', '', 'callback', 'PP"2!"`/"2#"`/"']);
}
installDkSqlTracer.__type = ['installDkSqlTracer', 'P"/!'];
//# sourceMappingURL=index.js.map