@kdump/code-cli-any-llm
Version:
> A unified gateway for the Gemini, opencode, crush, and Qwen Code AI CLIs
239 lines • 9.37 kB
JavaScript
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
;