Skip to main content
Glama
logger.ts•3.67 kB
/** * Production-ready logging utility */ import { getEnvironmentConfig } from '../config/environment.js'; export enum LogLevel { ERROR = 0, WARN = 1, INFO = 2, DEBUG = 3 } export class Logger { private static instance: Logger; private logLevel: LogLevel; private isDevelopment: boolean; private constructor() { const config = getEnvironmentConfig(); this.isDevelopment = config.nodeEnv === 'development'; this.logLevel = this.parseLogLevel(config.logLevel); } public static getInstance(): Logger { if (!Logger.instance) { Logger.instance = new Logger(); } return Logger.instance; } private parseLogLevel(level: string): LogLevel { switch (level.toLowerCase()) { case 'error': return LogLevel.ERROR; case 'warn': return LogLevel.WARN; case 'info': return LogLevel.INFO; case 'debug': return LogLevel.DEBUG; default: return LogLevel.INFO; } } private formatMessage(level: string, message: string, meta?: any): string { const timestamp = new Date().toISOString(); const baseMessage = `[${timestamp}] [${level}] ${message}`; if (meta && Object.keys(meta).length > 0) { return `${baseMessage} ${JSON.stringify(meta)}`; } return baseMessage; } private log(level: LogLevel, levelName: string, message: string, meta?: any): void { if (level > this.logLevel) return; const formattedMessage = this.formatMessage(levelName, message, meta); // In production, use console.error for all logs to ensure they appear in stderr // In development, use appropriate console methods if (this.isDevelopment) { switch (level) { case LogLevel.ERROR: console.error(formattedMessage); break; case LogLevel.WARN: console.warn(formattedMessage); break; case LogLevel.INFO: console.info(formattedMessage); break; case LogLevel.DEBUG: console.debug(formattedMessage); break; } } else { // In production, always use console.error to ensure logs go to stderr console.error(formattedMessage); } } public error(message: string, meta?: any): void { this.log(LogLevel.ERROR, 'ERROR', message, meta); } public warn(message: string, meta?: any): void { this.log(LogLevel.WARN, 'WARN', message, meta); } public info(message: string, meta?: any): void { this.log(LogLevel.INFO, 'INFO', message, meta); } public debug(message: string, meta?: any): void { this.log(LogLevel.DEBUG, 'DEBUG', message, meta); } // Convenience methods for common logging scenarios public logRequest(method: string, url: string, duration?: number): void { const meta = duration ? { duration: `${duration}ms` } : undefined; this.info(`${method} ${url}`, meta); } public logError(error: Error, context?: string): void { const meta = { error: error.message, stack: error.stack, context: context || 'unknown' }; this.error(`Error occurred: ${error.message}`, meta); } public logCacheHit(key: string): void { this.debug(`Cache hit: ${key}`); } public logCacheMiss(key: string): void { this.debug(`Cache miss: ${key}`); } public logServiceCall(service: string, method: string, params?: any): void { const meta = params ? { params } : undefined; this.debug(`Service call: ${service}.${method}`, meta); } } // Export singleton instance export const logger = Logger.getInstance();

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/mixelpixx/Google-Research-MCP'

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