Skip to main content
Glama
container-logger.ts6.63 kB
/** * Container Logger * * Provides structured logging for container operations during test setup and teardown. * Logs to stderr to avoid interfering with MCP protocol on stdout. * * @module containers/container-logger */ import type { IContainerLogger } from "./types"; /** * Log levels for container operations. */ type LogLevel = "info" | "warn" | "error" | "debug"; /** * Remediation suggestions for common container errors. */ const REMEDIATION_SUGGESTIONS: Record<string, string> = { "port already in use": "Try stopping the conflicting service or use a different port via TEST_DB_PORT/TEST_OLLAMA_PORT environment variables", "connection refused": "Ensure Docker daemon is running. Try: docker info", "permission denied": "Add your user to the docker group: sudo usermod -aG docker $USER, then log out and back in", "image not found": "Check your internet connection and try: docker pull <image-name>", "no such file": "Ensure docker-compose.test.yml exists in the project root", timeout: "Increase CONTAINER_STARTUP_TIMEOUT or check container logs for startup issues", "health check": "Container may be slow to start. Check logs with: docker compose -f docker-compose.test.yml logs", "out of memory": "Increase Docker memory allocation in Docker Desktop settings", "disk space": "Free up disk space or run: docker system prune", }; /** * Formats a timestamp for log output. */ function formatTimestamp(): string { return new Date().toISOString(); } /** * Formats a log message with timestamp and level. */ function formatLogMessage(level: LogLevel, prefix: string, message: string): string { const timestamp = formatTimestamp(); const levelUpper = level.toUpperCase().padEnd(5); return `[${timestamp}] [${levelUpper}] [${prefix}] ${message}`; } /** * Finds a remediation suggestion based on error message content. */ function findRemediation(error: string): string | undefined { const errorLower = error.toLowerCase(); for (const [pattern, suggestion] of Object.entries(REMEDIATION_SUGGESTIONS)) { if (errorLower.includes(pattern)) { return suggestion; } } return undefined; } /** * ContainerLogger provides structured logging for container operations. * * Features: * - Timestamped log messages * - Log level indicators (INFO, WARN, ERROR, DEBUG) * - Service name prefixes for easy filtering * - Automatic remediation suggestions for common errors * - Writes to stderr to avoid MCP protocol interference * * @implements {IContainerLogger} */ export class ContainerLogger implements IContainerLogger { private readonly prefix: string; private readonly verbose: boolean; /** * Creates a new ContainerLogger instance. * * @param prefix - Prefix for all log messages (default: "containers") * @param verbose - Whether to include debug-level logs (default: based on NODE_ENV) */ constructor(prefix = "containers", verbose?: boolean) { this.prefix = prefix; this.verbose = verbose ?? process.env.NODE_ENV !== "production"; } /** * Logs that a service is starting. * * Requirement 5.1: WHEN containers are starting THEN the Test Container Manager * SHALL log the container name and target port * * @param serviceName - Name of the service being started * @param composeFile - Path to the Docker Compose file being used */ logStarting(serviceName: string, composeFile: string): void { const message = `Starting service '${serviceName}' using ${composeFile}`; this.log("info", message); } /** * Logs health check status. * * Requirement 5.2: WHEN health checks are in progress THEN the Test Container Manager * SHALL log the health check status every 5 seconds * * @param serviceName - Name of the service being checked * @param status - Current health check status */ logHealthCheck(serviceName: string, status: string): void { const message = `Health check for '${serviceName}': ${status}`; this.log("debug", message); } /** * Logs that a service is ready with connection details. * * Requirement 5.3: WHEN containers are ready THEN the Test Container Manager * SHALL log the final connection details (host, port, database name) * * @param serviceName - Name of the service that is ready * @param connectionDetails - Connection details string (e.g., "localhost:5433/testdb") */ logReady(serviceName: string, connectionDetails: string): void { const message = `Service '${serviceName}' is ready at ${connectionDetails}`; this.log("info", message); } /** * Logs an error with optional remediation suggestion. * * Requirement 5.4: WHEN container startup fails THEN the Test Container Manager * SHALL log the Docker error output and suggest remediation steps * * @param serviceName - Name of the service that encountered an error * @param error - Error message or description * @param suggestion - Optional remediation suggestion (auto-detected if not provided) */ logError(serviceName: string, error: string, suggestion?: string): void { const message = `Error with service '${serviceName}': ${error}`; this.log("error", message); // Use provided suggestion or try to find one based on error content const remediation = suggestion ?? findRemediation(error); if (remediation) { this.log("info", `Suggestion: ${remediation}`); } } /** * Logs that a service has stopped. * * Requirement 5.5: WHEN containers are stopped THEN the Test Container Manager * SHALL log the cleanup status * * @param serviceName - Name of the service that was stopped */ logStopped(serviceName: string): void { const message = `Service '${serviceName}' has been stopped`; this.log("info", message); } /** * Internal logging method that writes to stderr. * * @param level - Log level * @param message - Message to log */ private log(level: LogLevel, message: string): void { // Skip debug logs in production unless verbose is explicitly enabled if (level === "debug" && !this.verbose) { return; } const formattedMessage = formatLogMessage(level, this.prefix, message); process.stderr.write(`${formattedMessage}\n`); } } /** * Creates a new ContainerLogger instance. * * @param prefix - Optional prefix for log messages * @param verbose - Optional verbose flag * @returns A new ContainerLogger instance */ export function createContainerLogger(prefix?: string, verbose?: boolean): IContainerLogger { return new ContainerLogger(prefix, verbose); }

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/keyurgolani/ThoughtMcp'

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