UNPKG

deepsource-mcp-server

Version:
223 lines 7.87 kB
/** * @fileoverview Simple logging service for the application. * This provides a centralized place for all logging functionality. * * Configuration: * - LOG_LEVEL: Sets the minimum log level (DEBUG, INFO, WARN, ERROR). Defaults to DEBUG. * - LOG_FILE: Path to the log file. If not set, no logs will be written. * * Note: Since MCP servers use stdout for protocol communication, logs are written * to a file instead of stdout/stderr to avoid interference. */ import { writeFileSync, appendFileSync, existsSync, mkdirSync } from 'fs'; import { dirname } from 'path'; /** * Log levels for the application * @enum {string} */ // This enum is part of the public API and is used by consumers, even if not all values are used in this file /* eslint-disable no-unused-vars */ export var LogLevel; (function (LogLevel) { LogLevel["DEBUG"] = "DEBUG"; LogLevel["INFO"] = "INFO"; LogLevel["WARN"] = "WARN"; LogLevel["ERROR"] = "ERROR"; })(LogLevel || (LogLevel = {})); /* eslint-enable no-unused-vars */ /** * Environment-aware logging configuration */ const LOG_LEVELS_PRIORITY = { [LogLevel.DEBUG]: 0, [LogLevel.INFO]: 1, [LogLevel.WARN]: 2, [LogLevel.ERROR]: 3, }; /** * Get the log file path from environment * @returns {string | null} The log file path or null if not configured * @private */ function getLogFilePath() { return process.env.LOG_FILE || null; } let logFileInitialized = false; /** * Initialize the log file if needed by creating the directory and file * Only initializes once per process to avoid redundant file operations * @private * @returns {void} */ function initializeLogFile() { const logFile = getLogFilePath(); if (logFile && !logFileInitialized) { try { // Create directory if it doesn't exist const dir = dirname(logFile); if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }); } // Create or truncate the log file writeFileSync(logFile, ''); logFileInitialized = true; } catch { // Fail silently if we can't create the log file logFileInitialized = true; // Don't retry } } } /** * Write a log message to file * @param message The formatted log message to write * @private */ function writeToLogFile(message) { const logFile = getLogFilePath(); if (logFile) { try { if (!logFileInitialized) { initializeLogFile(); } appendFileSync(logFile, `${message}\n`); } catch { // Fail silently if we can't write to the log file } } } /** * Check if a log level should be displayed based on the environment configuration * @param level The log level to check * @returns {boolean} True if the log level should be displayed * @private */ function shouldLog(level) { const configuredLevel = (process.env.LOG_LEVEL || 'DEBUG'); return LOG_LEVELS_PRIORITY[level] >= LOG_LEVELS_PRIORITY[configuredLevel]; } /** * Format a log message with timestamp, level, and context information * @param level The log level of the message * @param message The log message content * @param context Optional context identifier * @returns {string} Formatted log message * @private */ function formatLogMessage(level, message, context) { const timestamp = new Date().toISOString(); const contextStr = context ? `[${context}] ` : ''; return `${timestamp} ${level} ${contextStr}${message}`; } /** * Logger service for consistent logging throughout the application */ export class Logger { context; /** * Create a new logger instance, optionally with a context * @param context Optional context name to identify the log source */ constructor(context) { this.context = context; } /** * Log a debug message * @param message The message to log * @param data Optional data to include in the log */ debug(message, data) { if (shouldLog(LogLevel.DEBUG) && getLogFilePath()) { const formattedMessage = formatLogMessage(LogLevel.DEBUG, message, this.context); const fullMessage = data !== undefined ? `${formattedMessage} ${JSON.stringify(data, null, 2)}` : formattedMessage; writeToLogFile(fullMessage); } } /** * Log an info message * @param message The message to log * @param data Optional data to include in the log */ info(message, data) { if (shouldLog(LogLevel.INFO) && getLogFilePath()) { const formattedMessage = formatLogMessage(LogLevel.INFO, message, this.context); const fullMessage = data !== undefined ? `${formattedMessage} ${JSON.stringify(data, null, 2)}` : formattedMessage; writeToLogFile(fullMessage); } } /** * Log a warning message * @param message The message to log * @param data Optional data to include in the log */ warn(message, data) { if (shouldLog(LogLevel.WARN) && getLogFilePath()) { const formattedMessage = formatLogMessage(LogLevel.WARN, message, this.context); const fullMessage = data !== undefined ? `${formattedMessage} ${JSON.stringify(data, null, 2)}` : formattedMessage; writeToLogFile(fullMessage); } } /** * Log an error message with improved error formatting * @param message The message to log * @param error Optional error to include in the log. The error will be formatted for better readability: * - Error objects will include name, message and stack trace * - Objects will be stringified with proper indentation * - Other values will be converted to strings */ error(message, error) { if (shouldLog(LogLevel.ERROR) && getLogFilePath()) { const formattedMessage = formatLogMessage(LogLevel.ERROR, message, this.context); // Format the error for better debugging let errorOutput = ''; if (error !== undefined) { if (error instanceof Error) { errorOutput = `${error.name}: ${error.message}${error.stack ? `\n${error.stack}` : ''}`; } else { try { errorOutput = JSON.stringify(error, null, 2); } catch { // Fallback to string representation if JSON.stringify fails errorOutput = String(error); } } } const fullMessage = errorOutput ? `${formattedMessage} ${errorOutput}` : formattedMessage; writeToLogFile(fullMessage); } } } /** * Default logger instance for the application * Pre-configured with the 'DeepSourceMCP' context for quick imports * @const {Logger} */ export const defaultLogger = new Logger('DeepSourceMCP'); /** * Helper function to create a logger with a specific context * @param context The context to use for the logger * @returns A new logger instance with the specified context */ export function createLogger(context) { return new Logger(context); } /** * Default export for simpler imports */ export default defaultLogger; // These log levels define the hierarchy for logging operations: // - DEBUG: Detailed information for debugging // - INFO: General information about application operation // - WARN: Warning events that might lead to issues // - ERROR: Error events that might still allow the application to continue // This helps maintain consistent logging patterns throughout the application //# sourceMappingURL=logger.js.map