CC 4.0 协议声明
本节内容派生于以下链接指向的内容 ,并遵守 CC BY 4.0 许可证的规定。
以下内容如果没有特殊声明,可以认为都是基于原内容的修改和删减后的结果。
Logger
使用 Logger 输出消息是一种向用户展示信息的有效方式。
Rspack logger 可以在 loaders 和 plugins 中使用。 生成的日志将作为 Stats 的一部分并且可以在 rspack configuration 中配置。
使用 Rspack 的 Logger 有如下收益:
- 可统一配置日志的展示级别。
- 日志可作为
stats.json
的一部分。
- Stats 的预设可控制日志的输出。
- 使用 Plugin 可以影响日志的捕获和展示级别。
- 档使用多个 Plugin 和 Loader 时,提供通用的日志方案。
- Rspack 的 CLI、UI 工具可能会选择不同的方式来展示日志。
- Rspack 核心也会输出日志,如一些时间统计数据
通过引入 Rspack 的 Logger API。我们希望能够统一 Plugin 和 Loader 输出日志的方式,以更方便地排查问题和提升开发体验。同时为非 CLI 的集成 Rspack 提供解决方案,如 dashboard 和其他 UI 工具。
避免输出过多日志
避免在输出过多日志!
由于构建过程中使用多个 Plugin 和 Loader,一个 Loader 通常也会处理许多文件。尽量选择一个低等级的日志展示等级来保证日志的信息有效性。
示例
在 Plugin 中使用
插件中有两种方式来获取 Logger:
- compilation.getLogger: 日志内容会被存储到 Stats 中,适合输出与一次 Compilation 关联的日志。
- compiler.getInfrastructureLogger: 日志内容不会被存储,适合输出不与 Compilation 关联的全局信息。
可以在插件中通过如下代码获得 Logger:
MyPlugin.js
const PLUGIN_NAME = 'my-plugin';
export class MyRspackPlugin {
apply(compiler) {
// 获得全局 Logger
const logger = compiler.getInfrastructureLogger(PLUGIN_NAME);
logger.log('log from compiler');
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
// 获得关联 Compilation 的 Logger
const logger = compilation.getLogger(PLUGIN_NAME);
logger.info('log from compilation');
});
}
}
在 Loader 中使用
可以在 Loader Context 上获取 Logger:
MyLoader.js
module.exports = function (source) {
// access Logger from loader
const logger = this.getLogger('my-loader');
logger.info('hello Logger');
return source;
};
Logger API
基础 API
类型: (...args: any[]): void;
按照展示等级从高到低依次为:
error
: 用于输出错误信息。
warn
: 用于输出警告信息。
info
: 用于输出重要的信息,默认会被展示,确保这些信息需要被用户看到。
log
: 用于输出不重要的信息,默认不会被展示
debug
: 用于输出调试信息,需要通过特定的开关开启。
使用 compilation.getLogger
时,可通过 stats.logging
和 stats.loggingDebug
来控制日志的展示等级:
rspack.config.js
module.exports = {
plugins: [{
apply(compiler) {
compiler.hooks.thisCompilation.tap("test plugin", compilation => {
const logger = compilation.getLogger("TEST");
logger.error("I am an error");
logger.warn("I am a warning");
logger.info("I am an information");
logger.log("I am a log");
logger.debug("I am a debug log");
});
}
}],
stats: {
logging: "verbose",
loggingDebug: true
},
};
输出
asset main.js 264 bytes [emitted] (name: main)
runtime modules 124 bytes 2 modules
./index.js 15 bytes [built] [code generated]
DEBUG LOG from TEST
<e> I am an error
<w> I am a warning
<i> I am an information
I am a log
I am a debug log
当使用 compiler.getInfrastructureLogger
时,可通过 infrastructureLogging.level
和 infrastructureLogging.debug
来控制日志的展示等级:
rspack.config.js
module.exports = {
plugins: [{
apply(compiler) {
compiler.hooks.thisCompilation.tap("test plugin", compilation => {
const logger = compiler.getInfrastructureLogger("TEST");
logger.error("I am an error");
logger.warn("I am a warning");
logger.info("I am an information");
logger.log("I am a log");
logger.debug("I am a debug log");
});
}
}],
infrastructureLogging: {
level: "verbose",
debug: true
},
};
输出
<e> [TEST] I am an error
<w> [TEST] I am a warning
<i> [TEST] I am an information
[TEST] I am a log
[TEST] I am a debug log
Rspack compiled successfully in 49 ms
assert
当断言失败时展示错误信息。
- 等级:
error
- 类型::
assert(assertion: any, ...args: any[]): void;
rspack.config.js
logger.assert(false, "I am an assert error");
logger.assert(true, "Never displayed");
输出
LOG from TEST
<e> I am an assert error
status
展示处理状态信息,默认会使用 console.status
,如果不存在则降级到 console.info
。
- 等级:
info
- 类型:
status(...args: any[]): void
rspack.config.js
logger.status("status info");
trace
展示当前堆栈,仅当使用 Compilation Logger 且开启 stats.loggingTrace
可用。
- 等级:
debug
- 类型:
trace(): void
Output
DEBUG LOG from TEST
Trace
| at Object.fn
| at SyncHook.callAsyncStageRange
clear
清除所有之前已打印的所有日志,等同于 console.clear()
。
- 等级:
log
- 类型:
clear(): void;
rspack.config.js
logger.debug("not displayed");
logger.clear();
logger.debug("will displayed");
分组 API
包括如下方法:
group(...args: any[]): void
: 创建一个日志分组,分组信息以 logger.log
展示。
groupEnd(...args: any[]): void
: 结束一个日志分组。
groupCollapsed(...args: any[]): void
: 将日志进行分组。默认显示为折叠 logger.log
日志,当日志记录级别设置为 'verbose' 或 'debug' 时,显示展开的日志。
rspack.config.js
logger.group("Group");
logger.info("Info");
logger.log("Log");
logger.debug("Debug");
logger.groupCollapsed("Collapsed group");
logger.log("Log inside collapsed group");
logger.group("Inner group");
logger.log("Inner inner message");
logger.groupEnd();
logger.groupEnd();
logger.log("Log");
logger.groupEnd();
logger.log("End");
Output
<-> [TEST] Group
<i> [TEST] Info
[TEST] Log
[TEST] Debug
<-> [TEST] Collapsed group
[TEST] Log inside collapsed group
<-> [TEST] Inner group
[TEST] Inner inner message
[TEST] Log
[TEST] End
时间 API
包括如下方法:
time(label: any): void
: 启动一个计时器。
timeLog(label: any): void
: 记录时间差但不关闭计时器。
timeEnd(label: any): void
: 记录时间差并关闭计时器。
timeAggregate(label: any): void
: 叠加记录时间差。
timeAggregateEnd(label: any): void
: 结束叠加记录时间差,并获得时间差总和。
rspack.config.js
const wait = time => new Promise(resolve => setTimeout(resolve, time))
logger.time("normal");
await wait(100);
logger.timeLog("normal");
await wait(100);
logger.timeEnd("normal");
for (let i = 10;i--;) {
logger.time("aggregate")
await wait(i \* 10);
logger.timeAggregate("aggregate")
}
logger.timeAggregateEnd("aggregate")
Output
<t> [TEST] normal: 101.091167 ms
<t> [TEST] normal: 202.565 ms
<t> [TEST] aggregate: 460.416124 ms
Profile API
包括如下方法:
profile(label: any): void
: 开启 Profile 捕获,如果支持会直接代理到 console.profile
。
profileEnd(label: any): void
: 结束 Profile 捕获,如果支持会直接代理到 console.profileEnd
。
子 Logger
可以通过 logger.getChildLogger()
来创建子 Logger,其方法完全一致。
rspack.config.js
const logger = compiler.getInfrastructureLogger("TEST");
logger.info("logger info");
const childLogger = logger.getChildLogger("CHILD");
childLogger.info("child logger info");
Output
<i> [TEST] logger info
<i> [TEST/CHILD] child logger info