Skip to main content
Glama
logger.ts7.5 kB
/** * db-mcp - Centralized Logger * * Structured logging with module-prefixed error codes, * severity levels, and contextual payloads. * * Format: [LEVEL] [module] [CODE] message (context) */ // ============================================================================= // Types // ============================================================================= /** * Log severity levels */ export type LogLevel = 'error' | 'warning' | 'info'; /** * Structured log payload */ export interface LogPayload { /** Module name (e.g., 'AUTH', 'SERVER', 'SQLITE') */ module: string; /** Operation being performed */ operation: string; /** Entity identifier (e.g., token ID, database name) */ entityId?: string | undefined; /** Additional context */ context?: Record<string, unknown> | undefined; /** Error object if applicable */ error?: Error | undefined; /** Stack trace (auto-extracted from error if provided) */ stack?: string | undefined; } /** * Module-prefixed error code */ export interface ErrorCode { /** Module prefix (e.g., 'AUTH', 'DB', 'SERVER') */ module: string; /** Error code suffix (e.g., 'TOKEN_INVALID', 'CONNECT_FAILED') */ code: string; /** Full code string (e.g., 'AUTH_TOKEN_INVALID') */ full: string; } // ============================================================================= // Error Codes // ============================================================================= /** * Create a module-prefixed error code */ export function createErrorCode(module: string, code: string): ErrorCode { return { module: module.toUpperCase(), code: code.toUpperCase(), full: `${module.toUpperCase()}_${code.toUpperCase()}` }; } /** * Common error codes by module */ export const ERROR_CODES = { // Auth module AUTH: { TOKEN_INVALID: createErrorCode('AUTH', 'TOKEN_INVALID'), TOKEN_EXPIRED: createErrorCode('AUTH', 'TOKEN_EXPIRED'), TOKEN_MISSING: createErrorCode('AUTH', 'TOKEN_MISSING'), SIGNATURE_INVALID: createErrorCode('AUTH', 'SIGNATURE_INVALID'), SCOPE_DENIED: createErrorCode('AUTH', 'SCOPE_DENIED'), DISCOVERY_FAILED: createErrorCode('AUTH', 'DISCOVERY_FAILED'), JWKS_FETCH_FAILED: createErrorCode('AUTH', 'JWKS_FETCH_FAILED'), REGISTRATION_FAILED: createErrorCode('AUTH', 'REGISTRATION_FAILED') }, // Server module SERVER: { START_FAILED: createErrorCode('SERVER', 'START_FAILED'), SHUTDOWN_FAILED: createErrorCode('SERVER', 'SHUTDOWN_FAILED'), TRANSPORT_ERROR: createErrorCode('SERVER', 'TRANSPORT_ERROR') }, // Database module DB: { CONNECT_FAILED: createErrorCode('DB', 'CONNECT_FAILED'), QUERY_FAILED: createErrorCode('DB', 'QUERY_FAILED'), DISCONNECT_FAILED: createErrorCode('DB', 'DISCONNECT_FAILED'), ADAPTER_NOT_FOUND: createErrorCode('DB', 'ADAPTER_NOT_FOUND') } } as const; // ============================================================================= // Logger Class // ============================================================================= /** * Logger configuration */ export interface LoggerConfig { /** Minimum log level to output */ minLevel?: LogLevel; /** Whether to include timestamps */ timestamps?: boolean; /** Whether to include stack traces for errors */ includeStacks?: boolean; /** Custom output function (defaults to console.error) */ output?: (message: string) => void; } /** * Centralized logger with structured payloads */ export class Logger { private readonly config: Required<LoggerConfig>; private static readonly LEVEL_PRIORITY: Record<LogLevel, number> = { error: 0, warning: 1, info: 2 }; constructor(config: LoggerConfig = {}) { this.config = { minLevel: config.minLevel ?? 'info', timestamps: config.timestamps ?? true, includeStacks: config.includeStacks ?? true, output: config.output ?? console.error.bind(console) }; } /** * Log an error message */ error(module: string, code: string | ErrorCode, message: string, payload?: Partial<LogPayload>): void { this.log('error', module, code, message, payload); } /** * Log a warning message */ warning(module: string, code: string | ErrorCode, message: string, payload?: Partial<LogPayload>): void { this.log('warning', module, code, message, payload); } /** * Log an info message */ info(module: string, code: string | ErrorCode, message: string, payload?: Partial<LogPayload>): void { this.log('info', module, code, message, payload); } /** * Core logging method */ private log( level: LogLevel, module: string, code: string | ErrorCode, message: string, payload?: Partial<LogPayload> ): void { // Check if level should be logged if (Logger.LEVEL_PRIORITY[level] > Logger.LEVEL_PRIORITY[this.config.minLevel]) { return; } // Normalize code const codeStr = typeof code === 'string' ? code : code.full; // Build log parts const parts: string[] = []; // Timestamp if (this.config.timestamps) { parts.push(`[${new Date().toISOString()}]`); } // Level (uppercase) parts.push(`[${level.toUpperCase()}]`); // Module parts.push(`[${module.toUpperCase()}]`); // Code parts.push(`[${codeStr}]`); // Message parts.push(message); // Context if (payload?.context && Object.keys(payload.context).length > 0) { parts.push(`(${JSON.stringify(payload.context)})`); } // Output main message this.config.output(parts.join(' ')); // Stack trace for errors if (this.config.includeStacks && level === 'error') { const stack = payload?.stack ?? payload?.error?.stack; if (stack) { this.config.output(` Stack: ${stack}`); } } } /** * Create a child logger with a fixed module prefix */ child(module: string): ModuleLogger { return new ModuleLogger(this, module); } } /** * Module-scoped logger (child of main logger) */ export class ModuleLogger { constructor( private readonly parent: Logger, private readonly module: string ) { } error(code: string | ErrorCode, message: string, payload?: Partial<LogPayload>): void { this.parent.error(this.module, code, message, payload); } warning(code: string | ErrorCode, message: string, payload?: Partial<LogPayload>): void { this.parent.warning(this.module, code, message, payload); } info(code: string | ErrorCode, message: string, payload?: Partial<LogPayload>): void { this.parent.info(this.module, code, message, payload); } } // ============================================================================= // Default Logger Instance // ============================================================================= /** * Default logger instance */ export const logger = new Logger(); /** * Create a module-specific logger */ export function createModuleLogger(module: string): ModuleLogger { return logger.child(module); }

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/neverinfamous/db-mcp'

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