Files
ST-Amily2-Chat-Optimisation/SL/bus/log/Logger.js
2026-01-16 00:25:41 +08:00

205 lines
7.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 日志总类,用于记录日志信息
* 支持基于位运算的自定义日志级别控制
*/
class Logger {
static LOG_HEADER_DEBUG = '[DEBUG]';
static LOG_HEADER_INFO = '[INFO]';
static LOG_HEADER_WARN = '[WARN]';
static LOG_HEADER_ERROR = '[ERROR]';
static LOG_LEVEL_CODE = {
none: 0,
debug: 1 << 0, // 1
info: 1 << 1, // 2
warn: 1 << 2, // 4
error: 1 << 3, // 8
all: (1 << 4) - 1 // 15
};
constructor() {
// 全局默认级别 (默认开启 info, warn, error)
this.globalLevel = Logger.LOG_LEVEL_CODE.info | Logger.LOG_LEVEL_CODE.warn | Logger.LOG_LEVEL_CODE.error;
// 针对特定插件或模块的配置
// 结构示例:
// {
// "PluginA": 3, // PluginA 下所有模块掩码为 3 (debug | info)
// "PluginB::ModuleX": 8 // 仅 PluginB 下的 ModuleX 掩码为 8 (error)
// }
this.levelConfig = {};
}
/**
* 将输入转换为对应的日志级别掩码
* @param {number|string|string[]} levelInput
* @returns {number} 掩码
*/
_parseLevelInput(levelInput) {
if (typeof levelInput === 'number') {
return levelInput;
}
if (typeof levelInput === 'string') {
if (Logger.LOG_LEVEL_CODE.hasOwnProperty(levelInput)) {
return Logger.LOG_LEVEL_CODE[levelInput];
}
// 支持 "debug|info" 这种写法
if (levelInput.includes('|')) {
return levelInput.split('|').reduce((mask, l) => mask | (Logger.LOG_LEVEL_CODE[l.trim()] || 0), 0);
}
console.warn(`[Logger] Unknown log level string: ${levelInput}`);
return 0;
}
if (Array.isArray(levelInput)) {
return levelInput.reduce((mask, l) => mask | (Logger.LOG_LEVEL_CODE[l] || 0), 0);
}
return 0;
}
/**
* 设置日志级别(覆盖模式)
* @param {string} target 目标范围,可以是 'Global'、'PluginName' 或 'PluginName::ModuleName'
* @param {number|string|string[]} level 输入的级别配置
*/
setLevel(target, level) {
const mask = this._parseLevelInput(level);
if (target === 'Global') {
this.globalLevel = mask;
console.log(`[Logger] Global log level mask set to: ${mask.toString(2)}`);
} else {
this.levelConfig[target] = mask;
console.log(`[Logger] Log level mask for '${target}' set to: ${mask.toString(2)}`);
}
}
/**
* 添加日志级别(增量模式)
* @param {string} target
* @param {number|string|string[]} level
*/
addLevel(target, level) {
const maskToAdd = this._parseLevelInput(level);
let currentMask;
if (target === 'Global') {
currentMask = this.globalLevel;
this.globalLevel = currentMask | maskToAdd;
console.log(`[Logger] Added level to Global. New mask: ${this.globalLevel.toString(2)}`);
} else {
currentMask = this.levelConfig[target] !== undefined ? this.levelConfig[target] : this.globalLevel;
this.levelConfig[target] = currentMask | maskToAdd;
console.log(`[Logger] Added level to '${target}'. New mask: ${this.levelConfig[target].toString(2)}`);
}
}
/**
* 移除日志级别(减量模式)
* @param {string} target
* @param {number|string|string[]} level
*/
removeLevel(target, level) {
const maskToRemove = this._parseLevelInput(level);
let currentMask;
if (target === 'Global') {
currentMask = this.globalLevel;
// 使用 & ~mask 实现移除
this.globalLevel = currentMask & ~maskToRemove;
console.log(`[Logger] Removed level from Global. New mask: ${this.globalLevel.toString(2)}`);
} else {
currentMask = this.levelConfig[target] !== undefined ? this.levelConfig[target] : this.globalLevel;
this.levelConfig[target] = currentMask & ~maskToRemove;
console.log(`[Logger] Removed level from '${target}'. New mask: ${this.levelConfig[target].toString(2)}`);
}
}
/**
* 获取指定上下文的生效日志级别掩码(级联查找)
* @param {string} plugin
* @param {string} origin (Module)
*/
_getEffectiveLevelMask(plugin, origin) {
// 1. 检查精确匹配 "Plugin::Module"
const specificKey = `${plugin}::${origin}`;
if (this.levelConfig.hasOwnProperty(specificKey)) {
return this.levelConfig[specificKey];
}
// 2. 检查插件级匹配 "Plugin"
if (this.levelConfig.hasOwnProperty(plugin)) {
return this.levelConfig[plugin];
}
// 3. 返回全局默认
return this.globalLevel;
}
log(plugin, origin, type, message, inFile = false) {
// 获取当前上下文生效的日志级别掩码
const effectiveMask = this._getEffectiveLevelMask(plugin, origin);
// 获取当前日志类型的位码
const typeCode = Logger.LOG_LEVEL_CODE[type];
// 级别筛选位与运算结果为0则表示该级别未开启
if (typeCode === undefined || (effectiveMask & typeCode) === 0) {
return;
}
const timestamp = new Date().toLocaleTimeString();
// 格式: [12:00:00] [PluginName::ClassName] [INFO]: message
const fullMessage = `[${timestamp}] [${plugin}::${origin}] [${type.toUpperCase()}]: ${message}`;
// 1. Console Output
switch (type) {
case 'debug':
console.debug(fullMessage);
break;
case 'info':
console.info(fullMessage);
break;
case 'warn':
console.warn(fullMessage);
break;
case 'error':
console.error(fullMessage);
break;
default:
console.log(fullMessage);
break;
}
// 2. File Output (via FilePipe)
if (inFile) {
// Logger 自身也需要作为系统组件注册,获取写入权限
if (!this.sysBus) {
if (window.Amily2Bus && window.Amily2Bus.register) {
this.sysBus = window.Amily2Bus.register('SystemLogger');
}
}
if (this.sysBus && this.sysBus.file) {
// 使用注册后的安全接口写入,无需再手动传 'SystemLogger'
this.sysBus.file.write('runtime.log', fullMessage + '\n');
} else {
// Fallback: 如果总线未就绪,仅在控制台警告一次,避免死循环
if (!this._warned) {
console.warn('[Logger] FilePipe system not linked. Log not saved to file.');
this._warned = true;
}
}
}
}
}
// Ensure Amily2Bus namespace exists to prevent crash if loaded out of order
window.Amily2Bus = window.Amily2Bus || {};
window.Amily2Bus.Logger = new Logger();
export default Logger;