mirror of
https://github.com/foxhui/WebAI2API.git
synced 2026-06-16 21:03:59 +08:00
feat: 完善 WebUI 功能
This commit is contained in:
+113
-1
@@ -4,9 +4,12 @@
|
||||
*
|
||||
* - 环境变量:LOG_LEVEL=debug|info|warn|error
|
||||
* - 输出格式:YYYY-MM-DD HH:mm:ss.SSS [LEVEL] [模块] 消息 | k=v ...
|
||||
* - 日志文件:data/temp/system.log(超过 5MB 自动轮转)
|
||||
*/
|
||||
|
||||
import process from 'process';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const LEVELS = ['debug', 'info', 'warn', 'error'];
|
||||
|
||||
@@ -19,6 +22,49 @@ const COLORS = {
|
||||
white: '\x1b[37m'
|
||||
};
|
||||
|
||||
// 日志文件配置
|
||||
const LOG_DIR = path.join(process.cwd(), 'data', 'temp');
|
||||
const LOG_FILE = path.join(LOG_DIR, 'system.log');
|
||||
const LOG_FILE_OLD = path.join(LOG_DIR, 'system.log.old');
|
||||
const MAX_LOG_SIZE = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
// 确保日志目录存在
|
||||
function ensureLogDir() {
|
||||
if (!fs.existsSync(LOG_DIR)) {
|
||||
fs.mkdirSync(LOG_DIR, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
// 日志轮转:超过 5MB 时重命名为 .old
|
||||
function rotateLogIfNeeded() {
|
||||
try {
|
||||
if (fs.existsSync(LOG_FILE)) {
|
||||
const stats = fs.statSync(LOG_FILE);
|
||||
if (stats.size >= MAX_LOG_SIZE) {
|
||||
// 删除旧的 .old 文件
|
||||
if (fs.existsSync(LOG_FILE_OLD)) {
|
||||
fs.unlinkSync(LOG_FILE_OLD);
|
||||
}
|
||||
// 重命名当前日志
|
||||
fs.renameSync(LOG_FILE, LOG_FILE_OLD);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// 忽略轮转错误
|
||||
}
|
||||
}
|
||||
|
||||
// 写入日志文件
|
||||
function writeToFile(line) {
|
||||
try {
|
||||
ensureLogDir();
|
||||
rotateLogIfNeeded();
|
||||
fs.appendFileSync(LOG_FILE, line + '\n', 'utf8');
|
||||
} catch (e) {
|
||||
// 忽略写入错误
|
||||
}
|
||||
}
|
||||
|
||||
// 根据日志级别获取颜色
|
||||
function getColor(level) {
|
||||
switch (level.toLowerCase()) {
|
||||
@@ -94,6 +140,7 @@ export function log(level, mod, msg, meta = {}) {
|
||||
const color = getColor(level);
|
||||
const coloredLine = `${color}${line}${COLORS.reset}`;
|
||||
|
||||
// 输出到控制台
|
||||
if (level === 'error') {
|
||||
console.error(coloredLine);
|
||||
} else if (level === 'warn') {
|
||||
@@ -101,6 +148,66 @@ export function log(level, mod, msg, meta = {}) {
|
||||
} else {
|
||||
console.log(coloredLine);
|
||||
}
|
||||
|
||||
// 写入日志文件(不带颜色)
|
||||
writeToFile(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日志文件路径
|
||||
*/
|
||||
export function getLogPath() {
|
||||
return LOG_FILE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取旧日志文件路径
|
||||
*/
|
||||
export function getOldLogPath() {
|
||||
return LOG_FILE_OLD;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除日志文件
|
||||
*/
|
||||
export function clearLogs() {
|
||||
try {
|
||||
if (fs.existsSync(LOG_FILE)) {
|
||||
fs.unlinkSync(LOG_FILE);
|
||||
}
|
||||
if (fs.existsSync(LOG_FILE_OLD)) {
|
||||
fs.unlinkSync(LOG_FILE_OLD);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取日志文件(返回最后 N 行)
|
||||
* @param {number} lines - 读取行数
|
||||
* @returns {{logs: string[], total: number, file: string}}
|
||||
*/
|
||||
export function readLogs(lines = 200) {
|
||||
const result = { logs: [], total: 0, file: LOG_FILE };
|
||||
|
||||
try {
|
||||
if (!fs.existsSync(LOG_FILE)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(LOG_FILE, 'utf8');
|
||||
const allLines = content.split('\n').filter(line => line.trim());
|
||||
result.total = allLines.length;
|
||||
|
||||
// 返回最后 N 行
|
||||
result.logs = allLines.slice(-lines);
|
||||
} catch (e) {
|
||||
// 忽略读取错误
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export const logger = {
|
||||
@@ -108,5 +215,10 @@ export const logger = {
|
||||
info: (mod, msg, meta) => log('info', mod, msg, meta),
|
||||
warn: (mod, msg, meta) => log('warn', mod, msg, meta),
|
||||
error: (mod, msg, meta) => log('error', mod, msg, meta),
|
||||
setLevel: setLogLevel
|
||||
setLevel: setLogLevel,
|
||||
getLogPath,
|
||||
getOldLogPath,
|
||||
clearLogs,
|
||||
readLogs
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user