LogManager.js 6.86 KB
/**
 * LogManager - 统一日志管理器
 *
 * 提供全局日志管理功能:
 * - 多会话管理
 * - 多后端支持
 * - 全局配置
 * - 日志查询
 */

const path = require('path');
const { EventEmitter } = require('events');
const { LogSession } = require('./LogSession');
const { CompositeBackend } = require('./backends/CompositeBackend');
const { FileBackend } = require('./backends/FileBackend');
const { ConsoleBackend } = require('./backends/ConsoleBackend');

// 获取项目根目录 (从 server/src/core/logging/LogManager.js 向上回溯)
const PROJECT_ROOT = path.resolve(__dirname, '../../../../');

class LogManager extends EventEmitter {
  constructor(options = {}) {
    super();
    this.options = {
      // 默认使用项目根目录的 .logs/
      baseDir: options.baseDir || path.join(PROJECT_ROOT, '.logs'),
      enableConsole: options.enableConsole !== false,
      enableFile: options.enableFile !== false,
      ...options,
    };

    this.sessions = new Map(); // sessionId -> LogSession
    this.backend = new CompositeBackend();
    this.initialized = false;
    this.globalMetadata = {};
  }

  /**
   * 初始化日志管理器
   */
  async init() {
    if (this.initialized) return;

    // 添加文件后端
    if (this.options.enableFile) {
      const fileBackend = new FileBackend({
        baseDir: this.options.baseDir,
        maxFileSize: this.options.maxFileSize,
        maxFiles: this.options.maxFiles,
      });
      this.backend.add(fileBackend);
    }

    // 添加控制台后端
    if (this.options.enableConsole) {
      const consoleBackend = new ConsoleBackend({
        colorize: this.options.colorize !== false,
        pretty: this.options.pretty !== false,
        level: this.options.consoleLevel || 'info',
      });
      this.backend.add(consoleBackend);
    }

    await this.backend.init();
    this.initialized = true;

    this.emit('initialized');
  }

  /**
   * 创建新会话
   * @param {string} sessionId - 会话ID
   * @param {Object} options - 会话选项
   * @returns {LogSession}
   */
  createSession(sessionId, options = {}) {
    if (!this.initialized) {
      throw new Error('LogManager not initialized. Call init() first.');
    }

    if (this.sessions.has(sessionId)) {
      console.warn(`[LogManager] Session ${sessionId} already exists, returning existing session`);
      return this.sessions.get(sessionId);
    }

    const session = new LogSession(sessionId, this.backend, {
      metadata: {
        ...this.globalMetadata,
        ...options.metadata,
      },
      ...options,
    });

    // 转发事件
    session.on('log', (entry) => {
      this.emit('log', entry);
    });

    this.sessions.set(sessionId, session);
    this.emit('session_created', { sessionId, session });

    // 记录会话开始
    session.logEvent(null, 'session_start', {
      workDir: options.workDir,
      requirement: options.requirement,
      config: options.config,
    });

    return session;
  }

  /**
   * 获取会话
   * @param {string} sessionId - 会话ID
   * @returns {LogSession|null}
   */
  getSession(sessionId) {
    return this.sessions.get(sessionId) || null;
  }

  /**
   * 获取或创建会话
   * @param {string} sessionId - 会话ID
   * @param {Object} options - 创建选项(如果会话不存在)
   * @returns {LogSession}
   */
  getOrCreateSession(sessionId, options = {}) {
    return this.getSession(sessionId) || this.createSession(sessionId, options);
  }

  /**
   * 关闭会话
   * @param {string} sessionId - 会话ID
   */
  async closeSession(sessionId) {
    const session = this.sessions.get(sessionId);
    if (!session) return;

    // 记录会话结束
    await session.logEvent(null, 'session_end', {});

    await session.close();
    this.sessions.delete(sessionId);
    this.emit('session_closed', { sessionId });
  }

  /**
   * 关闭所有会话
   */
  async closeAllSessions() {
    const promises = [];
    for (const sessionId of this.sessions.keys()) {
      promises.push(this.closeSession(sessionId));
    }
    await Promise.all(promises);
  }

  /**
   * 注册自定义后端
   * @param {string} name - 后端名称
   * @param {BaseBackend} backend - 后端实例
   */
  registerBackend(name, backend) {
    backend.name = name;
    this.backend.add(backend);
  }

  /**
   * 设置全局元数据
   * @param {Object} metadata - 元数据对象
   */
  setGlobalMetadata(metadata) {
    this.globalMetadata = { ...this.globalMetadata, ...metadata };
  }

  /**
   * 查询日志
   * @param {Object} filters - 查询条件
   */
  async query(filters = {}) {
    if (!this.initialized) {
      throw new Error('LogManager not initialized');
    }

    return this.backend.query(filters);
  }

  /**
   * 获取所有会话列表
   */
  getSessions() {
    return Array.from(this.sessions.keys());
  }

  /**
   * 生成会话报告
   * @param {string} sessionId - 会话ID
   */
  async generateReport(sessionId) {
    const session = this.sessions.get(sessionId);
    if (session) {
      return session.generateReport();
    }

    // 如果会话已关闭,从后端查询
    const entries = await this.backend.query({ sessionId, limit: 10000 });
    return {
      sessionId,
      entryCount: entries.length,
      archived: true,
      entries: entries.slice(0, 100), // 返回最近100条
    };
  }

  /**
   * 关闭日志管理器
   */
  async close() {
    await this.closeAllSessions();
    await this.backend.close();
    this.initialized = false;
    this.emit('closed');
  }

  // ============ 快捷方法 ============

  /**
   * 记录系统级事件(不关联特定会话)
   */
  async logSystemEvent(eventType, payload, level = 'info') {
    if (!this.initialized) return;

    const entry = {
      timestamp: new Date().toISOString(),
      sequence: 0,
      level,
      category: 'system',
      eventType,
      payload,
      metadata: this.globalMetadata,
    };

    await this.backend.write(entry);
    this.emit('log', entry);
  }
}

// 全局实例
let globalInstance = null;
let initPromise = null;

/**
 * 获取全局 LogManager 实例(自动初始化)
 */
function getGlobalLogManager(options = {}) {
  if (!globalInstance) {
    globalInstance = new LogManager({
      enableConsole: false,  // 全局实例默认不输出控制台
      enableFile: true,
      ...options,
    });
    // 异步初始化,不阻塞返回
    initPromise = globalInstance.init().catch(err => {
      console.error('[LogManager] Auto-init failed:', err);
    });
  }
  return globalInstance;
}

/**
 * 等待全局 LogManager 初始化完成
 */
async function waitForGlobalLogManager() {
  getGlobalLogManager();
  if (initPromise) await initPromise;
  return globalInstance;
}

/**
 * 设置全局 LogManager 实例
 */
function setGlobalLogManager(instance) {
  globalInstance = instance;
}

module.exports = {
  LogManager,
  getGlobalLogManager,
  setGlobalLogManager,
  waitForGlobalLogManager,
};