Skip to main content
Glama
loggingSystem.ts6.19 kB
import logger from '../utils/logger'; import path from 'path'; import fs from 'fs'; import { v4 as uuidv4 } from 'uuid'; /** * Log entry */ export interface LogEntry { id?: string; name: string; data: any; timestamp: string; } /** * Logging system * This is a simple system for storing and retrieving logs */ export class LoggingSystem { private static instance: LoggingSystem; private logsDir: string; private initialized: boolean = false; /** * Create a new logging system */ private constructor() { this.logsDir = path.join(process.cwd(), 'data', 'logs'); } /** * Get the singleton instance */ public static getInstance(): LoggingSystem { if (!LoggingSystem.instance) { LoggingSystem.instance = new LoggingSystem(); } return LoggingSystem.instance; } /** * Initialize the logging system */ private async ensureInitialized(): Promise<void> { if (!this.initialized) { // Create logs directory if it doesn't exist if (!fs.existsSync(this.logsDir)) { fs.mkdirSync(this.logsDir, { recursive: true }); } this.initialized = true; } } /** * Generate a unique ID */ private generateId(): string { return uuidv4(); } /** * Append to a log * * @param logName Log name * @param data Log data * @returns Log ID */ public async appendToLog(logName: string, data: any): Promise<string> { await this.ensureInitialized(); const logId = this.generateId(); const logEntry: LogEntry = { id: logId, name: logName, data, timestamp: new Date().toISOString() }; try { // Get the log file path const logFilePath = path.join(this.logsDir, `${logName}.json`); // Read existing log entries or create an empty array let entries: LogEntry[] = []; if (fs.existsSync(logFilePath)) { const fileContent = fs.readFileSync(logFilePath, 'utf8'); entries = JSON.parse(fileContent); } // Add the new entry entries.push(logEntry); // Write the updated entries back to the file fs.writeFileSync(logFilePath, JSON.stringify(entries, null, 2)); logger.info(`Appended to log: ${logName}, ID: ${logId}`); return logId; } catch (error) { logger.error(`Error appending to log: ${error instanceof Error ? error.message : String(error)}`); throw error; } } /** * Get a log by name * * @param logName Log name * @param limit Maximum number of entries to return * @returns Log entries */ public async getLogByName(logName: string, limit: number = 10): Promise<LogEntry[]> { await this.ensureInitialized(); try { // Get the log file path const logFilePath = path.join(this.logsDir, `${logName}.json`); // Check if the log file exists if (!fs.existsSync(logFilePath)) { logger.info(`Log not found: ${logName}`); return []; } // Read the log entries const fileContent = fs.readFileSync(logFilePath, 'utf8'); const entries: LogEntry[] = JSON.parse(fileContent); // Sort by timestamp (newest first) and limit the number of entries const sortedEntries = entries .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()) .slice(0, limit); logger.info(`Retrieved ${sortedEntries.length} entries for log: ${logName}`); return sortedEntries; } catch (error) { logger.error(`Error getting log by name: ${error instanceof Error ? error.message : String(error)}`); throw error; } } /** * Get all logs * * @param limit Maximum number of logs to return * @returns Logs */ public async getLogs(limit: number = 10): Promise<LogEntry[]> { await this.ensureInitialized(); try { // Get all log files const logFiles = fs.readdirSync(this.logsDir) .filter(file => file.endsWith('.json')) .map(file => path.join(this.logsDir, file)); // Get the most recent entry from each log const logEntries: LogEntry[] = []; for (const logFile of logFiles) { try { const fileContent = fs.readFileSync(logFile, 'utf8'); const entries: LogEntry[] = JSON.parse(fileContent); if (entries.length > 0) { // Sort by timestamp (newest first) and get the most recent entry const sortedEntries = entries.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime() ); logEntries.push(sortedEntries[0]); } } catch (err) { logger.warn(`Error reading log file ${logFile}: ${err instanceof Error ? err.message : String(err)}`); } } // Sort by timestamp (newest first) and limit the number of entries const sortedEntries = logEntries .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()) .slice(0, limit); logger.info(`Retrieved ${sortedEntries.length} logs`); return sortedEntries; } catch (error) { logger.error(`Error getting logs: ${error instanceof Error ? error.message : String(error)}`); throw error; } } /** * Clear a log * * @param logName Log name * @returns True if the log was cleared, false if it didn't exist */ public async clearLog(logName: string): Promise<boolean> { await this.ensureInitialized(); try { // Get the log file path const logFilePath = path.join(this.logsDir, `${logName}.json`); // Check if the log file exists if (!fs.existsSync(logFilePath)) { logger.info(`Log not found: ${logName}`); return false; } // Delete the log file fs.unlinkSync(logFilePath); logger.info(`Cleared log: ${logName}`); return true; } catch (error) { logger.error(`Error clearing log: ${error instanceof Error ? error.message : String(error)}`); throw error; } } /** * Dispose of the logging system */ public async dispose(): Promise<void> { // Nothing to dispose this.initialized = false; } }

Latest Blog Posts

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/TSavo/Unity-MCP'

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