"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Console = exports.Logger = exports.level = exports.promiseRetry = void 0;
const os = require("os");
const openflow_api_1 = require("@openiap/openflow-api");
const Config_1 = require("./Config");
const dockerdriver_1 = require("./dockerdriver");
const DBHelper_1 = require("./DBHelper");
const amqpwrapper_1 = require("./amqpwrapper");
const fs = require('fs');
const path = require('path');
const MAX_RETRIES_DEFAULT = 5;
async function promiseRetry(fn, retries = MAX_RETRIES_DEFAULT, retryIntervalMillis, previousError) {
    return !retries
        ? Promise.reject(previousError)
        : fn().catch(async (error) => {
            await new Promise((resolve) => setTimeout(resolve, retryIntervalMillis));
            return promiseRetry(fn, retries - 1, retryIntervalMillis, error);
        });
}
exports.promiseRetry = promiseRetry;
var level;
(function (level) {
    level[level["Error"] = 1] = "Error";
    level[level["Warning"] = 2] = "Warning";
    level[level["Information"] = 3] = "Information";
    level[level["Debug"] = 4] = "Debug";
    level[level["Verbose"] = 5] = "Verbose";
    level[level["Silly"] = 6] = "Silly";
})(level = exports.level || (exports.level = {}));
class Logger {
    static parsecli(cli) {
        if (openflow_api_1.NoderedUtil.IsNullUndefinded(cli))
            return {};
        return { user: cli.username, agent: cli.clientagent, version: cli.clientversion, cid: cli.id, ip: cli.remoteip };
    }
    prefix(lvl, cls, func, message, collection, user, ms) {
        let White = Console.Reset + Console.Bright + Console.FgWhite;
        let Grey = Console.Reset + Console.Dim + Console.FgWhite;
        let Red = Console.Reset + Console.Bright + Console.FgRed;
        let Yellow = Console.Reset + Console.Bright + Console.FgYellow;
        let darkYellow = Console.Reset + Console.Dim + Console.FgYellow;
        let Blue = Console.Reset + Console.Bright + Console.FgBlue;
        let Cyan = Console.Reset + Console.Bright + Console.FgCyan;
        let Green = Console.Reset + Console.Bright + Console.FgGreen;
        let dt = new Date();
        if (cls == "cli" || cls == "cli-lic" || cls == "cliutil")
            cls = "";
        if (openflow_api_1.NoderedUtil.IsNullEmpty(cls))
            cls = "";
        if (typeof cls !== 'string') {
            try {
                cls = cls.toString();
            }
            catch (_a) {
                cls = "unknown";
            }
        }
        let prefix = "";
        let color = Cyan;
        if (lvl == level.Debug)
            color = Blue;
        if (lvl == level.Verbose || lvl == level.Silly)
            color = Grey;
        if (lvl == level.Error)
            color = Red;
        if (lvl == level.Warning)
            color = darkYellow;
        if (cls != "") {
            let dts = dt.getHours() + ":" + dt.getMinutes() + ":" + dt.getSeconds() + "." + dt.getMilliseconds();
            if (Logger.usecolors) {
                prefix = (dts.padEnd(13, " ") + "[" + cls.padEnd(21) + "][" + func + "]");
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(collection))
                    prefix += ("[" + collection + "]");
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(user))
                    prefix += ("[" + user + "]");
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(ms))
                    prefix += ("[" + ms + "ms]");
                prefix += (" ");
                let spaces = 0;
                if (prefix.length < 60)
                    spaces = 60 - prefix.length;
                prefix = Green +
                    dts.padEnd(13, " ") + White + "[" + darkYellow + cls.padEnd(21) + White + "][" + darkYellow + func + White + "] ";
                if (spaces > 0)
                    prefix += "".padEnd(spaces, " ");
            }
            else {
                prefix = dts.padEnd(13, " ") + "[" + cls.padEnd(21) + "][" + func + "]";
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(collection))
                    prefix += ("[" + collection + "]");
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(user))
                    prefix += ("[" + user + "]");
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(ms))
                    prefix += ("[" + ms + "ms]");
                prefix += (" ");
                prefix = prefix.padEnd(60, " ");
            }
        }
        if (Logger.usecolors) {
            return prefix + color + message + Console.Reset;
        }
        return prefix + message;
    }
    json(obj, span) {
        if (Config_1.Config.unittesting)
            return;
        const { cls, func, message, lvl } = obj;
        if (!openflow_api_1.NoderedUtil.IsNullEmpty(func) && span != null && span.isRecording()) {
            var stringifyError = function (err, filter, space) {
                var plainObject = {};
                Object.getOwnPropertyNames(err).forEach(function (key) {
                    plainObject[key] = err[key];
                });
                return JSON.stringify(plainObject, filter, space);
            };
            if (typeof obj.message == "object")
                obj.message = JSON.parse(stringifyError(obj.message, null, 2));
            if (lvl == level.Error) {
                span.setStatus({ code: 2, message: obj.message });
                span.recordException(message);
            }
            span.addEvent(obj.message, obj);
        }
        if (Logger.enabled[cls]) {
            if (Logger.enabled[cls] < lvl)
                return;
        }
        else {
            if (Config_1.Config.log_silly) {
                if (lvl > level.Silly)
                    return;
            }
            else if (Config_1.Config.log_debug) {
                if (lvl > level.Debug)
                    return;
            }
            else if (Config_1.Config.log_verbose) {
                if (lvl > level.Verbose)
                    return;
            }
            else if (lvl > level.Information) {
                if (Config_1.Config.log_database_queries && obj.ms != null && obj.ms != "") {
                    if (obj.ms < Config_1.Config.log_database_queries_ms)
                        return;
                }
                else {
                    return;
                }
            }
        }
        if (message instanceof Error) {
            console.error(message);
        }
        else if (lvl == level.Error) {
            console.error(this.prefix(lvl, cls, func, message, obj.collection, obj.user, obj.ms));
        }
        else if (lvl == level.Warning) {
            console.warn(this.prefix(lvl, cls, func, message, obj.collection, obj.user, obj.ms));
        }
        else if (lvl == level.Verbose || lvl == level.Silly) {
            console.debug(this.prefix(lvl, cls, func, message, obj.collection, obj.user, obj.ms));
        }
        else {
            console.log(this.prefix(lvl, cls, func, message, obj.collection, obj.user, obj.ms));
        }
        var stringifyError = function (err, filter, space) {
            var plainObject = {};
            Object.getOwnPropertyNames(err).forEach(function (key) {
                plainObject[key] = err[key];
            });
            return JSON.stringify(plainObject, filter, space);
        };
        if (Config_1.Config.log_to_exchange && !Config_1.Config.unittesting) {
            if (openflow_api_1.NoderedUtil.IsNullEmpty(Logger._hostname))
                Logger._hostname = (Config_1.Config.getEnv("HOSTNAME", undefined) || os.hostname()) || "unknown";
            if (amqpwrapper_1.amqpwrapper.Instance() && amqpwrapper_1.amqpwrapper.Instance().connected && amqpwrapper_1.amqpwrapper.Instance().of_logger_ready) {
                if (typeof obj.message == "object")
                    obj.message = JSON.parse(stringifyError(obj.message, null, 2));
                amqpwrapper_1.amqpwrapper.Instance().send("openflow_logs", "", { ...obj, host: Logger._hostname }, 500, null, "", span, 1);
            }
        }
    }
    error(message, span, options) {
        var s = Logger.getStackInfo(0);
        if (s.method == "")
            s = Logger.getStackInfo(1);
        if (s.method == "")
            s = Logger.getStackInfo(2);
        var obj = { cls: "", func: "", message, lvl: level.Error };
        if (options != null)
            obj = { ...obj, ...options };
        if (s.method.indexOf(".") > 1 && s.method.indexOf("<anonymous>") == -1) {
            obj.func = s.method.substring(s.method.indexOf(".") + 1);
            obj.cls = s.method.substring(0, s.method.indexOf("."));
        }
        else {
            obj.func = s.method;
            obj.cls = "";
            if (s.file != '')
                obj.cls = s.file.replace(".js", "");
        }
        if (obj.cls == "") {
            var c = obj.cls;
        }
        this.json(obj, span);
    }
    info(message, span, options) {
        var s = Logger.getStackInfo(0);
        if (s.method == "")
            s = Logger.getStackInfo(1);
        if (s.method == "")
            s = Logger.getStackInfo(2);
        var obj = { cls: "", func: "", message, lvl: level.Information };
        if (options != null)
            obj = { ...obj, ...options };
        if (s.method.indexOf(".") > 1) {
            obj.func = s.method.substring(s.method.indexOf(".") + 1);
            obj.cls = s.method.substring(0, s.method.indexOf("."));
            if (s.file != '')
                obj.cls = s.file.replace(".js", "");
        }
        else {
            obj.func = s.method;
            obj.cls = "";
            if (s.file != '')
                obj.cls = s.file.replace(".js", "");
        }
        if (obj.cls == "") {
            var c = obj.cls;
        }
        this.json(obj, span);
    }
    warn(message, span, options) {
        var s = Logger.getStackInfo(0);
        if (s.method == "")
            s = Logger.getStackInfo(1);
        if (s.method == "")
            s = Logger.getStackInfo(2);
        var obj = { cls: "", func: "", message, lvl: level.Warning };
        if (options != null)
            obj = { ...obj, ...options };
        if (s.method.indexOf(".") > 1) {
            obj.func = s.method.substring(s.method.indexOf(".") + 1);
            obj.cls = s.method.substring(0, s.method.indexOf("."));
        }
        else {
            obj.func = s.method;
            obj.cls = "";
            if (s.file != '')
                obj.cls = s.file.replace(".js", "");
        }
        if (obj.cls == "") {
            var c = obj.cls;
        }
        this.json(obj, span);
    }
    debug(message, span, options) {
        var s = Logger.getStackInfo(0);
        if (s.method == "")
            s = Logger.getStackInfo(1);
        if (s.method == "")
            s = Logger.getStackInfo(2);
        var obj = { cls: "", func: "", message, lvl: level.Debug };
        if (options != null)
            obj = { ...obj, ...options };
        if (s.method.indexOf(".") > 1) {
            obj.func = s.method.substring(s.method.indexOf(".") + 1);
            obj.cls = s.method.substring(0, s.method.indexOf("."));
        }
        else {
            obj.func = s.method;
            obj.cls = "";
            if (s.file != '')
                obj.cls = s.file.replace(".js", "");
        }
        if (obj.cls == "") {
            var c = obj.cls;
        }
        this.json(obj, span);
    }
    verbose(message, span, options) {
        var s = Logger.getStackInfo(0);
        if (s.method == "")
            s = Logger.getStackInfo(1);
        if (s.method == "")
            s = Logger.getStackInfo(2);
        var obj = { cls: "", func: "", message, lvl: level.Verbose };
        if (options != null)
            obj = { ...obj, ...options };
        if (s.method.indexOf(".") > 1) {
            obj.func = s.method.substring(s.method.indexOf(".") + 1);
            obj.cls = s.method.substring(0, s.method.indexOf("."));
        }
        else {
            obj.func = s.method;
            obj.cls = "";
            if (s.file != '')
                obj.cls = s.file.replace(".js", "");
        }
        if (obj.cls == "") {
            var c = obj.cls;
        }
        this.json(obj, span);
    }
    silly(message, span, options) {
        var s = Logger.getStackInfo(0);
        if (s.method == "")
            s = Logger.getStackInfo(1);
        if (s.method == "")
            s = Logger.getStackInfo(2);
        var obj = { cls: "", func: "", message, lvl: level.Silly };
        if (options != null)
            obj = { ...obj, ...options };
        if (s.method.indexOf(".") > 1) {
            obj.func = s.method.substring(s.method.indexOf(".") + 1);
            obj.cls = s.method.substring(0, s.method.indexOf("."));
        }
        else {
            obj.func = s.method;
            obj.cls = "";
            if (s.file != '')
                obj.cls = s.file.replace(".js", "");
        }
        if (obj.cls == "") {
            var c = obj.cls;
        }
        this.json(obj, span);
    }
    static async shutdown() {
        Logger.License.shutdown();
        if (Config_1.Config.db != null)
            await Config_1.Config.db.shutdown();
        await Logger.otel.shutdown();
    }
    static reload() {
        Logger.log_with_trace = Config_1.Config.log_with_trace;
        Logger.usecolors = Config_1.Config.log_with_colors;
        // if (Config.NODE_ENV == "development") Logger.log_with_trace = true;
        Logger.enabled = {};
        if (Config_1.Config.log_cache)
            Logger.enabled["DBHelper"] = level.Verbose;
        if (Config_1.Config.log_amqp)
            Logger.enabled["amqpwrapper"] = level.Verbose;
        if (Config_1.Config.log_login_provider)
            Logger.enabled["LoginProvider"] = level.Verbose;
        if (Config_1.Config.log_websocket)
            Logger.enabled["WebSocketServer"] = level.Verbose;
        if (Config_1.Config.log_websocket)
            Logger.enabled["WebSocketServerClient"] = level.Verbose;
        if (Config_1.Config.log_oauth)
            Logger.enabled["OAuthProvider"] = level.Verbose;
        if (Config_1.Config.log_webserver)
            Logger.enabled["WebServer"] = level.Verbose;
        if (Config_1.Config.log_database)
            Logger.enabled["DatabaseConnection"] = level.Verbose;
        if (Config_1.Config.log_grafana)
            Logger.enabled["grafana-proxy"] = level.Verbose;
        if (Config_1.Config.log_housekeeping)
            Logger.enabled["Housekeeping"] = level.Verbose;
        if (Config_1.Config.log_otel)
            Logger.enabled["otel"] = level.Verbose;
        if (Config_1.Config.otel_debug_log)
            Logger.enabled["WebSocketServerClient"] = level.Verbose;
        if (Config_1.Config.otel_warn_log)
            Logger.enabled["WebSocketServerClient"] = level.Warning;
        if (Config_1.Config.otel_err_log)
            Logger.enabled["WebSocketServerClient"] = level.Error;
        if (Config_1.Config.log_database_queries)
            Logger.enabled["log_database_queries"] = level.Verbose;
    }
    static hasDockerEnv() {
        try {
            fs.statSync('/.dockerenv');
            return true;
        }
        catch (_) {
            return false;
        }
    }
    static hasDockerCGroup() {
        try {
            if (fs.readFileSync('/proc/self/cgroup', 'utf8').includes('docker'))
                return true;
            return fs.readFileSync('/proc/self/cgroup', 'utf8').includes('/kubepods');
        }
        catch (_) {
            return false;
        }
    }
    static isDocker() {
        if (Logger._isDocker != null)
            return Logger._isDocker;
        Logger._isDocker = Logger.hasDockerEnv() || Logger.hasDockerCGroup();
        return false;
    }
    static isKubernetes() {
        if (Logger._isKubernetes != null)
            return Logger._isKubernetes;
        if (!Logger.isDocker()) {
            Logger._isKubernetes = false;
            return false;
        }
        if (openflow_api_1.NoderedUtil.IsNullEmpty(process.env["KUBERNETES_SERVICE_HOST"])) {
            Logger._isKubernetes = false;
            return false;
        }
        Logger._isKubernetes = true;
        return true;
    }
    static async configure(skipotel, skiplic) {
        Logger.DBHelper = new DBHelper_1.DBHelper();
        Logger.reload();
        const filename = path.join(Config_1.Config.logpath, "openflow.log");
        const options = {
            file: {
                level: "debug",
                filename: filename,
                handleExceptions: false,
                json: true,
                maxsize: 5242880,
                maxFiles: 5,
                colorize: false,
            },
            console: {
                level: "debug",
                handleExceptions: false,
                json: false,
                colorize: true
            },
        };
        Logger.instanse = new Logger();
        let _lic_require = null;
        try {
            if (!skiplic)
                _lic_require = require("./ee/license-file");
        }
        catch (error) {
        }
        if (_lic_require != null) {
            Logger.License = new _lic_require.LicenseFile();
        }
        else {
            Logger.License = {};
            Logger.License.ofid = Logger.ofid;
            Logger.License.shutdown = () => undefined;
        }
        let _otel_require = null;
        try {
            if (!skipotel)
                _otel_require = require("./ee/otel");
        }
        catch (error) {
        }
        if (_otel_require != null) {
            Logger.otel = await _otel_require.otel.configure();
        }
        else {
            const fakespan = {
                context: () => undefined,
                setAttribute: () => undefined,
                setAttributes: () => undefined,
                addEvent: () => undefined,
                setStatus: () => undefined,
                updateName: () => undefined,
                end: () => undefined,
                isRecording: () => undefined,
                recordException: () => undefined,
            };
            Logger.otel =
                {
                    startSpan: () => fakespan,
                    startSubSpan: () => fakespan,
                    startSpanExpress: () => fakespan,
                    GetTraceSpanId(span) { return () => ["", ""]; },
                    endSpan: () => undefined,
                    startTimer: () => undefined,
                    endTimer: () => undefined,
                    setdefaultlabels: () => undefined,
                    shutdown: () => undefined,
                    meter: {
                        createHistogram: () => undefined,
                        createCounter: () => undefined,
                        createObservableUpDownCounter: () => undefined,
                        createUpDownCounter: () => undefined,
                        createValueObserver: () => undefined,
                        createObservableGauge: () => undefined,
                    }
                };
        }
        this.nodereddriver = null; // with npm -omit=optional we need to install npm i openid-client
        if (!openflow_api_1.NoderedUtil.IsNullEmpty(process.env["KUBERNETES_SERVICE_HOST"]) || !openflow_api_1.NoderedUtil.IsNullEmpty(process.env["USE_KUBERNETES"])) {
            let _driver = null;
            try {
                _driver = require("./ee/kubedriver");
            }
            catch (error) {
                console.log(error);
            }
            try {
                if (_driver != null) {
                    this.nodereddriver = new _driver.kubedriver();
                }
                else {
                    this.nodereddriver = new dockerdriver_1.dockerdriver();
                }
                if (_driver != null) {
                    if (!this.nodereddriver.detect()) {
                        this.nodereddriver = null;
                    }
                }
            }
            catch (error) {
                this.nodereddriver = null;
                Logger.instanse.error(error, null);
            }
        }
        if (this.nodereddriver == null) {
            try {
                this.nodereddriver = new dockerdriver_1.dockerdriver();
                if (!this.nodereddriver.detect()) {
                    this.nodereddriver = null;
                }
            }
            catch (error) {
                this.nodereddriver = null;
                Logger.instanse.error(error, null);
            }
        }
    }
    static ofid() {
        if (!openflow_api_1.NoderedUtil.IsNullEmpty(Logger._ofid))
            return Logger._ofid;
        var crypto = require('crypto');
        const openflow_uniqueid = Config_1.Config.openflow_uniqueid || crypto.createHash('md5').update(Config_1.Config.domain).digest("hex");
        Config_1.Config.openflow_uniqueid = openflow_uniqueid;
        Logger._ofid = openflow_uniqueid;
        return openflow_uniqueid;
    }
    static getStackInfo(stackIndex) {
        // get call stack, and analyze it
        // get all file, method, and line numbers
        var stacklist = (new Error()).stack.split('\n').slice(3);
        // stack trace format:
        // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
        // do not remove the regex expresses to outside of this method (due to a BUG in node.js)
        var stackReg = /at\s+(.*)\s+\((.*):(\d*):(\d*)\)/gi;
        var stackReg2 = /at\s+()(.*):(\d*):(\d*)/gi;
        var s = stacklist[stackIndex] || stacklist[0];
        var sp = stackReg.exec(s) || stackReg2.exec(s);
        if (sp && sp.length === 5) {
            return {
                method: sp[1] || "",
                relativePath: path.relative(__dirname, sp[2]),
                line: sp[3],
                pos: sp[4],
                file: path.basename(sp[2]),
                stack: stacklist.join('\n')
            };
        }
        else {
            return {
                method: "",
                relativePath: "",
                line: "",
                pos: "",
                file: "",
                stack: stacklist.join('\n')
            };
        }
    }
}
exports.Logger = Logger;
Logger.log_with_trace = false;
Logger.enabled = {};
Logger.usecolors = true;
Logger._hostname = "";
Logger._isDocker = null;
Logger._isKubernetes = null;
Logger.instanse = null;
Logger._ofid = null;
var Console;
(function (Console) {
    Console["Reset"] = "\u001B[0m";
    Console["Bright"] = "\u001B[1m";
    Console["Dim"] = "\u001B[2m";
    Console["Underscore"] = "\u001B[4m";
    Console["Blink"] = "\u001B[5m";
    Console["Reverse"] = "\u001B[7m";
    Console["Hidden"] = "\u001B[8m";
    Console["FgBlack"] = "\u001B[30m";
    Console["FgRed"] = "\u001B[31m";
    Console["FgGreen"] = "\u001B[32m";
    Console["FgYellow"] = "\u001B[33m";
    Console["FgBlue"] = "\u001B[34m";
    Console["FgMagenta"] = "\u001B[35m";
    Console["FgCyan"] = "\u001B[36m";
    Console["FgWhite"] = "\u001B[37m";
    Console["BgBlack"] = "\u001B[40m";
    Console["BgRed"] = "\u001B[41m";
    Console["BgGreen"] = "\u001B[42m";
    Console["BgYellow"] = "\u001B[43m";
    Console["BgBlue"] = "\u001B[44m";
    Console["BgMagenta"] = "\u001B[45m";
    Console["BgCyan"] = "\u001B[46m";
    Console["BgWhite"] = "\u001B[47m";
})(Console = exports.Console || (exports.Console = {}));
//# sourceMappingURL=Logger.js.map