Skip to content

Commit b733e3a

Browse files
committed
feat(logger): Add module filtering, task-skip event
Allow filtering of log messages by module names using an environment variable UI5_LOG_MODULES. Inspired by the 'debug' npm package. **Examples:** * `UI5_LOG_MODULES=specifications:*,graph:Module,Build ui5 build` * `UI5_LOG_MODULES=graph:*,-graph:providers:* ui5 serve --verbose` Add a new log event "task-skip". Cherry-pick of SAP/ui5-logger#480 JIRA: CPOUI5FOUNDATION-1174
1 parent cadc077 commit b733e3a

File tree

3 files changed

+157
-1
lines changed

3 files changed

+157
-1
lines changed

packages/logger/lib/loggers/ProjectBuild.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,24 @@ class ProjectBuild extends Logger {
8383
this._log(level, `${this.#projectName}: Finished task ${taskName}`);
8484
}
8585
}
86+
87+
skipTask(taskName) {
88+
if (!this.#tasksToRun || !this.#tasksToRun.includes(taskName)) {
89+
throw new Error(`loggers/ProjectBuild#skipTask: Unknown task ${taskName}`);
90+
}
91+
const level = "info";
92+
const hasListeners = this._emit(ProjectBuild.PROJECT_BUILD_STATUS_EVENT_NAME, {
93+
level,
94+
projectName: this.#projectName,
95+
projectType: this.#projectType,
96+
taskName,
97+
status: "task-skip",
98+
});
99+
100+
if (!hasListeners) {
101+
this._log(level, `${this.#projectName}: Skipping task ${taskName}`);
102+
}
103+
}
86104
}
87105

88106
export default ProjectBuild;

packages/logger/lib/writers/Console.js

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class Console {
2121
#progressBarContainer;
2222
#progressBar;
2323
#progressProjectWeight;
24+
#moduleFilter;
2425

2526
constructor() {
2627
this._handleLogEvent = this.#handleLogEvent.bind(this);
@@ -31,6 +32,65 @@ class Console {
3132
this._handleStop = this.disable.bind(this);
3233
}
3334

35+
#initFiters() {
36+
const modulesPatterns = process.env.UI5_LOG_MODULES;
37+
if (!modulesPatterns) {
38+
this.#moduleFilter = null;
39+
return;
40+
}
41+
const enabledModules = [];
42+
const enabledNamespaces = [];
43+
const disabledModules = [];
44+
const disabledNamespaces = [];
45+
// Example of modulePattern: "module1,module2:submodule:subsubmodule,module3:*:-module3:submodule"
46+
modulesPatterns.split(",").forEach((modulePattern) => {
47+
const pattern = modulePattern.trim();
48+
if (pattern.startsWith("-")) {
49+
if (pattern.endsWith(":*")) {
50+
disabledNamespaces.push(pattern.substring(1, pattern.length - 2));
51+
} else {
52+
disabledModules.push(pattern.substring(1));
53+
}
54+
} else {
55+
if (pattern.endsWith(":*")) {
56+
enabledNamespaces.push(pattern.substring(0, pattern.length - 2));
57+
} else {
58+
enabledModules.push(pattern);
59+
}
60+
}
61+
});
62+
63+
this.#moduleFilter = {
64+
enabledModules,
65+
enabledNamespaces,
66+
disabledModules,
67+
disabledNamespaces,
68+
};
69+
}
70+
71+
#filterModule(moduleName) {
72+
if (!this.#moduleFilter) {
73+
return true;
74+
}
75+
if (this.#moduleFilter.disabledModules.includes(moduleName)) {
76+
return false;
77+
}
78+
if (this.#moduleFilter.enabledModules.includes(moduleName)) {
79+
return true;
80+
}
81+
const moduleParts = moduleName.split(":");
82+
for (let i = moduleParts.length - 1; i > 0; i--) {
83+
const namespace = moduleParts.slice(0, i).join(":");
84+
if (this.#moduleFilter.disabledNamespaces.includes(namespace)) {
85+
return false;
86+
}
87+
if (this.#moduleFilter.enabledNamespaces.includes(namespace)) {
88+
return true;
89+
}
90+
}
91+
return false;
92+
}
93+
3494
/**
3595
* Attaches all event listeners and starts writing to output stream
3696
*
@@ -137,7 +197,9 @@ class Console {
137197
}
138198

139199
#handleLogEvent({level, message, moduleName}) {
140-
this.#writeMessage(level, `${chalk.blue(moduleName)} ${message}`);
200+
if (this.#filterModule(moduleName)) {
201+
this.#writeMessage(level, `${chalk.blue(moduleName)} ${message}`);
202+
}
141203
}
142204

143205
#handleBuildMetadataEvent({projectsToBuild}) {
@@ -328,6 +390,27 @@ class Console {
328390
taskMetadata.executionEnded = true;
329391
message = `${chalk.green(figures.tick)} Finished task ${chalk.bold(taskName)}`;
330392

393+
// Update progress bar (if used)
394+
this._getProgressBar()?.increment(1);
395+
break;
396+
case "task-skip":
397+
if (taskMetadata.executionSkipped) {
398+
throw new Error(`writers/Console: ` +
399+
`Unexpected duplicate task-skip event for project ${projectName}, task ${taskName}`);
400+
}
401+
if (taskMetadata.executionStarted) {
402+
throw new Error(`writers/Console: ` +
403+
`Unexpected task-skip event for project ${projectName}, task ${taskName}. ` +
404+
`Task execution already started`);
405+
}
406+
if (taskMetadata.executionEnded) {
407+
throw new Error(`writers/Console: ` +
408+
`Unexpected task-skip event for project ${projectName}, task ${taskName}. ` +
409+
`Task execution already ended`);
410+
}
411+
taskMetadata.executionEnded = true;
412+
message = `${chalk.green(figures.tick)} Skipping task ${chalk.bold(taskName)}`;
413+
331414
// Update progress bar (if used)
332415
this._getProgressBar()?.increment(1);
333416
break;

packages/logger/test/lib/loggers/ProjectBuild.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,58 @@ test.serial("End task: Unknown task", (t) => {
228228
}, "Threw with expected error message");
229229
});
230230

231+
test.serial("Skip task", (t) => {
232+
const {projectBuildLogger, logHandler, metadataHandler, statusHandler, logStub} = t.context;
233+
projectBuildLogger.setTasks(["task.a"]);
234+
235+
projectBuildLogger.skipTask("task.a");
236+
237+
t.is(statusHandler.callCount, 1, "One build-status event emitted");
238+
t.deepEqual(statusHandler.getCall(0).args[0], {
239+
level: "info",
240+
projectName: "projectName",
241+
projectType: "projectType",
242+
status: "task-skip",
243+
taskName: "task.a",
244+
}, "Metadata event has expected payload");
245+
246+
t.is(logHandler.callCount, 0, "No log event emitted");
247+
t.is(metadataHandler.callCount, 1, "One build-metadata event emitted");
248+
t.is(logStub.callCount, 0, "_log was never called");
249+
});
250+
251+
test.serial("No event listener: Skip task", (t) => {
252+
const {projectBuildLogger, logHandler, metadataHandler, statusHandler, logStub} = t.context;
253+
process.off(ProjectBuildLogger.PROJECT_BUILD_STATUS_EVENT_NAME, statusHandler);
254+
projectBuildLogger.setTasks(["task.a"]);
255+
256+
projectBuildLogger.skipTask("task.a");
257+
t.is(logStub.callCount, 1, "_log got called once");
258+
t.is(logStub.getCall(0).args[0], "info", "Logged with expected log-level");
259+
t.is(logStub.getCall(0).args[1],
260+
"projectName: Skipping task task.a",
261+
"Logged expected message");
262+
263+
t.is(logHandler.callCount, 0, "No log event emitted");
264+
t.is(metadataHandler.callCount, 1, "One build-metadata event emitted");
265+
});
266+
267+
test.serial("Skip task: Unknown task", (t) => {
268+
const {projectBuildLogger} = t.context;
269+
270+
// Throws because no projects are set
271+
t.throws(() => {
272+
projectBuildLogger.skipTask("task.x");
273+
}, {
274+
message: `loggers/ProjectBuild#skipTask: Unknown task task.x`
275+
}, "Threw with expected error message");
276+
277+
projectBuildLogger.setTasks(["task.a"]);
278+
// Throws because given project is unknown
279+
t.throws(() => {
280+
projectBuildLogger.skipTask("task.x");
281+
}, {
282+
message: `loggers/ProjectBuild#skipTask: Unknown task task.x`
283+
}, "Threw with expected error message");
284+
});
285+

0 commit comments

Comments
 (0)