import path from 'path'; import { ConstructorOf, Injectable, Optional } from '@opensumi/di'; import { Emitter } from '@opensumi/ide-core-common'; import { AppConfig } from '@opensumi/ide-core-node/lib/types'; import { Archive, BaseLogServiceOptions, ILogService, ILogServiceManager, LogLevel, LoggerManagerInitOptions, SupportLogNamespace, } from '../common/'; import { DEFAULT_LOG_FOLDER, LogService } from './log.service'; import { cleanAllLogs, cleanExpiredLogs, cleanOldLogs, getLogFolder, getLogZipArchiveByFolder } from './utils'; @Injectable() export class LogServiceManager implements ILogServiceManager { protected readonly logLevelChangeEmitter = new Emitter(); private globalLogLevel: LogLevel; private logMap = new Map(); private logRootFolderPath: string; private logFolderPath: string; private LogServiceClass: ConstructorOf; constructor(@Optional(AppConfig) private appConfig: AppConfig) { this.init({ logDir: this.appConfig.logDir, logLevel: this.appConfig.logLevel, }); this.cleanOldLogs(); } private init = (options: LoggerManagerInitOptions) => { this.logRootFolderPath = options.logDir || DEFAULT_LOG_FOLDER; this.logFolderPath = this._getLogFolder(); this.globalLogLevel = options.logLevel || LogLevel.Info; this.LogServiceClass = this.appConfig.LogServiceClass || LogService; }; getLogger = (namespace: SupportLogNamespace, loggerOptions?: BaseLogServiceOptions): ILogService => { if (this.logMap.get(namespace)) { const logger: ILogService = this.logMap.get(namespace)!; if (loggerOptions) { logger.setOptions(loggerOptions); } return logger; } const logger = new this.LogServiceClass( Object.assign( { namespace, logLevel: this.globalLogLevel, logServiceManager: this, }, loggerOptions, ), ); this.logMap.set(namespace, logger); return logger; }; removeLogger = (namespace: SupportLogNamespace) => { this.logMap.delete(namespace); }; getGlobalLogLevel = () => this.globalLogLevel; setGlobalLogLevel = (level: LogLevel) => { this.globalLogLevel = level; this.logLevelChangeEmitter.fire(level); }; get onDidChangeLogLevel() { return this.logLevelChangeEmitter.event; } getLogFolder = (): string => { if (!this.logFolderPath) { throw new Error('Please do init first!'); } return this.logFolderPath; }; getRootLogFolder = (): string => this.logRootFolderPath; cleanOldLogs = async () => await cleanOldLogs(this.getRootLogFolder()); cleanAllLogs = async () => await cleanAllLogs(this.getRootLogFolder()); cleanExpiredLogs = async (day: number) => await cleanExpiredLogs(day, this.getRootLogFolder()); getLogZipArchiveByDay(day: number): Promise { return this.getLogZipArchiveByFolder(path.join(this.getRootLogFolder(), String(day))); } async getLogZipArchiveByFolder(foldPath: string): Promise { const promiseList: any[] = []; this.logMap.forEach((logger) => { promiseList.push(logger.flush()); }); return getLogZipArchiveByFolder(foldPath, Promise.all(promiseList)); } dispose = () => { this.logLevelChangeEmitter.dispose(); this.logMap.forEach((logger) => { logger.dispose(); }); }; /** * 日志目录路径为 `${logRootPath}/${folderName}` * folderName 为当前当天日期比如: `20190807` * @private * @memberof LogServiceManager */ private _getLogFolder = (): string => { const logRootPath = this.getRootLogFolder(); if (!logRootPath) { throw new Error('Please do initLogManager first!!!'); } return getLogFolder(logRootPath); }; }