有一个旧的应用程序,使用打印出相当多的消息console.log,但我无法找到console.log调用哪些文件和行.
有没有办法挂钩应用程序并显示文件名和行号?
Dmi*_*nov 17
每次通话都有完整的堆栈跟踪有点吵.我刚刚改进了@noppa的解决方案,只打印启动器:
['log', 'warn', 'error'].forEach((methodName) => {
const originalMethod = console[methodName];
console[methodName] = (...args) => {
let initiator = 'unknown place';
try {
throw new Error();
} catch (e) {
if (typeof e.stack === 'string') {
let isFirst = true;
for (const line of e.stack.split('\n')) {
const matches = line.match(/^\s+at\s+(.*)/);
if (matches) {
if (!isFirst) { // first line - current function
// second line - caller (what we are looking for)
initiator = matches[1];
break;
}
isFirst = false;
}
}
}
}
originalMethod.apply(console, [...args, '\n', ` at ${initiator}`]);
};
});
Run Code Online (Sandbox Code Playgroud)
它还修补了其他方法(对Nodejs很有用,因为warn并error没有像Chrome中那样带有堆栈跟踪).
所以你的控制台看起来像:
Loading settings.json
at fs.readdirSync.filter.forEach (.../settings.js:21:13)
Server is running on http://localhost:3000 or http://127.0.0.1:3000
at Server.app.listen (.../index.js:67:11)
Run Code Online (Sandbox Code Playgroud)
nop*_*ppa 12
对于临时hack来查找要删除的日志语句,覆盖console.log自己并不困难.
var log = console.log;
console.log = function() {
log.apply(console, arguments);
// Print the stack trace
console.trace();
};
// Somewhere else...
function foo(){
console.log('Foobar');
}
foo();Run Code Online (Sandbox Code Playgroud)
那将打印出类似的东西
Foobar
Trace
at Console.console.log (index.js:4:13)
at foo (index.js:10:13)
at Object.<anonymous> (index.js:12:1)
...
Run Code Online (Sandbox Code Playgroud)
那里的很多噪音,但是调用堆栈中的第二行at foo (index.js:10:13),应该指向正确的位置.
到目前为止,这个问题的所有解决方案都依赖于将堆栈跟踪拆分和匹配为一个字符串,这将在(不太可能的)情况下打破该字符串的格式在未来发生变化。受GitHub 上的这个要点和这里的其他答案的启发,我想提供我自己的解决方案:
'use strict';
const path = require('path');
['debug', 'log', 'warn', 'error'].forEach((methodName) => {
const originalLoggingMethod = console[methodName];
console[methodName] = (firstArgument, ...otherArguments) => {
const originalPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (_, stack) => stack;
const callee = new Error().stack[1];
Error.prepareStackTrace = originalPrepareStackTrace;
const relativeFileName = path.relative(process.cwd(), callee.getFileName());
const prefix = `${relativeFileName}:${callee.getLineNumber()}:`;
if (typeof firstArgument === 'string') {
originalLoggingMethod(prefix + ' ' + firstArgument, ...otherArguments);
} else {
originalLoggingMethod(prefix, firstArgument, ...otherArguments);
}
};
});
// Tests:
console.log('%s %d', 'hi', 42);
console.log({ a: 'foo', b: 'bar'});
Run Code Online (Sandbox Code Playgroud)
与其他解决方案不同,此脚本
你可以prefix用chalk或color.js 给它上色,但我不想在这里引入依赖关系。
上面的脚本使用V8 API 来自定义堆栈跟踪。该callee是CallSite在情况下,你要自定义的下列方法对象prefix:
getThis: 返回值thisgetTypeName:this以字符串形式返回的类型。这是存储在 的构造函数字段中的函数名称(this如果可用),否则为对象的[[Class]]内部属性。getFunction: 返回当前函数getFunctionName: 返回当前函数的名称,通常是它的name属性。如果某个name属性不可用,则会尝试从函数的上下文中推断出一个名称。getMethodName: 返回this保存当前函数的属性的名称或其原型之一getFileName: 如果这个函数是在脚本中定义的,则返回脚本的名称getLineNumber: 如果这个函数是在脚本中定义的,则返回当前行号getColumnNumber: 如果此函数是在脚本中定义的,则返回当前列号getEvalOrigin:如果这个功能是使用一个调用创建eval返回表示位置的字符串,其中eval被称为isToplevel: 这是顶级调用,也就是说,这是全局对象吗?isEval:此调用是否发生在由调用定义的代码中eval?isNative:这是原生 V8 代码中的调用吗?isConstructor: 这是构造函数调用吗?isAsync:这是一个异步调用(即await或Promise.all())?isPromiseAll: 这是对 的异步调用Promise.all()吗?getPromiseIndex: 返回Promise.all()用于异步堆栈跟踪的 promise 元素的索引,或者null如果CallSite不是Promise.all()调用。
这个答案是我刚刚对一个类似问题给出的答案的交叉帖子,因为更多的人可能会找到这个页面。
我发现Dmitry Druganov的回答确实不错,但是我在Windows 10(带有Node 8.9.4)上尝试了一下,但效果不佳。它正在打印完整路径,例如:
Loading settings.json
at fs.readdirSync.filter.forEach (D:\Users\Piyin\Projects\test\settings.js:21:13)
Server is running on http://localhost:3000 or http://127.0.0.1:3000
at Server.app.listen (D:\Users\Piyin\Projects\test\index.js:67:11)
Run Code Online (Sandbox Code Playgroud)
因此,我回答了我,并做出了以下改进(从我的观点):
Error,第二行是放置此脚本的位置)D:\Users\Piyin\Projects\test)。注意:为使此方法正常运行,脚本应位于项目的主Javascript上atClass.method at path/to/file:line:column这里是:
['log','warn','error'].forEach((methodName) => {
const originalMethod = console[methodName];
console[methodName] = (...args) => {
try {
throw new Error();
} catch (error) {
originalMethod.apply(
console,
[
(
error
.stack // Grabs the stack trace
.split('\n')[2] // Grabs third line
.trim() // Removes spaces
.substring(3) // Removes three first characters ("at ")
.replace(__dirname, '') // Removes script folder path
.replace(/\s\(./, ' at ') // Removes first parentheses and replaces it with " at "
.replace(/\)/, '') // Removes last parentheses
),
'\n',
...args
]
);
}
};
});
Run Code Online (Sandbox Code Playgroud)
这是新的输出:
fs.readdirSync.filter.forEach at settings.js:21:13
Loading settings.json
Server.app.listen at index.js:67:11
Server is running on http://localhost:3000 or http://127.0.0.1:3000
Run Code Online (Sandbox Code Playgroud)
这是最小化的代码(240字节):
['log','warn','error'].forEach(a=>{let b=console[a];console[a]=(...c)=>{try{throw new Error}catch(d){b.apply(console,[d.stack.split('\n')[2].trim().substring(3).replace(__dirname,'').replace(/\s\(./,' at ').replace(/\)/,''),'\n',...c])}}});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8742 次 |
| 最近记录: |