283 lines
7.9 KiB
TypeScript
283 lines
7.9 KiB
TypeScript
// debug_logger.ts - 调试日志模块
|
|
export enum LogLevel {
|
|
ERROR = 0,
|
|
WARN = 1,
|
|
INFO = 2,
|
|
DEBUG = 3,
|
|
TRACE = 4
|
|
}
|
|
|
|
export interface LogConfig {
|
|
level: LogLevel;
|
|
enableTimestamp: boolean;
|
|
enableColors: boolean;
|
|
enableFileOutput: boolean;
|
|
logFilePath?: string;
|
|
modules: {
|
|
[moduleName: string]: LogLevel;
|
|
};
|
|
}
|
|
|
|
const DEFAULT_CONFIG: LogConfig = {
|
|
level: LogLevel.INFO,
|
|
enableTimestamp: true,
|
|
enableColors: true,
|
|
enableFileOutput: false,
|
|
modules: {}
|
|
};
|
|
|
|
class DebugLogger {
|
|
private config: LogConfig;
|
|
private logFile?: Deno.FsFile;
|
|
|
|
constructor(config: Partial<LogConfig> = {}) {
|
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
|
|
if (this.config.enableFileOutput && this.config.logFilePath) {
|
|
this.initLogFile();
|
|
}
|
|
}
|
|
|
|
private async initLogFile() {
|
|
try {
|
|
this.logFile = await Deno.open(this.config.logFilePath!, {
|
|
create: true,
|
|
write: true,
|
|
append: true
|
|
});
|
|
} catch (error) {
|
|
console.error(`Failed to open log file: ${error}`);
|
|
}
|
|
}
|
|
|
|
private getTimestamp(): string {
|
|
if (!this.config.enableTimestamp) return "";
|
|
return `[${new Date().toISOString()}] `;
|
|
}
|
|
|
|
private getColorCode(level: LogLevel): string {
|
|
if (!this.config.enableColors) return "";
|
|
|
|
switch (level) {
|
|
case LogLevel.ERROR: return "\x1b[31m"; // Red
|
|
case LogLevel.WARN: return "\x1b[33m"; // Yellow
|
|
case LogLevel.INFO: return "\x1b[36m"; // Cyan
|
|
case LogLevel.DEBUG: return "\x1b[32m"; // Green
|
|
case LogLevel.TRACE: return "\x1b[35m"; // Magenta
|
|
default: return "";
|
|
}
|
|
}
|
|
|
|
private getResetCode(): string {
|
|
return this.config.enableColors ? "\x1b[0m" : "";
|
|
}
|
|
|
|
private getLevelName(level: LogLevel): string {
|
|
switch (level) {
|
|
case LogLevel.ERROR: return "ERROR";
|
|
case LogLevel.WARN: return "WARN ";
|
|
case LogLevel.INFO: return "INFO ";
|
|
case LogLevel.DEBUG: return "DEBUG";
|
|
case LogLevel.TRACE: return "TRACE";
|
|
default: return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
private shouldLog(level: LogLevel, module?: string): boolean {
|
|
// 检查模块特定的日志级别
|
|
if (module && this.config.modules[module] !== undefined) {
|
|
return level <= this.config.modules[module];
|
|
}
|
|
|
|
// 使用全局日志级别
|
|
return level <= this.config.level;
|
|
}
|
|
|
|
private formatMessage(level: LogLevel, module: string, message: string, ...args: any[]): string {
|
|
const timestamp = this.getTimestamp();
|
|
const colorCode = this.getColorCode(level);
|
|
const resetCode = this.getResetCode();
|
|
const levelName = this.getLevelName(level);
|
|
|
|
const formattedArgs = args.length > 0 ? " " + args.map(arg =>
|
|
typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
|
|
).join(" ") : "";
|
|
|
|
return `${timestamp}${colorCode}[${levelName}]${resetCode} [${module}] ${message}${formattedArgs}`;
|
|
}
|
|
|
|
private async writeLog(formattedMessage: string) {
|
|
// 输出到控制台
|
|
console.log(formattedMessage);
|
|
|
|
// 输出到文件
|
|
if (this.logFile) {
|
|
try {
|
|
const encoder = new TextEncoder();
|
|
await this.logFile.write(encoder.encode(formattedMessage + "\n"));
|
|
await this.logFile.sync();
|
|
} catch (error) {
|
|
console.error(`Failed to write to log file: ${error}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
log(level: LogLevel, module: string, message: string, ...args: any[]) {
|
|
if (!this.shouldLog(level, module)) return;
|
|
|
|
const formattedMessage = this.formatMessage(level, module, message, ...args);
|
|
this.writeLog(formattedMessage);
|
|
}
|
|
|
|
error(module: string, message: string, ...args: any[]) {
|
|
this.log(LogLevel.ERROR, module, message, ...args);
|
|
}
|
|
|
|
warn(module: string, message: string, ...args: any[]) {
|
|
this.log(LogLevel.WARN, module, message, ...args);
|
|
}
|
|
|
|
info(module: string, message: string, ...args: any[]) {
|
|
this.log(LogLevel.INFO, module, message, ...args);
|
|
}
|
|
|
|
debug(module: string, message: string, ...args: any[]) {
|
|
this.log(LogLevel.DEBUG, module, message, ...args);
|
|
}
|
|
|
|
trace(module: string, message: string, ...args: any[]) {
|
|
this.log(LogLevel.TRACE, module, message, ...args);
|
|
}
|
|
|
|
// 设置模块特定的日志级别
|
|
setModuleLevel(module: string, level: LogLevel) {
|
|
this.config.modules[module] = level;
|
|
}
|
|
|
|
// 设置全局日志级别
|
|
setGlobalLevel(level: LogLevel) {
|
|
this.config.level = level;
|
|
}
|
|
|
|
// 获取当前配置
|
|
getConfig(): LogConfig {
|
|
return { ...this.config };
|
|
}
|
|
|
|
// 关闭日志文件
|
|
async close() {
|
|
if (this.logFile) {
|
|
await this.logFile.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
// 创建全局调试器实例
|
|
export const debugLogger = new DebugLogger({
|
|
level: LogLevel.DEBUG,
|
|
enableTimestamp: true,
|
|
enableColors: true,
|
|
enableFileOutput: false,
|
|
logFilePath: "./debug.log",
|
|
modules: {
|
|
"DEVICE_SIMULATOR": LogLevel.ERROR,
|
|
"MODBUS": LogLevel.ERROR,
|
|
"MQTT": LogLevel.ERROR,
|
|
"REGISTER_CONFIG": LogLevel.ERROR,
|
|
"DEVICE_MANAGER": LogLevel.ERROR,
|
|
"SIMULATOR_MAIN": LogLevel.ERROR
|
|
}
|
|
});
|
|
|
|
// 便捷的模块日志器创建函数
|
|
export function createModuleLogger(moduleName: string) {
|
|
return {
|
|
error: (message: string, ...args: any[]) => debugLogger.error(moduleName, message, ...args),
|
|
warn: (message: string, ...args: any[]) => debugLogger.warn(moduleName, message, ...args),
|
|
info: (message: string, ...args: any[]) => debugLogger.info(moduleName, message, ...args),
|
|
debug: (message: string, ...args: any[]) => debugLogger.debug(moduleName, message, ...args),
|
|
trace: (message: string, ...args: any[]) => debugLogger.trace(moduleName, message, ...args)
|
|
};
|
|
}
|
|
|
|
// 性能监控工具
|
|
export class PerformanceMonitor {
|
|
private timers: Map<string, number> = new Map();
|
|
private logger = createModuleLogger("PERFORMANCE");
|
|
|
|
start(label: string) {
|
|
this.timers.set(label, performance.now());
|
|
this.logger.trace(`⏱️ Started timer: ${label}`);
|
|
}
|
|
|
|
end(label: string): number {
|
|
const startTime = this.timers.get(label);
|
|
if (!startTime) {
|
|
this.logger.trace(`⚠️ Timer not found: ${label}`);
|
|
return 0;
|
|
}
|
|
|
|
const duration = performance.now() - startTime;
|
|
this.timers.delete(label);
|
|
this.logger.trace(`⏱️ ${label}: ${duration.toFixed(2)}ms`);
|
|
return duration;
|
|
}
|
|
|
|
measure<T>(label: string, fn: () => T): T {
|
|
this.start(label);
|
|
try {
|
|
const result = fn();
|
|
this.end(label);
|
|
return result;
|
|
} catch (error) {
|
|
this.end(label);
|
|
this.logger.error(`❌ Error in ${label}:`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async measureAsync<T>(label: string, fn: () => Promise<T>): Promise<T> {
|
|
this.start(label);
|
|
try {
|
|
const result = await fn();
|
|
this.end(label);
|
|
return result;
|
|
} catch (error) {
|
|
this.end(label);
|
|
this.logger.error(`❌ Error in ${label}:`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
export const perfMonitor = new PerformanceMonitor();
|
|
|
|
// 内存使用监控
|
|
export function logMemoryUsage(module: string) {
|
|
if (typeof Deno !== 'undefined' && Deno.memoryUsage) {
|
|
const memory = Deno.memoryUsage();
|
|
const logger = createModuleLogger(module);
|
|
logger.debug(`💾 Memory usage:`, {
|
|
rss: `${(memory.rss / 1024 / 1024).toFixed(2)}MB`,
|
|
heapTotal: `${(memory.heapTotal / 1024 / 1024).toFixed(2)}MB`,
|
|
heapUsed: `${(memory.heapUsed / 1024 / 1024).toFixed(2)}MB`,
|
|
external: `${(memory.external / 1024 / 1024).toFixed(2)}MB`
|
|
});
|
|
}
|
|
}
|
|
|
|
// 调试配置管理
|
|
export function setDebugLevel(level: LogLevel | string, module?: string) {
|
|
const logLevel = typeof level === 'string' ?
|
|
LogLevel[level.toUpperCase() as keyof typeof LogLevel] : level;
|
|
|
|
if (module) {
|
|
debugLogger.setModuleLevel(module, logLevel);
|
|
console.log(`🔧 Set debug level for ${module}: ${LogLevel[logLevel]}`);
|
|
} else {
|
|
debugLogger.setGlobalLevel(logLevel);
|
|
console.log(`🔧 Set global debug level: ${LogLevel[logLevel]}`);
|
|
}
|
|
}
|
|
|
|
// 调试工具已在上面导出
|