Skip to content

Commit

Permalink
Merge pull request #13051 from KENNYSOFT/infrastructurelogging-colors
Browse files Browse the repository at this point in the history
  • Loading branch information
sokra committed Apr 6, 2021
2 parents 6f66c70 + e5e7b32 commit 48b7cce
Show file tree
Hide file tree
Showing 17 changed files with 339 additions and 160 deletions.
16 changes: 16 additions & 0 deletions declarations/WebpackOptions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,18 @@ export interface ExternalsPresets {
* Options for infrastructure level logging.
*/
export interface InfrastructureLogging {
/**
* Only appends lines to the output. Avoids updating existing output e. g. for status messages. This option is only used when no custom console is provided.
*/
appendOnly?: boolean;
/**
* Enables/Disables colorful output. This option is only used when no custom console is provided.
*/
colors?: boolean;
/**
* Custom console used for logging.
*/
console?: Console;
/**
* Enable debug logging for specific loggers.
*/
Expand All @@ -1207,6 +1219,10 @@ export interface InfrastructureLogging {
* Log level.
*/
level?: "none" | "error" | "warn" | "info" | "log" | "verbose";
/**
* Stream used for logging output. Defaults to process.stderr. This option is only used when no custom console is provided.
*/
stream?: NodeJS.WritableStream;
}
/**
* Custom values available in the loader context.
Expand Down
9 changes: 7 additions & 2 deletions lib/config/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ const A = (obj, prop, factory) => {
*/
const applyWebpackOptionsBaseDefaults = options => {
F(options, "context", () => process.cwd());
applyInfrastructureLoggingDefaults(options.infrastructureLogging);
};

/**
Expand Down Expand Up @@ -235,8 +236,6 @@ const applyWebpackOptionsDefaults = options => {
getResolveLoaderDefaults({ cache }),
options.resolveLoader
);

applyInfrastructureLoggingDefaults(options.infrastructureLogging);
};

/**
Expand Down Expand Up @@ -1077,8 +1076,14 @@ const getResolveLoaderDefaults = ({ cache }) => {
* @returns {void}
*/
const applyInfrastructureLoggingDefaults = infrastructureLogging => {
F(infrastructureLogging, "stream", () => process.stderr);
const tty =
/** @type {any} */ (infrastructureLogging.stream).isTTY &&
process.env.TERM !== "dumb";
D(infrastructureLogging, "level", "info");
D(infrastructureLogging, "debug", false);
D(infrastructureLogging, "colors", tty);
D(infrastructureLogging, "appendOnly", !tty);
};

exports.applyWebpackOptionsBaseDefaults = applyWebpackOptionsBaseDefaults;
Expand Down
20 changes: 19 additions & 1 deletion lib/logging/createConsoleLogger.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,29 @@ const { LogType } = require("./Logger");

/** @typedef {function(string): boolean} FilterFunction */

/**
* @typedef {Object} LoggerConsole
* @property {function(): void} clear
* @property {function(): void} trace
* @property {(...args: any[]) => void} info
* @property {(...args: any[]) => void} log
* @property {(...args: any[]) => void} warn
* @property {(...args: any[]) => void} error
* @property {(...args: any[]) => void=} debug
* @property {(...args: any[]) => void=} group
* @property {(...args: any[]) => void=} groupCollapsed
* @property {(...args: any[]) => void=} groupEnd
* @property {(...args: any[]) => void=} status
* @property {(...args: any[]) => void=} profile
* @property {(...args: any[]) => void=} profileEnd
* @property {(...args: any[]) => void=} logTime
*/

/**
* @typedef {Object} LoggerOptions
* @property {false|true|"none"|"error"|"warn"|"info"|"log"|"verbose"} level loglevel
* @property {FilterTypes|boolean} debug filter for debug logging
* @property {Console & { status?: Function, logTime?: Function }} console the console to log to
* @property {LoggerConsole} console the console to log to
*/

/**
Expand Down
29 changes: 18 additions & 11 deletions lib/node/NodeEnvironmentPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@ const createConsoleLogger = require("../logging/createConsoleLogger");
const NodeWatchFileSystem = require("./NodeWatchFileSystem");
const nodeConsole = require("./nodeConsole");

/** @typedef {import("../../declarations/WebpackOptions").InfrastructureLogging} InfrastructureLogging */
/** @typedef {import("../Compiler")} Compiler */

class NodeEnvironmentPlugin {
/**
* @param {Object} options options
* @param {InfrastructureLogging} options.infrastructureLogging infrastructure logging options
*/
constructor(options) {
this.options = options || {};
this.options = options;
}

/**
Expand All @@ -24,16 +29,18 @@ class NodeEnvironmentPlugin {
* @returns {void}
*/
apply(compiler) {
compiler.infrastructureLogger = createConsoleLogger(
Object.assign(
{
level: "info",
debug: false,
console: nodeConsole
},
this.options.infrastructureLogging
)
);
const { infrastructureLogging } = this.options;
compiler.infrastructureLogger = createConsoleLogger({
level: infrastructureLogging.level || "info",
debug: infrastructureLogging.debug || false,
console:
infrastructureLogging.console ||
nodeConsole({
colors: infrastructureLogging.colors,
appendOnly: infrastructureLogging.appendOnly,
stream: infrastructureLogging.stream
})
});
compiler.inputFileSystem = new CachedInputFileSystem(fs, 60000);
const inputFileSystem = compiler.inputFileSystem;
compiler.outputFileSystem = fs;
Expand Down
233 changes: 121 additions & 112 deletions lib/node/nodeConsole.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,127 +8,136 @@
const util = require("util");
const truncateArgs = require("../logging/truncateArgs");

const tty = process.stderr.isTTY && process.env.TERM !== "dumb";
module.exports = ({ colors, appendOnly, stream }) => {
let currentStatusMessage = undefined;
let hasStatusMessage = false;
let currentIndent = "";
let currentCollapsed = 0;

let currentStatusMessage = undefined;
let hasStatusMessage = false;
let currentIndent = "";
let currentCollapsed = 0;

const indent = (str, prefix, colorPrefix, colorSuffix) => {
if (str === "") return str;
prefix = currentIndent + prefix;
if (tty) {
return (
prefix +
colorPrefix +
str.replace(/\n/g, colorSuffix + "\n" + prefix + colorPrefix) +
colorSuffix
);
} else {
return prefix + str.replace(/\n/g, "\n" + prefix);
}
};
const indent = (str, prefix, colorPrefix, colorSuffix) => {
if (str === "") return str;
prefix = currentIndent + prefix;
if (colors) {
return (
prefix +
colorPrefix +
str.replace(/\n/g, colorSuffix + "\n" + prefix + colorPrefix) +
colorSuffix
);
} else {
return prefix + str.replace(/\n/g, "\n" + prefix);
}
};

const clearStatusMessage = () => {
if (hasStatusMessage) {
process.stderr.write("\x1b[2K\r");
hasStatusMessage = false;
}
};
const clearStatusMessage = () => {
if (hasStatusMessage) {
stream.write("\x1b[2K\r");
hasStatusMessage = false;
}
};

const writeStatusMessage = () => {
if (!currentStatusMessage) return;
const l = process.stderr.columns;
const args = l
? truncateArgs(currentStatusMessage, l - 1)
: currentStatusMessage;
const str = args.join(" ");
const coloredStr = `\u001b[1m${str}\u001b[39m\u001b[22m`;
process.stderr.write(`\x1b[2K\r${coloredStr}`);
hasStatusMessage = true;
};
const writeStatusMessage = () => {
if (!currentStatusMessage) return;
const l = stream.columns;
const args = l
? truncateArgs(currentStatusMessage, l - 1)
: currentStatusMessage;
const str = args.join(" ");
const coloredStr = `\u001b[1m${str}\u001b[39m\u001b[22m`;
stream.write(`\x1b[2K\r${coloredStr}`);
hasStatusMessage = true;
};

const writeColored = (prefix, colorPrefix, colorSuffix) => {
return (...args) => {
if (currentCollapsed > 0) return;
clearStatusMessage();
const str = indent(util.format(...args), prefix, colorPrefix, colorSuffix);
process.stderr.write(str + "\n");
writeStatusMessage();
const writeColored = (prefix, colorPrefix, colorSuffix) => {
return (...args) => {
if (currentCollapsed > 0) return;
clearStatusMessage();
const str = indent(
util.format(...args),
prefix,
colorPrefix,
colorSuffix
);
stream.write(str + "\n");
writeStatusMessage();
};
};
};

const writeGroupMessage = writeColored(
"<-> ",
"\u001b[1m\u001b[36m",
"\u001b[39m\u001b[22m"
);
const writeGroupMessage = writeColored(
"<-> ",
"\u001b[1m\u001b[36m",
"\u001b[39m\u001b[22m"
);

const writeGroupCollapsedMessage = writeColored(
"<+> ",
"\u001b[1m\u001b[36m",
"\u001b[39m\u001b[22m"
);
const writeGroupCollapsedMessage = writeColored(
"<+> ",
"\u001b[1m\u001b[36m",
"\u001b[39m\u001b[22m"
);

module.exports = {
log: writeColored(" ", "\u001b[1m", "\u001b[22m"),
debug: writeColored(" ", "", ""),
trace: writeColored(" ", "", ""),
info: writeColored("<i> ", "\u001b[1m\u001b[32m", "\u001b[39m\u001b[22m"),
warn: writeColored("<w> ", "\u001b[1m\u001b[33m", "\u001b[39m\u001b[22m"),
error: writeColored("<e> ", "\u001b[1m\u001b[31m", "\u001b[39m\u001b[22m"),
logTime: writeColored("<t> ", "\u001b[1m\u001b[35m", "\u001b[39m\u001b[22m"),
group: (...args) => {
writeGroupMessage(...args);
if (currentCollapsed > 0) {
return {
log: writeColored(" ", "\u001b[1m", "\u001b[22m"),
debug: writeColored(" ", "", ""),
trace: writeColored(" ", "", ""),
info: writeColored("<i> ", "\u001b[1m\u001b[32m", "\u001b[39m\u001b[22m"),
warn: writeColored("<w> ", "\u001b[1m\u001b[33m", "\u001b[39m\u001b[22m"),
error: writeColored("<e> ", "\u001b[1m\u001b[31m", "\u001b[39m\u001b[22m"),
logTime: writeColored(
"<t> ",
"\u001b[1m\u001b[35m",
"\u001b[39m\u001b[22m"
),
group: (...args) => {
writeGroupMessage(...args);
if (currentCollapsed > 0) {
currentCollapsed++;
} else {
currentIndent += " ";
}
},
groupCollapsed: (...args) => {
writeGroupCollapsedMessage(...args);
currentCollapsed++;
} else {
currentIndent += " ";
}
},
groupCollapsed: (...args) => {
writeGroupCollapsedMessage(...args);
currentCollapsed++;
},
groupEnd: () => {
if (currentCollapsed > 0) currentCollapsed--;
else if (currentIndent.length >= 2)
currentIndent = currentIndent.slice(0, currentIndent.length - 2);
},
// eslint-disable-next-line node/no-unsupported-features/node-builtins
profile: console.profile && (name => console.profile(name)),
// eslint-disable-next-line node/no-unsupported-features/node-builtins
profileEnd: console.profileEnd && (name => console.profileEnd(name)),
clear:
tty &&
},
groupEnd: () => {
if (currentCollapsed > 0) currentCollapsed--;
else if (currentIndent.length >= 2)
currentIndent = currentIndent.slice(0, currentIndent.length - 2);
},
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.clear &&
(() => {
clearStatusMessage();
profile: console.profile && (name => console.profile(name)),
// eslint-disable-next-line node/no-unsupported-features/node-builtins
profileEnd: console.profileEnd && (name => console.profileEnd(name)),
clear:
!appendOnly &&
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.clear();
writeStatusMessage();
}),
status: tty
? (name, ...args) => {
args = args.filter(Boolean);
if (name === undefined && args.length === 0) {
clearStatusMessage();
currentStatusMessage = undefined;
} else if (
typeof name === "string" &&
name.startsWith("[webpack.Progress] ")
) {
currentStatusMessage = [name.slice(19), ...args];
writeStatusMessage();
} else if (name === "[webpack.Progress]") {
currentStatusMessage = [...args];
writeStatusMessage();
} else {
currentStatusMessage = [name, ...args];
writeStatusMessage();
}
}
: writeColored("<s> ", "", "")
console.clear &&
(() => {
clearStatusMessage();
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.clear();
writeStatusMessage();
}),
status: appendOnly
? writeColored("<s> ", "", "")
: (name, ...args) => {
args = args.filter(Boolean);
if (name === undefined && args.length === 0) {
clearStatusMessage();
currentStatusMessage = undefined;
} else if (
typeof name === "string" &&
name.startsWith("[webpack.Progress] ")
) {
currentStatusMessage = [name.slice(19), ...args];
writeStatusMessage();
} else if (name === "[webpack.Progress]") {
currentStatusMessage = [...args];
writeStatusMessage();
} else {
currentStatusMessage = [name, ...args];
writeStatusMessage();
}
}
};
};

0 comments on commit 48b7cce

Please sign in to comment.