cnb-mcp-server
Version:
MCP Server for the cnb API, enabling file operations, repository management, search functionality, and more.
167 lines (166 loc) • 5.1 kB
JavaScript
/**
* 日志模块,支持将日志写入本地文件
*/
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
// 日志级别
export var LogLevel;
(function (LogLevel) {
LogLevel["DEBUG"] = "DEBUG";
LogLevel["INFO"] = "INFO";
LogLevel["WARN"] = "WARN";
LogLevel["ERROR"] = "ERROR";
})(LogLevel || (LogLevel = {}));
class Logger {
_level;
_filePath;
console;
logStream = null;
initialized = false;
pendingLogs = [];
constructor(config) {
this._level = config.level;
this.console = config.console !== false;
this._filePath = config.filePath || path.join(process.cwd(), 'log.txt');
// 不在构造函数中初始化文件,而是在initialize()中执行
}
initLogFile() {
try {
// 关闭现有的流
if (this.logStream) {
this.logStream.end();
this.logStream = null;
}
// 确保目录存在
const dir = path.dirname(this._filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
// 创建写入流
this.logStream = fs.createWriteStream(this._filePath, { flags: 'a' });
// 添加错误处理
this.logStream.on('error', (err) => {
console.error(`Log stream error: ${err.message}`);
this.logStream = null;
});
// 处理待写入的日志
if (this.pendingLogs.length > 0) {
this.pendingLogs.forEach(log => {
if (this.logStream) {
this.logStream.write(log);
}
});
this.pendingLogs = [];
}
this.initialized = true;
return true;
}
catch (error) {
console.error(`Failed to initialize log file: ${error instanceof Error ? error.message : String(error)}`);
return false;
}
}
formatDate() {
const date = new Date();
return date.toISOString();
}
shouldLog(level) {
const levels = Object.values(LogLevel);
return levels.indexOf(level) >= levels.indexOf(this._level);
}
writeLog(level, message, meta) {
if (!this.shouldLog(level))
return;
const timestamp = this.formatDate();
let logMessage = `[${timestamp}] [${level}] ${message}`;
if (meta) {
const metaStr = typeof meta === 'object'
? JSON.stringify(meta)
: String(meta);
logMessage += ` - ${metaStr}`;
}
// 添加换行符
logMessage += os.EOL;
// 输出到控制台
if (this.console) {
if (level === LogLevel.ERROR) {
console.error(logMessage);
}
else if (level === LogLevel.WARN) {
console.warn(logMessage);
}
else {
console.log(logMessage);
}
}
// 写入文件
if (this.logStream) {
this.logStream.write(logMessage);
}
else if (!this.initialized) {
// 如果日志流未初始化,先缓存日志
this.pendingLogs.push(logMessage);
// 尝试初始化日志文件
this.initialize();
}
else {
// 日志流初始化失败但已尝试过,只输出到控制台
console.log(`[Warning] 无法写入日志文件: ${this._filePath}`);
}
}
debug(message, meta) {
this.writeLog(LogLevel.DEBUG, message, meta);
}
info(message, meta) {
this.writeLog(LogLevel.INFO, message, meta);
}
warn(message, meta) {
this.writeLog(LogLevel.WARN, message, meta);
}
error(message, meta) {
this.writeLog(LogLevel.ERROR, message, meta);
}
close() {
if (this.logStream) {
this.logStream.end();
this.logStream = null;
}
this.initialized = false;
}
/**
* 重新初始化日志文件,确保在程序启动时正确创建
*/
initialize() {
this.close();
const success = this.initLogFile();
if (success) {
this.info(`Logger initialized with file: ${this._filePath}`);
}
else {
console.error(`Failed to initialize logger with file: ${this._filePath}`);
}
return success;
}
// Getter和Setter
get level() {
return this._level;
}
set level(value) {
this._level = value;
}
get filePath() {
return this._filePath;
}
set filePath(value) {
this._filePath = value;
this.initLogFile(); // 重新初始化日志文件
}
}
// 默认日志实例
const defaultLogger = new Logger({
level: LogLevel.DEBUG, // 改为DEBUG级别方便调试
console: true,
filePath: path.join(process.cwd(), 'log.txt')
});
export { Logger, defaultLogger };