"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module RpcInterface
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.RpcTrace = void 0;
exports.initializeTracing = initializeTracing;
// cspell:ignore calltrace
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const async_hooks_1 = require("async_hooks");
const BackendLoggerCategory_1 = require("../BackendLoggerCategory");
const IModelHost_1 = require("../IModelHost");
/* eslint-disable @typescript-eslint/no-deprecated */
/**
 * Utility for tracing Rpc activity processing. When multiple Rpc requests are being processed asynchronously, this
 * class can be used to correlate the current calltrace with the originating RpcActivity. This is used for automatic appending
 * of RpcActivity to log messages emitted during Rpc processing. It may also be used to retrieve the user accessToken
 * from the RpcActivity.
 * @public
 */
class RpcTrace {
    static _storage = new async_hooks_1.AsyncLocalStorage();
    /** Get the [RpcActivity]($common) for the currently executing async, or `undefined` if there is no
     * RpcActivity in the current call stack.
     * */
    static get currentActivity() {
        return RpcTrace._storage.getStore();
    }
    /** Get the [RpcActivity]($common) for the currently executing async. Asserts that the RpcActivity
     * exists in the current call stack.
     * */
    static get expectCurrentActivity() {
        (0, core_bentley_1.assert)(undefined !== RpcTrace.currentActivity);
        return RpcTrace.currentActivity;
    }
    /** Start the processing of an RpcActivity. */
    static async run(activity, fn) {
        return RpcTrace._storage.run(activity, fn);
    }
    /** Start the processing of an RpcActivity inside an OpenTelemetry span */
    static async runWithSpan(activity, fn) {
        return core_bentley_1.Tracing.withSpan(activity.rpcMethod ?? "unknown RPC method", async () => RpcTrace.run(activity, fn), {
            attributes: {
                ...core_bentley_1.Logger.getMetaData(), // add default metadata
                ...core_common_1.RpcInvocation.sanitizeForLog(activity), // override with the correct RpcActivity
            },
            kind: core_bentley_1.SpanKind.INTERNAL,
        });
    }
}
exports.RpcTrace = RpcTrace;
/** @internal */
function initializeTracing(enableOpenTelemetry = false) {
    core_common_1.RpcInvocation.runActivity = async (activity, fn) => RpcTrace.run(activity, fn); // redirect the invocation processing to the tracer
    if (enableOpenTelemetry) {
        try {
            // eslint-disable-next-line @typescript-eslint/no-require-imports
            const api = require("@opentelemetry/api");
            const tracer = api.trace.getTracer("@itwin/core-backend", IModelHost_1.IModelHost.backendVersion);
            core_bentley_1.Tracing.enableOpenTelemetry(tracer, api);
            core_common_1.RpcInvocation.runActivity = async (activity, fn) => RpcTrace.runWithSpan(activity, fn); // wrap invocation in an OpenTelemetry span in addition to RpcTrace
        }
        catch (e) {
            core_bentley_1.Logger.logWarning(BackendLoggerCategory_1.BackendLoggerCategory.IModelHost, "Failed to initialize OpenTelemetry");
            core_bentley_1.Logger.logError(BackendLoggerCategory_1.BackendLoggerCategory.IModelHost, e);
        }
    }
    // set up static logger metadata to include current RpcActivity information for logs during rpc processing
    core_bentley_1.Logger.staticMetaData.set("rpc", () => core_common_1.RpcInvocation.sanitizeForLog(RpcTrace.currentActivity));
}
//# sourceMappingURL=tracing.js.map