UNPKG

@kdump/code-cli-any-llm

Version:

> A unified gateway for the Gemini, opencode, crush, and Qwen Code AI CLIs

239 lines 9.37 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GatewayLoggerService = void 0; const common_1 = require("@nestjs/common"); const fs_1 = require("fs"); const os_1 = __importDefault(require("os")); const path_1 = __importDefault(require("path")); const util_1 = require("util"); const DEFAULT_LOG_DIR = path_1.default.join(os_1.default.homedir(), '.code-cli-any-llm', 'logs'); const DEFAULT_FILE_PREFIX = 'gateway'; class GatewayLoggerService extends common_1.ConsoleLogger { static instance = null; static logStream = null; static logFilePath = ''; static logDir = DEFAULT_LOG_DIR; static filePrefix = DEFAULT_FILE_PREFIX; static stackTracePattern = /^(.)+\n\s+at .+:\d+:\d+/; constructor(options) { const { logDir, filePrefix, ...consoleOptions } = options ?? {}; super(consoleOptions); GatewayLoggerService.applyLogDestination(logDir, filePrefix); GatewayLoggerService.ensureLogStream(); } static create(options) { if (!GatewayLoggerService.instance) { GatewayLoggerService.instance = new GatewayLoggerService(options); } else if (options) { let reopened = false; if (options.logDir || options.filePrefix) { reopened = GatewayLoggerService.applyLogDestination(options.logDir, options.filePrefix); if (reopened) { GatewayLoggerService.ensureLogStream(); } } if (options.logLevels) { GatewayLoggerService.instance.setLogLevels(options.logLevels); } } return GatewayLoggerService.instance; } static getLogFilePath() { GatewayLoggerService.ensureLogStream(); return GatewayLoggerService.logFilePath; } static close() { if (!GatewayLoggerService.logStream) { return; } GatewayLoggerService.logStream.end(); GatewayLoggerService.logStream = null; } log(message, ...optionalParams) { super.log(message, ...optionalParams); this.persistIfEnabled('log', 'INFO', message, optionalParams); } error(message, ...optionalParams) { super.error(message, ...optionalParams); this.persistIfEnabled('error', 'ERROR', message, optionalParams); } warn(message, ...optionalParams) { super.warn(message, ...optionalParams); this.persistIfEnabled('warn', 'WARN', message, optionalParams); } debug(message, ...optionalParams) { super.debug(message, ...optionalParams); this.persistIfEnabled('debug', 'DEBUG', message, optionalParams); } verbose(message, ...optionalParams) { super.verbose(message, ...optionalParams); this.persistIfEnabled('verbose', 'VERBOSE', message, optionalParams); } fatal(message, ...optionalParams) { super.fatal?.(message, ...optionalParams); this.persistIfEnabled('fatal', 'FATAL', message, optionalParams); } setLogLevels(levels) { super.setLogLevels(levels); } persistIfEnabled(level, label, message, optionalParams) { if (!this.isLevelEnabled(level)) { return; } this.persist(label, message, optionalParams); } persist(level, message, optionalParams) { if (!GatewayLoggerService.logStream) { return; } const timestamp = new Date().toISOString(); const { context, rest } = GatewayLoggerService.extractContext(optionalParams); const parts = [`[${timestamp}]`, `[${level}]`]; if (context) { parts.push(`[${context}]`); } const baseMessage = GatewayLoggerService.stringify(message); let line = `${parts.join(' ')} ${baseMessage}`; for (const param of rest) { const formatted = GatewayLoggerService.formatExtra(param); if (formatted.startsWith('\n')) { line += formatted; } else { line += ` ${formatted}`; } } GatewayLoggerService.logStream.write(`${line}\n`); } static formatExtra(value) { if (value instanceof Error) { return value.stack ? `\n${value.stack}` : value.message; } if (typeof value === 'string') { return GatewayLoggerService.isStackTrace(value) ? `\n${value}` : value; } if (typeof value === 'object') { try { return JSON.stringify(value); } catch { return (0, util_1.inspect)(value, { depth: 5, breakLength: Infinity }); } } return String(value); } static stringify(value) { if (value instanceof Error) { return value.message ?? value.toString(); } if (typeof value === 'string') { return value; } if (typeof value === 'object') { try { return JSON.stringify(value); } catch { return (0, util_1.inspect)(value, { depth: 5, breakLength: Infinity }); } } return String(value); } static extractContext(params) { if (!params.length) { return { rest: [] }; } const last = params[params.length - 1]; if (typeof last === 'string' && !GatewayLoggerService.isStackTrace(last)) { return { context: last, rest: params.slice(0, -1) }; } return { rest: params }; } static isStackTrace(value) { return (typeof value === 'string' && GatewayLoggerService.stackTracePattern.test(value)); } static ensureLogStream() { if (GatewayLoggerService.logStream) { return; } (0, fs_1.mkdirSync)(GatewayLoggerService.logDir, { recursive: true }); const baseFilePath = path_1.default.join(GatewayLoggerService.logDir, `${GatewayLoggerService.filePrefix}.log`); GatewayLoggerService.rotateExistingLog(baseFilePath); GatewayLoggerService.logFilePath = baseFilePath; GatewayLoggerService.logStream = (0, fs_1.createWriteStream)(baseFilePath, { flags: 'a', encoding: 'utf8', }); } static getDefaultLogDir() { return DEFAULT_LOG_DIR; } static applyLogDestination(logDir, filePrefix) { const resolvedDir = GatewayLoggerService.resolveLogDir(logDir); const resolvedPrefix = GatewayLoggerService.resolveFilePrefix(filePrefix); const dirChanged = resolvedDir !== GatewayLoggerService.logDir; const prefixChanged = resolvedPrefix !== GatewayLoggerService.filePrefix; if (dirChanged || prefixChanged) { GatewayLoggerService.logDir = resolvedDir; GatewayLoggerService.filePrefix = resolvedPrefix; GatewayLoggerService.close(); return true; } return false; } static resolveLogDir(dir) { if (!dir || !dir.trim()) { return DEFAULT_LOG_DIR; } const trimmed = dir.trim(); if (trimmed === '~') { return os_1.default.homedir(); } if (trimmed.startsWith('~/') || trimmed.startsWith('~\\')) { const relative = trimmed.slice(2); return path_1.default.join(os_1.default.homedir(), relative); } if (trimmed.startsWith('~')) { const relative = trimmed.slice(1).replace(/^[\\/]/, ''); return path_1.default.join(os_1.default.homedir(), relative); } return path_1.default.isAbsolute(trimmed) ? trimmed : path_1.default.resolve(trimmed); } static resolveFilePrefix(prefix) { return prefix && prefix.trim().length > 0 ? prefix.trim() : DEFAULT_FILE_PREFIX; } static buildTimestamp() { const now = new Date(); const pad = (input) => input.toString().padStart(2, '0'); return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`; } static rotateExistingLog(baseFilePath) { if (!(0, fs_1.existsSync)(baseFilePath)) { return; } const timestamp = GatewayLoggerService.buildTimestamp(); let archivedFilePath = path_1.default.join(GatewayLoggerService.logDir, `${GatewayLoggerService.filePrefix}-${timestamp}.log`); if ((0, fs_1.existsSync)(archivedFilePath)) { let suffix = 1; do { archivedFilePath = path_1.default.join(GatewayLoggerService.logDir, `${GatewayLoggerService.filePrefix}-${timestamp}-${suffix}.log`); suffix += 1; } while ((0, fs_1.existsSync)(archivedFilePath)); } try { (0, fs_1.renameSync)(baseFilePath, archivedFilePath); } catch (error) { process.stderr.write(`Failed to rename gateway log file, continuing with the existing file: ${error.message}\n`); } } } exports.GatewayLoggerService = GatewayLoggerService; //# sourceMappingURL=gateway-logger.service.js.map