Skip to main content
Glama

mcptix

by ownlytics
logger.js13.2 kB
"use strict"; /** * mcptix Logger * A centralized logging system with console and file output */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Logger = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const chalk_1 = __importDefault(require("chalk")); /** * Environment detection for MCP server mode * Using a function instead of a constant ensures we always have the latest value, * even if the environment variable is set after this module is initialized */ function isMcpMode() { return process.env.MCPTIX_MCP_MODE === 'true'; } /** * Log levels with corresponding colors */ var LogLevel; (function (LogLevel) { LogLevel["INFO"] = "info"; LogLevel["SUCCESS"] = "success"; LogLevel["WARN"] = "warn"; LogLevel["ERROR"] = "error"; LogLevel["DEBUG"] = "debug"; LogLevel["REQUEST"] = "request"; })(LogLevel || (LogLevel = {})); /** * Transport types for logging */ var LogTransport; (function (LogTransport) { LogTransport["CONSOLE"] = "console"; LogTransport["FILE"] = "file"; LogTransport["BOTH"] = "both"; })(LogTransport || (LogTransport = {})); /** * Centralized logger for mcptix * Provides consistent, color-coded logging across all components * with support for file-based logging for MCP mode */ class Logger { /** * Initialize the logger * Creates log directory if it doesn't exist */ static initialize() { // Create log directory if it doesn't exist and file logging is enabled if ([LogTransport.FILE, LogTransport.BOTH].includes(Logger.config.logTransport)) { try { if (!fs_1.default.existsSync(Logger.config.logDirectory)) { fs_1.default.mkdirSync(Logger.config.logDirectory, { recursive: true }); } Logger.logFilePath = path_1.default.join(Logger.config.logDirectory, Logger.config.logFilename); // Initialize log file with header const timestamp = new Date().toISOString(); const header = `\n\n==== MCPTIX LOG STARTED AT ${timestamp} ====\n`; fs_1.default.appendFileSync(Logger.logFilePath, header); // Log to stderr in MCP mode that we've initialized file logging if (isMcpMode()) { console.error(`[LOGGER] Initialized file logging at ${Logger.logFilePath}`); } } catch (error) { // Log to stderr that file logging failed console.error(`[LOGGER] Failed to initialize file logging: ${error instanceof Error ? error.message : String(error)}`); // Fallback to console logging Logger.config.logTransport = LogTransport.CONSOLE; } } } /** * Configure the logger * @param config Configuration options */ static configure(config) { const oldConfig = { ...Logger.config }; Logger.config = { ...Logger.config, ...config }; // Reinitialize if transport or directory changed if (oldConfig.logTransport !== Logger.config.logTransport || oldConfig.logDirectory !== Logger.config.logDirectory || oldConfig.logFilename !== Logger.config.logFilename) { Logger.initialize(); } } /** * Set the base directory for logs * @param baseDir Base directory for all mcptix files */ static setBaseDirectory(baseDir) { Logger.configure({ logDirectory: path_1.default.join(baseDir, 'logs'), }); } /** * Log an informational message * @param component Component name * @param message Message to log */ static info(component, message) { Logger.log(LogLevel.INFO, component, message); } /** * Log a success message * @param component Component name * @param message Message to log */ static success(component, message) { Logger.log(LogLevel.SUCCESS, component, message); } /** * Log a warning message * @param component Component name * @param message Message to log */ static warn(component, message) { Logger.log(LogLevel.WARN, component, message); } /** * Log an error message * @param component Component name * @param message Message to log * @param error Optional error object */ static error(component, message, error) { Logger.log(LogLevel.ERROR, component, message); if (error) { const errorMessage = error instanceof Error ? error.message : String(error); const errorStack = error instanceof Error && error.stack ? error.stack.split('\n').slice(1).join('\n') : ''; const formattedErrorDetail = ` Error details: ${errorMessage}`; const formattedStackTrace = ' Stack trace:'; // Log error details Logger.logToTransport(formattedErrorDetail, LogLevel.ERROR); // Log stack trace if available if (errorStack) { Logger.logToTransport(formattedStackTrace, LogLevel.ERROR); Logger.logToTransport(errorStack, LogLevel.ERROR); } } } /** * Log a debug message (only in debug mode) * @param component Component name * @param message Message to log */ static debug(component, message) { if (Logger.config.logLevel === 'debug') { Logger.log(LogLevel.DEBUG, component, message); } } /** * Log an HTTP request * @param method HTTP method * @param path Request path * @param status HTTP status code * @param time Request processing time in ms */ static request(method, path, status, time) { const methodColor = Logger.getMethodColor(method); const statusColor = status ? Logger.getStatusColor(status) : (text) => text; const methodStr = Logger.config.enableColors ? methodColor(method.padEnd(7)) : method.padEnd(7); const statusStr = status ? (Logger.config.enableColors ? statusColor(status.toString()) : status.toString()) : ''; const timeStr = time ? `${time}ms` : ''; const message = `${methodStr} ${path} ${statusStr} ${timeStr}`.trim(); Logger.log(LogLevel.REQUEST, 'API', message); } /** * Internal logging method * @param level Log level * @param component Component name * @param message Message to log */ static log(level, component, message) { // Skip if log level is higher than configured level if (!Logger.shouldLog(level)) { return; } const timestamp = Logger.config.showTimestamp ? `[${new Date().toISOString()}] ` : ''; const colorFn = Logger.getColor(level); const componentStr = `[${component}]`; const formattedComponent = Logger.config.enableColors ? colorFn(componentStr) : componentStr; const logMessage = `${timestamp}${formattedComponent} ${message}`; // Log to appropriate transport Logger.logToTransport(logMessage, level); } /** * Log to the configured transport * @param message Formatted message to log * @param level Log level */ static logToTransport(message, level) { // Initialize logger if not already done if ([LogTransport.FILE, LogTransport.BOTH].includes(Logger.config.logTransport) && !Logger.logFilePath) { Logger.initialize(); } // Get color function for the log level // We don't need to get the color function here since we're not using it // MCP mode check - must be evaluated at log time, not just initialization time const inMcpMode = isMcpMode(); // In MCP mode, always log to stderr to avoid interfering with stdout MCP protocol if (inMcpMode) { console.error(Logger.config.enableColors ? message : message); // Exit early - in MCP mode we don't want to risk logging to stdout return; } // For non-MCP mode, log to console if configured if ([LogTransport.CONSOLE, LogTransport.BOTH].includes(Logger.config.logTransport)) { if (level === LogLevel.ERROR || level === LogLevel.WARN) { // Use console.error for errors/warnings console.error(Logger.config.enableColors ? message : message); } else { // Use console.log for other messages console.log(Logger.config.enableColors ? message : message); } } // Log to file if configured and initialized if ([LogTransport.FILE, LogTransport.BOTH].includes(Logger.config.logTransport) && Logger.logFilePath) { try { // Remove color codes for file logging const plainMessage = message.replace(/\u001b\[\d+m/g, ''); fs_1.default.appendFileSync(Logger.logFilePath, `${plainMessage}\n`); } catch (error) { // Log to stderr if file logging fails console.error(`[LOGGER] Failed to write to log file: ${error instanceof Error ? error.message : String(error)}`); } } } /** * Check if a message at the given level should be logged * @param level Log level to check * @returns Whether the message should be logged */ static shouldLog(level) { const levels = ['debug', 'info', 'warn', 'error']; const configLevelIndex = levels.indexOf(Logger.config.logLevel); const messageLevelIndex = levels.indexOf(level.toLowerCase()); // Special case for 'success' and 'request' - treat as 'info' const effectiveMessageLevelIndex = messageLevelIndex >= 0 ? messageLevelIndex : levels.indexOf('info'); return effectiveMessageLevelIndex >= configLevelIndex; } /** * Get color function for log level * @param level Log level * @returns Function that colors text */ static getColor(level) { if (!Logger.config.enableColors) { return (text) => text; } switch (level) { case LogLevel.INFO: return (text) => chalk_1.default.blue(text); case LogLevel.SUCCESS: return (text) => chalk_1.default.green(text); case LogLevel.WARN: return (text) => chalk_1.default.yellow(text); case LogLevel.ERROR: return (text) => chalk_1.default.red(text); case LogLevel.DEBUG: return (text) => chalk_1.default.gray(text); case LogLevel.REQUEST: return (text) => chalk_1.default.cyan(text); default: return (text) => chalk_1.default.white(text); } } /** * Get color function for HTTP method * @param method HTTP method * @returns Chalk color function */ static getMethodColor(method) { if (!Logger.config.enableColors) { return (text) => text; } switch (method.toUpperCase()) { case 'GET': return (text) => chalk_1.default.green(text); case 'POST': return (text) => chalk_1.default.blue(text); case 'PUT': return (text) => chalk_1.default.yellow(text); case 'DELETE': return (text) => chalk_1.default.red(text); case 'PATCH': return (text) => chalk_1.default.magenta(text); default: return (text) => chalk_1.default.white(text); } } /** * Get color function for HTTP status code * @param status HTTP status code * @returns Function that colors text */ static getStatusColor(status) { if (!Logger.config.enableColors) { return (text) => text; } if (status >= 500) { return (text) => chalk_1.default.red(text); } else if (status >= 400) { return (text) => chalk_1.default.yellow(text); } else if (status >= 300) { return (text) => chalk_1.default.cyan(text); } else if (status >= 200) { return (text) => chalk_1.default.green(text); } else { return (text) => chalk_1.default.white(text); } } } exports.Logger = Logger; Logger.config = { enableColors: true, showTimestamp: true, logLevel: process.env.NODE_ENV === 'production' ? 'info' : 'debug', logTransport: isMcpMode() ? LogTransport.FILE : LogTransport.CONSOLE, logDirectory: process.env.MCPTIX_HOME_DIR ? path_1.default.join(process.env.MCPTIX_HOME_DIR, 'logs') : path_1.default.join(process.cwd(), '.mcptix', 'logs'), logFilename: 'mcptix.log', }; Logger.logFilePath = null; // Initialize the logger Logger.initialize(); //# sourceMappingURL=logger.js.map

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ownlytics/mcptix'

If you have feedback or need assistance with the MCP directory API, please join our Discord server