74 lines
2.9 KiB
TypeScript
Executable File
74 lines
2.9 KiB
TypeScript
Executable File
/* monkey-patch console methods to prefix messages with file:line for easier logs */
|
|
(() => {
|
|
const cwd = process.cwd();
|
|
const cwdRe = new RegExp("^[^/]*" + cwd.replace("/", "\\/") + "/([^:]*:[0-9]*).*$");
|
|
const methods = ["log", "warn", "error", "info", "debug"] as const;
|
|
|
|
function getCallerFileLine(): string {
|
|
try {
|
|
// Create an Error to capture stack
|
|
const err = new Error();
|
|
if (!err.stack) return "unknown:0 -";
|
|
const lines = err.stack.split("\n").slice(1);
|
|
// Find the first stack line that is not this file
|
|
for (let i = 0; i < lines.length; i++) {
|
|
const line = lines[i];
|
|
if (!line) continue;
|
|
if (line.indexOf("console-line") !== -1) continue; // skip this helper
|
|
// Try to extract file:line from the line. Use a stricter capture so we
|
|
// don't accidentally include leading whitespace or the 'at' token.
|
|
const m = line.match(/\(?(\S+:\d+:\d+)\)?$/);
|
|
if (m && m[1]) {
|
|
return m[1].trim() + " -";
|
|
}
|
|
}
|
|
// Fallback: try to extract file:line:col from the third stack line even
|
|
// if it contains leading whitespace and the 'at' prefix. If that fails,
|
|
// fall back to the cwd-based replace and trim whitespace.
|
|
const fallback = err.stack.split("\n")[3] || "";
|
|
const m2 = fallback.match(/\(?(\S+:\d+:\d+)\)?$/);
|
|
if (m2 && m2[1]) return m2[1].trim() + " -";
|
|
const replaced = fallback.replace(cwdRe, "$1 -").trim();
|
|
return replaced || "unknown:0 -";
|
|
} catch (e) {
|
|
return "unknown:0 -";
|
|
}
|
|
}
|
|
|
|
methods.forEach((method) => {
|
|
const orig = (console as any)[method] || console.log;
|
|
(console as any)[method] = function (...args: any[]) {
|
|
try {
|
|
const prefix = getCallerFileLine();
|
|
|
|
// Separate Error objects from other args so we can print their stacks
|
|
// line-by-line with the same prefix. This keeps stack traces intact
|
|
// while ensuring every printed line shows the caller prefix.
|
|
const errorArgs = args.filter((a: any) => a instanceof Error) as Error[];
|
|
const otherArgs = args.filter((a: any) => !(a instanceof Error));
|
|
|
|
// Print non-error args in a single call (preserving original formatting)
|
|
const processedOther = otherArgs.map((a: any) => (a instanceof Error ? a.stack || a.toString() : a));
|
|
if (processedOther.length > 0) {
|
|
orig.apply(this, [prefix, ...processedOther]);
|
|
}
|
|
|
|
// For each Error, print each line of its stack as a separate prefixed log
|
|
// entry so lines that begin with ' at' are not orphaned.
|
|
errorArgs.forEach((err) => {
|
|
const stack = err.stack || err.toString();
|
|
stack.split("\n").forEach((line) => {
|
|
orig.apply(this, [prefix, line]);
|
|
});
|
|
});
|
|
} catch (e) {
|
|
try {
|
|
orig.apply(this, args);
|
|
} catch (e2) {
|
|
/* swallow */
|
|
}
|
|
}
|
|
};
|
|
});
|
|
})();
|