如何获取Nodejs中显示的console.log行号?

时间:2021-03-15 16:56:03

Got an old application, that prints out quite a lot of messages using console.log, but I just can not find in which files and lines console.log is called.

有一个旧的应用程序,使用console.log打印出相当多的消息,但我无法找到调用console.log的文件和行。

Is there a way to hook into the app and show file name and line numbers?

有没有办法挂钩应用程序并显示文件名和行号?

3 个解决方案

#1


3  

For a temporary hack to find the log statements that you want to get rid of, it's not too difficult to override console.log yourself.

对于临时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();

That will print something like

这将打印出类似的东西

Foobar
Trace
at Console.console.log (index.js:4:13)
at foo (index.js:10:13)
at Object.<anonymous> (index.js:12:1)
...

A lot of noise in there but the second line in the call stack, at foo (index.js:10:13), should point you to the right place.

那里有很多噪音,但是调用堆栈中的第二行,在foo(index.js:10:13),应该指向正确的位置。

#2


9  

Having full stack trace for each call is a bit noisy. I've just improved the @noppa's solution to print only the initiator:

每个呼叫都有完整的堆栈跟踪有点吵。我刚刚改进了@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}`]);
  };
});

It also patches other methods (useful for Nodejs, since warn and error don't come with a stack trace as in Chrome).

它还修补了其他方法(对Nodejs很有用,因为警告和错误不会像Chrome一样带有堆栈跟踪)。

So your console would look something like:

所以你的控制台看起来像:

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)

#3


0  

I found Dmitry Druganov's answer really nice, but I tried it on Windows 10 (with Node 8.9.4) and it didn't work well. It was printing the full path, something like:

我发现德米特里·德鲁加诺夫的答案非常好,但我在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)

So I took said answer and made these improvements (from my point of view):

所以我接受了所说的答案并做了这些改进(从我的角度来看):

  • Assume the important line of the stack trace is the third one (the first one is the word Error and the second one is where you place this script)
  • 假设堆栈跟踪的重要行是第三行(第一行是单词Error,第二行是放置此脚本的位置)

  • Remove the current script folder path (given by __dirname, which in my case is D:\Users\Piyin\Projects\test). Note: For this to work well, the script should be on the project's main Javascript
  • 删除当前脚本文件夹路径(由__dirname给出,在我的例子中是D:\ Users \ Piyin \ Projects \ test)。注意:为了使其正常工作,脚本应该在项目的主要Javascript上

  • Remove the starting at
  • 删除起点

  • Place the file information before the actual log
  • 将文件信息放在实际日志之前

  • Format the information as Class.method at path/to/file:line:column
  • 将信息格式化为Class.method在path / to / file:line:column

Here it is:

这里是:

['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
        ]
      );
    }
  };
});

And here's the new output:

这是新的输出:

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

Here's the minified-by-hand code (240 bytes):

这是手工编写的代码(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])}}});

#1


3  

For a temporary hack to find the log statements that you want to get rid of, it's not too difficult to override console.log yourself.

对于临时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();

That will print something like

这将打印出类似的东西

Foobar
Trace
at Console.console.log (index.js:4:13)
at foo (index.js:10:13)
at Object.<anonymous> (index.js:12:1)
...

A lot of noise in there but the second line in the call stack, at foo (index.js:10:13), should point you to the right place.

那里有很多噪音,但是调用堆栈中的第二行,在foo(index.js:10:13),应该指向正确的位置。

#2


9  

Having full stack trace for each call is a bit noisy. I've just improved the @noppa's solution to print only the initiator:

每个呼叫都有完整的堆栈跟踪有点吵。我刚刚改进了@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}`]);
  };
});

It also patches other methods (useful for Nodejs, since warn and error don't come with a stack trace as in Chrome).

它还修补了其他方法(对Nodejs很有用,因为警告和错误不会像Chrome一样带有堆栈跟踪)。

So your console would look something like:

所以你的控制台看起来像:

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)

#3


0  

I found Dmitry Druganov's answer really nice, but I tried it on Windows 10 (with Node 8.9.4) and it didn't work well. It was printing the full path, something like:

我发现德米特里·德鲁加诺夫的答案非常好,但我在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)

So I took said answer and made these improvements (from my point of view):

所以我接受了所说的答案并做了这些改进(从我的角度来看):

  • Assume the important line of the stack trace is the third one (the first one is the word Error and the second one is where you place this script)
  • 假设堆栈跟踪的重要行是第三行(第一行是单词Error,第二行是放置此脚本的位置)

  • Remove the current script folder path (given by __dirname, which in my case is D:\Users\Piyin\Projects\test). Note: For this to work well, the script should be on the project's main Javascript
  • 删除当前脚本文件夹路径(由__dirname给出,在我的例子中是D:\ Users \ Piyin \ Projects \ test)。注意:为了使其正常工作,脚本应该在项目的主要Javascript上

  • Remove the starting at
  • 删除起点

  • Place the file information before the actual log
  • 将文件信息放在实际日志之前

  • Format the information as Class.method at path/to/file:line:column
  • 将信息格式化为Class.method在path / to / file:line:column

Here it is:

这里是:

['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
        ]
      );
    }
  };
});

And here's the new output:

这是新的输出:

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

Here's the minified-by-hand code (240 bytes):

这是手工编写的代码(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])}}});