"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtendedLogger = exports.pinoLogger = exports.LoggerContextSymbol = exports.LoggerContextProps = exports.shouldUseSingleLine = exports.shouldUsePinoPretty = void 0;
exports.createLogger = createLogger;
exports.withLoggerContext = withLoggerContext;
const tslib_1 = require("tslib");
const __ΩError = ['name', 'message', 'stack', 'Error', 'P&4!&4"&4#8Mw$y'];
const __ΩInstanceType = ['T', 'args', 'new', 'InstanceType', 'l>e"!R"RPde#!P"@2"h"!/#qk#\'QRb!Pde"!p)w$y'];
function __assignType(fn, args) {
    fn.__type = args;
    return fn;
}
/*@ts-ignore*/
var { __ΩClassType } = require('@deepkit/core');
/*@ts-ignore*/
var { __ΩLogData, __ΩLoggerFormatter, __ΩLoggerLevel } = require('@deepkit/logger');
const logger_1 = require("@deepkit/logger");
const orm_1 = require("@deepkit/orm");
const axios_1 = require("axios");
const debug_1 = tslib_1.__importDefault(require("debug"));
const pino_1 = require("pino");
const config_1 = require("../app/config");
const const_1 = require("../app/const");
const helpers_1 = require("../helpers");
const resolver_1 = require("../app/resolver");
exports.shouldUsePinoPretty = (0, config_1.isDevFeatureEnabled)(process.env.ENABLE_PINO_PRETTY);
exports.shouldUseSingleLine = (0, config_1.isDevFeatureEnabled)(process.env.ENABLE_PINO_SINGLE_LINE);
exports.LoggerContextProps = ['http', 'job'];
exports.LoggerContextSymbol = Symbol('LoggerContext');
const PinoSeverityMap = {
    [logger_1.LoggerLevel.none]: 'DEFAULT',
    [logger_1.LoggerLevel.alert]: 'ALERT',
    [logger_1.LoggerLevel.error]: 'ERROR',
    [logger_1.LoggerLevel.warning]: 'WARNING',
    [logger_1.LoggerLevel.log]: 'NOTICE',
    [logger_1.LoggerLevel.info]: 'INFO',
    [logger_1.LoggerLevel.debug]: 'DEBUG',
    [logger_1.LoggerLevel.debug2]: 'DEBUG'
};
const __ΩSeverity = [() => PinoSeverityMap, () => PinoSeverityMap, 'Severity', 'i!i"gfw#y'];
const InvertedPinoSeverityMap = {
    DEFAULT: logger_1.LoggerLevel.none,
    ALERT: logger_1.LoggerLevel.alert,
    ERROR: logger_1.LoggerLevel.error,
    WARNING: logger_1.LoggerLevel.warning,
    NOTICE: logger_1.LoggerLevel.log,
    INFO: logger_1.LoggerLevel.info,
    DEBUG: logger_1.LoggerLevel.debug
};
const logStream = exports.shouldUsePinoPretty
    ? (() => {
        // eslint-disable-next-line @typescript-eslint/no-require-imports
        const PinoPretty = require('pino-pretty');
        return PinoPretty.default({
            colorize: true,
            singleLine: exports.shouldUseSingleLine,
            messageFormat: '\x1b[35m{scope} \x1b[36m{message}',
            ignore: 'scope',
            level: process.env.LOG_LEVEL || (process.env.NODE_ENV === 'production' ? 'info' : 'debug'),
            levelFirst: true,
            levelKey: 'severity',
            customLevels: Object.entries(InvertedPinoSeverityMap)
                .map(__assignType(([severity, level]) => `${severity}:${level}`, ['param0', '', 'P"2!"/"']))
                .join(','),
            messageKey: 'message',
            customColors: 'alert:bgRed,error:red,warning:yellow,notice:green,info:blue,debug:gray,default:white',
            sync: const_1.isTest
        });
    })()
    : undefined;
exports.pinoLogger = (0, pino_1.pino)({
    formatters: {
        level: __assignType(label => ({ severity: label }), ['label', '', 'P"2!"/"']),
        bindings: const_1.isDevelopment ? () => ({ pid: process.pid }) : () => ({})
    },
    timestamp: pino_1.stdTimeFunctions.isoTime,
    messageKey: 'message',
    customLevels: InvertedPinoSeverityMap,
    useOnlyCustomLevels: true,
    level: 'DEFAULT'
}, logStream);
class ExtendedLogger extends logger_1.Logger {
    addFormatter(formatter) {
        // - the server:start command injects DefaultFormatter after logger is instantiated
        // - the message that's transformed by DefaultFormatter is not used by the default JSON transport
        // - the color remover only removes colors from the prop the JSON transport *isn't* using
        // so don't allow the default formatter to be added, then use our custom JSON formatter
        // to read the original message prop after the color has been stripped
        if (formatter instanceof logger_1.DefaultFormatter) {
            return;
        }
        super.addFormatter(formatter);
    }
    scoped(shortName, data) {
        const name = this.scope.length ? `${this.scope}:${shortName}` : shortName;
        // If data is provided, always create a new instance to avoid sharing scopeData
        // between different callers (e.g., different SIP dialogs with different callIds)
        if (data) {
            const scoped = new ExtendedLogger(this.transporter, this.formatter, name);
            scoped.level = this.level;
            // Inherit parent's scopeData and merge with provided data
            scoped.scopeData = { ...this.scopeData, ...data };
            return scoped;
        }
        // For bare scoped loggers (no data), use caching
        if (!this.scopes[name]) {
            const scoped = new ExtendedLogger(this.transporter, this.formatter, name);
            scoped.level = this.level;
            if (this.scopeData) {
                scoped.scopeData = { ...this.scopeData };
            }
            this.scopes[name] = scoped;
        }
        return this.scopes[name];
    }
    // the first parameter can be a string or an object
    // if the first parameter is a string, the second can be an object
    // any funkier configurations than that, and we start stuffing indexed args onto the data object
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    send(messages, level, data) {
        let err = (0, helpers_1.isError)(messages[0]) ? messages.shift() : (0, helpers_1.isError)(messages[1]) ? messages.splice(1, 1).shift() : undefined;
        const message = typeof messages[0] === 'string' ? messages.shift() : '';
        if (messages.length === 1 && typeof messages[0] === 'object') {
            data = Object.assign(data ?? {}, messages[0]);
        }
        else if (messages.length) {
            data = data || {};
            messages.forEach(__assignType((msg, idx) => {
                data[`arg${idx}`] = msg;
            }, ['msg', 'idx', '', 'P"2!"2""/#']));
        }
        else {
            data = undefined;
        }
        if (!err && data && 'err' in data) {
            err = data.err;
            delete data.err;
        }
        if (this.scopeData) {
            data = Object.assign(data ?? {}, this.scopeData);
        }
        const strippedMessage = this.stripColors(message);
        // clean up errors that are too large and don't provide value to us
        if (err instanceof orm_1.DatabaseError) {
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            delete err.entity;
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            delete err.classSchema;
        }
        else if ((0, axios_1.isAxiosError)(err)) {
            err = transformAxiosError(err);
        }
        exports.pinoLogger[PinoSeverityMap[level]]({
            ...(err && { err }),
            ...(this.scope && { scope: this.scope }),
            ...data,
            ...this.getContextProps()
        }, strippedMessage);
        if (err || level === logger_1.LoggerLevel.alert || level === logger_1.LoggerLevel.error) {
            this.handleError(level, strippedMessage, err, data);
        }
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    debug(...message) {
        if (!(0, debug_1.default)(this.scope).enabled)
            return;
        this.send(message, logger_1.LoggerLevel.debug);
    }
    getContextProps() {
        const context = (0, helpers_1.getContext)();
        if (!context)
            return;
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const entries = [];
        for (const prop of exports.LoggerContextProps) {
            if (context[prop]) {
                entries.push([prop, context[prop]]);
            }
        }
        if (context[exports.LoggerContextSymbol]) {
            for (const [key, value] of Object.entries(context[exports.LoggerContextSymbol])) {
                entries.push([key, value]);
            }
        }
        if (!entries.length)
            return;
        return Object.fromEntries(entries);
    }
    stripColors(message) {
        return message.includes('<') ? message.replace(/<(\/)?([a-zA-Z]+)>/g, '') : message;
    }
    setScopeData(data) {
        this.scopeData = data;
        return this;
    }
    handleError(level, message, err, data) {
        const resolvedErr = message && message !== 'Controller error' ? new Error(message) : (err ?? new Error('Unknown error'));
        resolvedErr.cause = resolvedErr !== err ? err : undefined;
        (0, helpers_1.reportError)(level, resolvedErr, {
            data,
            scope: this.scope || undefined,
            scopeData: this.scopeData,
            ...this.getContextProps()
        });
    }
}
exports.ExtendedLogger = ExtendedLogger;
ExtendedLogger.__type = [() => logger_1.Logger, () => __ΩLogData, 'scopeData', () => __ΩLoggerFormatter, 'formatter', 'addFormatter', 'shortName', () => __ΩLogData, 'data', () => ExtendedLogger, 'scoped', 'messages', () => __ΩLoggerLevel, 'level', () => __ΩLogData, 'send', 'message', 'debug', 'getContextProps', 'stripColors', () => __ΩLogData, 'setScopeData', () => __ΩLoggerLevel, () => __ΩError, 'err', () => __ΩLogData, 'handleError', 'ExtendedLogger', 'P7!n"3#8<Pn$2%$0&P&2\'n(2)8P7*0+P"F2,n-2.n/2)8"00<P"@21$02P"03P&21"04Pn52)8"06Pn72.P&-J21Pn8-J29Pn:-J2)$0;5w<'];
function createLogger(subject, defaultData) {
    const name = typeof subject === 'string' ? subject : subject.constructor.name;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    return (resolver_1.r.Ω = [[() => ExtendedLogger, 'P7!']], (0, resolver_1.r)(logger_1.Logger)).scoped(name)
        .setScopeData(defaultData);
}
createLogger.__type = [() => __ΩInstanceType, () => __ΩClassType, 'subject', () => __ΩLogData, 'defaultData', 'createLogger', 'PP&n"o!"J2#n$2%8"/&'];
function withLoggerContext(data, fn) {
    const existingContext = (0, helpers_1.getContext)();
    return (0, helpers_1.withContextData)({
        [exports.LoggerContextSymbol]: {
            ...existingContext?.[exports.LoggerContextSymbol],
            ...data
        }
    }, fn);
}
withLoggerContext.__type = [() => __ΩLogData, 'data', '', 'fn', 'withLoggerContext', 'Pn!2"P"`/#2$"`/%'];
function transformAxiosError(err) {
    return {
        code: err.code,
        message: err.message,
        stack: err.stack,
        request: {
            url: err.config?.url,
            method: err.config?.method,
            headers: err.config?.headers,
            data: err.config?.data
        },
        response: {
            status: err.response?.status,
            headers: err.response?.headers,
            data: err.response?.data
        }
    };
}
transformAxiosError.__type = [() => axios_1.AxiosError, 'err', 'transformAxiosError', 'PP7!2""/#'];
//# sourceMappingURL=logger.js.map