From f64715aa16a2659f93cb1aeaf2ced45dbdd4b464 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 11 Mar 2025 23:46:37 -0700 Subject: [PATCH] feat(logger): added new logger --- lib/logs/console-logger.ts | 273 +++++++++++++++++++ lib/{logging.ts => logs/execution-logger.ts} | 2 +- 2 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 lib/logs/console-logger.ts rename lib/{logging.ts => logs/execution-logger.ts} (98%) diff --git a/lib/logs/console-logger.ts b/lib/logs/console-logger.ts new file mode 100644 index 0000000000..d6a13bbfbe --- /dev/null +++ b/lib/logs/console-logger.ts @@ -0,0 +1,273 @@ +/** + * console-logger.ts + * + * This module provides standardized console logging utilities for internal application logging. + * It is separate from the user-facing logging system in logging.ts. + */ +import chalk from 'chalk' + +/** + * LogLevel enum defines the severity levels for logging + * + * DEBUG: Detailed information, typically useful only for diagnosing problems + * These logs are only shown in development environment + * + * INFO: Confirmation that things are working as expected + * These logs are shown in both development and production environments + * + * WARN: Indication that something unexpected happened, or may happen in the near future + * The application can still continue working as expected + * + * ERROR: Error events that might still allow the application to continue running + * These should be investigated and fixed + */ +export enum LogLevel { + DEBUG = 'DEBUG', + INFO = 'INFO', + WARN = 'WARN', + ERROR = 'ERROR', +} + +/** + * Configuration for different environments + * + * enabled: Whether logging is enabled at all + * minLevel: The minimum log level that will be displayed + * (e.g., INFO will show INFO, WARN, and ERROR, but not DEBUG) + * colorize: Whether to apply color formatting to logs + */ +const LOG_CONFIG = { + development: { + enabled: true, + minLevel: LogLevel.DEBUG, // Show all logs in development + colorize: true, + }, + production: { + enabled: true, + minLevel: LogLevel.INFO, // Only show INFO and above in production + colorize: false, + }, + test: { + enabled: false, // Disable logs in test environment + minLevel: LogLevel.ERROR, + colorize: false, + }, +} + +// Get current environment +const ENV = process.env.NODE_ENV || 'development' +const config = LOG_CONFIG[ENV] || LOG_CONFIG.development + +// Format objects for logging +const formatObject = (obj: any): string => { + try { + if (obj instanceof Error) { + return JSON.stringify( + { + message: obj.message, + stack: ENV === 'development' ? obj.stack : undefined, + ...(obj as any), + }, + null, + ENV === 'development' ? 2 : 0 + ) + } + return JSON.stringify(obj, null, ENV === 'development' ? 2 : 0) + } catch (error) { + return '[Circular or Non-Serializable Object]' + } +} + +/** + * Logger class for standardized console logging + * + * This class provides methods for logging at different severity levels + * and handles formatting, colorization, and environment-specific behavior. + */ +export class Logger { + private module: string + + /** + * Create a new logger for a specific module + * @param module The name of the module (e.g., 'OpenAIProvider', 'AgentBlockHandler') + */ + constructor(module: string) { + this.module = module + } + + /** + * Determines if a log at the given level should be displayed + * based on the current environment configuration + * + * @param level The log level to check + * @returns boolean indicating whether the log should be displayed + */ + private shouldLog(level: LogLevel): boolean { + if (!config.enabled) return false + + const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR] + const minLevelIndex = levels.indexOf(config.minLevel) + const currentLevelIndex = levels.indexOf(level) + + return currentLevelIndex >= minLevelIndex + } + + /** + * Format arguments for logging, converting objects to JSON strings + * + * @param args Arguments to format + * @returns Formatted arguments + */ + private formatArgs(args: any[]): any[] { + return args.map((arg) => { + if (arg === null || arg === undefined) return arg + if (typeof arg === 'object') return formatObject(arg) + return arg + }) + } + + /** + * Internal method to log a message with the specified level + * + * @param level The severity level of the log + * @param message The main log message + * @param args Additional arguments to log + */ + private log(level: LogLevel, message: string, ...args: any[]) { + if (!this.shouldLog(level)) return + + const timestamp = new Date().toISOString() + const formattedArgs = this.formatArgs(args) + + // Color configuration + if (config.colorize) { + let levelColor + let moduleColor = chalk.cyan + let timestampColor = chalk.gray + + switch (level) { + case LogLevel.DEBUG: + levelColor = chalk.blue + break + case LogLevel.INFO: + levelColor = chalk.green + break + case LogLevel.WARN: + levelColor = chalk.yellow + break + case LogLevel.ERROR: + levelColor = chalk.red + break + } + + const coloredPrefix = `${timestampColor(`[${timestamp}]`)} ${levelColor(`[${level}]`)} ${moduleColor(`[${this.module}]`)}` + + if (level === LogLevel.ERROR) { + console.error(coloredPrefix, message, ...formattedArgs) + } else { + console.log(coloredPrefix, message, ...formattedArgs) + } + } else { + // No colors in production + const prefix = `[${timestamp}] [${level}] [${this.module}]` + + if (level === LogLevel.ERROR) { + console.error(prefix, message, ...formattedArgs) + } else { + console.log(prefix, message, ...formattedArgs) + } + } + } + + /** + * Log a debug message + * + * Use for detailed information useful during development and debugging. + * These logs are only shown in development environment. + * + * Examples: + * - Variable values during execution + * - Function entry/exit points + * - Detailed request/response data + * + * @param message The message to log + * @param args Additional arguments to log + */ + debug(message: string, ...args: any[]) { + this.log(LogLevel.DEBUG, message, ...args) + } + + /** + * Log an info message + * + * Use for general information about application operation. + * These logs are shown in both development and production environments. + * + * Examples: + * - Application startup/shutdown + * - Configuration information + * - Successful operations + * + * @param message The message to log + * @param args Additional arguments to log + */ + info(message: string, ...args: any[]) { + this.log(LogLevel.INFO, message, ...args) + } + + /** + * Log a warning message + * + * Use for potentially problematic situations that don't cause operation failure. + * + * Examples: + * - Deprecated feature usage + * - Suboptimal configurations + * - Recoverable errors + * + * @param message The message to log + * @param args Additional arguments to log + */ + warn(message: string, ...args: any[]) { + this.log(LogLevel.WARN, message, ...args) + } + + /** + * Log an error message + * + * Use for error events that might still allow the application to continue. + * + * Examples: + * - API call failures + * - Operation failures + * - Unexpected exceptions + * + * @param message The message to log + * @param args Additional arguments to log + */ + error(message: string, ...args: any[]) { + this.log(LogLevel.ERROR, message, ...args) + } +} + +/** + * Create a logger for a specific module + * + * Usage example: + * ``` + * import { createLogger } from '@/lib/console-logger' + * + * const logger = createLogger('MyComponent') + * + * logger.debug('Initializing component', { props }) + * logger.info('Component mounted') + * logger.warn('Deprecated prop used', { propName }) + * logger.error('Failed to fetch data', error) + * ``` + * + * @param module The name of the module (e.g., 'OpenAIProvider', 'AgentBlockHandler') + * @returns A Logger instance + */ +export function createLogger(module: string): Logger { + return new Logger(module) +} diff --git a/lib/logging.ts b/lib/logs/execution-logger.ts similarity index 98% rename from lib/logging.ts rename to lib/logs/execution-logger.ts index 2145b2cab0..edc3c0d544 100644 --- a/lib/logging.ts +++ b/lib/logs/execution-logger.ts @@ -1,7 +1,7 @@ import { v4 as uuidv4 } from 'uuid' import { db } from '@/db' import { workflowLogs } from '@/db/schema' -import { BlockLog, ExecutionResult as ExecutorResult } from '@/executor/types' +import { ExecutionResult as ExecutorResult } from '@/executor/types' export interface LogEntry { id: string