import { DisableTelemetry } from "../../EnvironmentConfig";
import { AsyncLocalStorage } from "async_hooks";
/**
 * Ambient, mutable telemetry context backed by AsyncLocalStorage.
 *
 * Why this exists: OpenTelemetry span attributes do NOT propagate from a
 * parent span to its children, and OneUptime sets tenant context (projectId,
 * userId, ...) deep in middleware while the spans that matter are created much
 * further down the call stack. Rather than thread attributes through every
 * function or tag ~1958 `@CaptureSpan` call sites by hand, we keep a small
 * mutable attribute bag scoped to the current unit of work. `ContextSpanProcessor`
 * stamps it onto every span at creation, and `Logger` merges it into every log
 * record — so context flows everywhere automatically.
 *
 * Seed a scope at each entry point with `runWithContext`, then enrich it as
 * more identifiers become known with `setAttributes`.
 */
class TelemetryContext {
    /**
     * Run `fn` within a fresh telemetry-context scope seeded with `attributes`.
     * Any attributes from an enclosing scope are inherited so nested units of
     * work (e.g. a job spawned while handling a request) keep their context.
     */
    static runWithContext(attributes, fn) {
        if (DisableTelemetry) {
            return fn();
        }
        const inherited = this.getAttributes();
        const store = {
            attributes: Object.assign({}, inherited),
        };
        this.mergeInto(store.attributes, attributes);
        return this.storage.run(store, fn);
    }
    /**
     * Merge `attributes` into the current scope. No-op when there is no active
     * scope (e.g. code running outside any seeded entry point) or telemetry is
     * disabled, so it is always safe to call.
     */
    static setAttributes(attributes) {
        if (DisableTelemetry) {
            return;
        }
        const store = this.storage.getStore();
        if (!store) {
            return;
        }
        this.mergeInto(store.attributes, attributes);
    }
    /**
     * Read the attributes for the current scope. Returns an empty object when
     * there is no active scope. The returned object is the live store — treat it
     * as read-only (consumers copy it before mutating).
     */
    static getAttributes() {
        const store = this.storage.getStore();
        if (!store) {
            return {};
        }
        return store.attributes;
    }
    /**
     * Best-effort extraction of known tenant/business identifiers from an
     * arbitrary object (e.g. a queue job's `data` payload), so worker jobs can
     * seed context without every job knowing about telemetry. Values are coerced
     * to strings; unknown/empty values are skipped.
     */
    static pickKnownAttributes(data) {
        const attributes = {};
        if (!data || typeof data !== "object") {
            return attributes;
        }
        const record = data;
        for (const key of this.KNOWN_ID_KEYS) {
            const value = record[key];
            if (value === undefined || value === null) {
                continue;
            }
            if (typeof value === "string" ||
                typeof value === "number" ||
                typeof value === "boolean") {
                attributes[key] = value;
                continue;
            }
            // ObjectID-like values expose a meaningful toString().
            const asString = String(value);
            if (asString && asString !== "[object Object]") {
                attributes[key] = asString;
            }
        }
        return attributes;
    }
    static mergeInto(target, attributes) {
        for (const key in attributes) {
            const value = attributes[key];
            if (value !== undefined && value !== null) {
                target[key] = value;
            }
        }
    }
}
TelemetryContext.storage = new AsyncLocalStorage();
/**
 * Identifier keys we look for when seeding context from an arbitrary payload
 * (see {@link pickKnownAttributes}).
 */
TelemetryContext.KNOWN_ID_KEYS = [
    "projectId",
    "userId",
    "monitorId",
    "incidentId",
    "alertId",
    "statusPageId",
    "scheduledMaintenanceId",
    "onCallDutyPolicyId",
    "onCallDutyPolicyScheduleId",
    "incidentEpisodeId",
    "alertEpisodeId",
    "workspaceType",
    "channelId",
    "requestId",
];
export default TelemetryContext;
//# sourceMappingURL=TelemetryContext.js.map