"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PerformanceService = void 0;
const os_1 = require("os");
const helpers_1 = require("../common/helpers");
const semver = require("semver");
const _ = require("lodash");
const yok_1 = require("../common/yok");
class PerformanceService {
    constructor($options, $fs, $logger, $analyticsService) {
        this.$options = $options;
        this.$fs = $fs;
        this.$logger = $logger;
        this.$analyticsService = $analyticsService;
        this.performance = null;
        if (this.isPerformanceModuleSupported()) {
            this.performance = require("perf_hooks").performance;
        }
    }
    processExecutionData(methodInfo, startTime, endTime, args) {
        const executionTime = Math.floor(endTime - startTime);
        this.trackAnalyticsData(methodInfo, executionTime);
        if (typeof this.$options.performance === "string") {
            this.logDataToFile(this.$options.performance, methodInfo, executionTime, args);
        }
        else if (this.$options.performance) {
            this.$logger.info(PerformanceService.LOG_MESSAGE_TEMPLATE, methodInfo, executionTime);
        }
    }
    now() {
        if (this.isPerformanceModuleSupported()) {
            return this.performance.now();
        }
        else {
            return new Date().getTime();
        }
    }
    isPerformanceModuleSupported() {
        return semver.gte(process.version, PerformanceService.MIN_NODE_PERFORMANCE_MODULE_VERSION);
    }
    trackAnalyticsData(methodInfo, executionTime) {
        this.$analyticsService
            .trackEventActionInGoogleAnalytics({
            action: "Performance",
            additionalData: methodInfo,
            value: executionTime,
        })
            .catch((err) => {
            throw err;
        });
    }
    logDataToFile(filePath, methodInfo, executionTime, args) {
        let methodArgs;
        try {
            methodArgs = JSON.stringify(args, this.getJsonSanitizer());
        }
        catch (e) {
            methodArgs = "cyclic args";
        }
        const info = {
            methodInfo,
            executionTime,
            timestamp: (0, helpers_1.getFixedLengthDateString)(),
            methodArgs: JSON.parse(methodArgs),
        };
        try {
            this.$fs.appendFile(filePath, `${JSON.stringify(info)}${os_1.EOL}`);
        }
        catch (e) {
            this.$logger.trace(PerformanceService.FAIL_LOG_MESSAGE_TEMPLATE, methodInfo);
            this.$logger.info(PerformanceService.LOG_MESSAGE_TEMPLATE, methodInfo, executionTime);
        }
    }
    getJsonSanitizer() {
        const seen = new WeakSet();
        seen.add(this.$options);
        return (key, value) => {
            if (typeof value === "object" && value !== null) {
                if (seen.has(value) || _.startsWith(key, "$")) {
                    return;
                }
                seen.add(value);
            }
            return value;
        };
    }
}
PerformanceService.LOG_MESSAGE_TEMPLATE = `Execution of method "%s" took %s ms.`;
PerformanceService.FAIL_LOG_MESSAGE_TEMPLATE = `Failed to log pefromance data in file for method %s.`;
PerformanceService.MIN_NODE_PERFORMANCE_MODULE_VERSION = "8.5.0";
exports.PerformanceService = PerformanceService;
yok_1.injector.register("performanceService", PerformanceService);
