Refactor logging in hooks, services, and routes to use centralized logger

- Replaced console.log and console.error statements with logger.info and logger.error in new-hook.ts, SDKAgent.ts, SessionManager.ts, and SessionRoutes.ts for consistent logging.
- Introduced log file creation and management in logger.ts, ensuring logs are saved to a file with a date-based naming convention.
- Enhanced error handling in logger to prevent crashes if log file operations fail.
This commit is contained in:
Alex Newman
2025-12-27 20:20:43 -05:00
parent b7d0664868
commit 356e3acae3
13 changed files with 226 additions and 185 deletions
+52 -4
View File
@@ -4,6 +4,8 @@
*/
import { SettingsDefaultsManager } from '../shared/SettingsDefaultsManager.js';
import { appendFileSync, existsSync, mkdirSync } from 'fs';
import { join } from 'path';
export enum LogLevel {
DEBUG = 0,
@@ -25,19 +27,55 @@ interface LogContext {
class Logger {
private level: LogLevel | null = null;
private useColor: boolean;
private logFilePath: string | null = null;
constructor() {
// Disable colors when output is not a TTY (e.g., PM2 logs)
this.useColor = process.stdout.isTTY ?? false;
this.initializeLogFile();
}
/**
* Lazy-load log level from settings (breaks circular dependency with SettingsDefaultsManager)
* Initialize log file path and ensure directory exists
*/
private initializeLogFile(): void {
try {
// Get data directory from settings
const dataDir = SettingsDefaultsManager.get('CLAUDE_MEM_DATA_DIR');
const logsDir = join(dataDir, 'logs');
// Ensure logs directory exists
if (!existsSync(logsDir)) {
mkdirSync(logsDir, { recursive: true });
}
// Create log file path with date
const date = new Date().toISOString().split('T')[0];
this.logFilePath = join(logsDir, `claude-mem-${date}.log`);
} catch (error) {
// If log file initialization fails, just log to console
console.error('[LOGGER] Failed to initialize log file:', error);
this.logFilePath = null;
}
}
/**
* Lazy-load log level from settings file (not hardcoded defaults!)
*/
private getLevel(): LogLevel {
if (this.level === null) {
const envLevel = SettingsDefaultsManager.get('CLAUDE_MEM_LOG_LEVEL').toUpperCase();
this.level = LogLevel[envLevel as keyof typeof LogLevel] ?? LogLevel.INFO;
try {
// Load settings from file to get user's actual log level
const dataDir = SettingsDefaultsManager.get('CLAUDE_MEM_DATA_DIR');
const settingsPath = join(dataDir, 'settings.json');
const settings = SettingsDefaultsManager.loadFromFile(settingsPath);
const envLevel = settings.CLAUDE_MEM_LOG_LEVEL.toUpperCase();
this.level = LogLevel[envLevel as keyof typeof LogLevel] ?? LogLevel.INFO;
} catch (error) {
// Fallback to INFO if settings can't be loaded
console.error('[LOGGER] Failed to load settings, using INFO level:', error);
this.level = LogLevel.INFO;
}
}
return this.level;
}
@@ -219,12 +257,22 @@ class Logger {
const logLine = `[${timestamp}] [${levelStr}] [${componentStr}] ${correlationStr}${message}${contextStr}${dataStr}`;
// Output to appropriate stream
// Output to console
if (level === LogLevel.ERROR) {
console.error(logLine);
} else {
console.log(logLine);
}
// Output to log file
if (this.logFilePath) {
try {
appendFileSync(this.logFilePath, logLine + '\n', 'utf8');
} catch (error) {
// If file write fails, just continue (don't crash)
console.error('[LOGGER] Failed to write to log file:', error);
}
}
}
// Public logging methods