19

When working in Python I always have this simple utility function which returns the file name and line number from where the function is called:

from inspect import getframeinfo, stack
def d():
    """ d stands for Debug. It returns the file name and line number from where this function is called."""
    caller = getframeinfo(stack()[1][0])
    return "%s:%d -" % (caller.filename, caller.lineno)

So in my code I simply put a couple debug lines like this to see how far we get before some error occurs:

print d()
# Some buggy code here
print d()
# More buggy code here
print d(), 'here is the result of some var: ', someVar

This works really well for me because it really helps debugging quickly.

I'm now looking for the equivalent in a node backend script. I was searching around but I can't find anything useful (maybe I'm looking for the wrong words?).

Does anybody know how I can create a Javascript/nodejs function which outputs the file name and line number from where the function is called? All tips are welcome!

kramer65
  • 50,427
  • 120
  • 308
  • 488
  • http://stackoverflow.com/questions/1340872/how-to-get-javascript-caller-function-line-number-how-to-get-javascript-caller?rq=1 and http://stackoverflow.com/questions/13815640/a-proper-wrapper-for-console-log-with-correct-line-number/14841411#14841411 – j08691 Feb 20 '15 at 14:31
  • Have you ever tried [`chrome://inspect`](https://medium.com/the-node-js-collection/debugging-node-js-with-google-chrome-4965b5f910f4)? – Patrick Roberts Nov 03 '17 at 22:53
  • @PatrickRoberts How do you want to use that in order to print the filename and the line of code in NodeJS? – lilezek Nov 03 '17 at 22:54
  • @lilezek if I was trying to answer the question as asked, I would have written an answer. I was suggesting a _much_ better debugging experience than sprinkling random function calls into your code to see approximately where it crashes. – Patrick Roberts Nov 03 '17 at 22:55
  • @PatrickRoberts - I'm not using a browser. This is a pure backend system in which I want to log certain information, including the source of the log. – kramer65 Nov 03 '17 at 22:57
  • @kramer65 please read the linked article instead of telling me what I already know. I'm fully aware you're referring to node.js, and this is a suggestion for exactly that. – Patrick Roberts Nov 03 '17 at 22:58
  • @PatrickRoberts It is ok for me that I know that, but if the OP (or someone reading this) doesn't, he/she might get confused thinking that `chrome://inspect` is just a new way to do what the question asks, not a better alternative for debugging. You could have randomly also offered `Visual Studio Code` as a debugging alternative, which IMHO is a better option for the backend debug. – lilezek Nov 03 '17 at 22:58
  • This was already answered here https://stackoverflow.com/questions/13591785/does-node-js-have-anything-like-file-and-line-like-the-c-preprocessor – Tarun Lalwani Nov 04 '17 at 05:29
  • @kramer65 you've completely changed the context of this question with your recent edit to make it NodeJS specific. My answer given at the time you originally asked this question was completely correct within the context given then. IMHO, this was a completely inappropriate edit, and you should have asked a new question instead. – Alnitak Nov 06 '17 at 11:34

4 Answers4

30

You can create an Error to get where the Error is, and its stack trace. Then you can put that into a function, to get the line where it is.

function thisLine() {
  const e = new Error();
  const regex = /\((.*):(\d+):(\d+)\)$/
  const match = regex.exec(e.stack.split("\n")[2]);
  return {
    filepath: match[1],
    line: match[2],
    column: match[3]
  };
}

console.log(thisLine());

This works for me in Google Chrome.

And also in node.

Note to @j08691's comment:

Both this and this seem to be using lineNumber, which is not present (as far as I could test) in NodeJS.

Shlomo
  • 120
  • 2
  • 8
lilezek
  • 6,976
  • 1
  • 27
  • 45
  • Seems to work fine. I also need the filename though. Can that be added somehow as well? So I need it to look like `filename.js:38` (no need for character number on the line) – kramer65 Nov 03 '17 at 22:34
  • @kramer65 Check the new code. You just have to play with the return value (which right now is an array of two elements) as you need, but it is a beginning. – lilezek Nov 03 '17 at 22:40
  • Thanks! This is what I just ended up with: https://pastebin.com/68pa6jVH . It creates lines like `thefilename.js:345`. I guess this can be made better/cleaner, but now it at least does what I want it to do.. :-) – kramer65 Nov 03 '17 at 22:46
  • @kramer65 By the way just edited the snippet again with a better construction. Uses only a single regex, and returns a human-readable object. – lilezek Nov 03 '17 at 22:48
  • wow, that's even better. Can you make it return the filename, instead of the whole file path? That would keep it even cleaner.. :-) – kramer65 Nov 03 '17 at 22:50
  • 1
    @kramer65 For sure, but book writers usually let readers do something on their own. Look here: https://nodejs.org/api/path.html#path_path_basename_path_ext – lilezek Nov 03 '17 at 22:51
  • The link below shows related compatibility information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack – Karthick May 11 '20 at 09:29
  • After a bit of massage, this even works in QML! (For those of you who know what that is) – BuvinJ Apr 13 '23 at 14:26
1

Printing line number with custom string

const moment = require('moment');
const log = console.log;
const path = require('path');

function getTime(time) { return moment().format('YYYY-MM-DD HH:mm:ss') };

function line(num = 2) {
    const e = new Error();
    const regex = /\((.*):(\d+):(\d+)\)$/
    const match = regex.exec(e.stack.split("\n")[num]);
    const filepath = match[1];
    const fileName = path.basename(filepath);
    const line = match[2];
    const column = match[3];
    return {
        filepath,
        fileName,
        line,
        column,
        str: `${getTime()} - ${fileName}:${line}:${column}`
    };
}

log(line().str, "mylog1");
log(line().str, "mylog2");
log(line().str, "mylog3");

OUTPUT

2021-11-22 13:07:15 - test.js:44:5 mylog1
2021-11-22 13:07:15 - test.js:45:5 mylog2
2021-11-22 13:07:15 - test.js:46:5 mylog3
M. Hamza Rajput
  • 7,810
  • 2
  • 41
  • 36
0

The only way I've found to get anything relating to line numbers is to trap the window.onerror function, and when there's an error that will get passed the error message, the file URL and the line number:

window.onerror = function(msg, url, line) {
    alert(msg + "\n" + url + ":" + line);
};

This works for me on Chrome - I don't know about other browsers.

EDIT when this answer was given in Feb' 15 there was no mention of NodeJS in the question. That was only added in November '17.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • 1
    Node wasn't present in the original question but wasn't Javascript for browsers either. So assuming either Node or web-based JS was wrong IMHO. – lilezek Apr 16 '18 at 15:21
0

You can use this gulp plugin gulp-log-line . It Logs file and line number without the extra cost of reading the stack.

you just have to install gulp and gulp-log-line using the npm install gulp --save and npm install gulp-log-line command. after that you need to create and write the below code in gulpfile.js and run gulp log-line to create a duplicate file in the build folder :-

var gulp = require('gulp');
var logLine = require('gulp-log-line');
gulp.task('line-log', function() {
  return gulp.src("file.js", {buffer : true})
//Write here the loggers you use.
    .pipe(logLine(['console.log', 'winston.info']))
    .pipe(gulp.dest('./build'))

})

gulp.task('default', ['line-log'])

Example

file.js :-

console.log('First log')
var someVariable
console.log('Second log')

Becomes

console.log('file.js:1', 'First log')
var someVariable
console.log('file.js:3', 'Second log')
yawningphantom
  • 386
  • 1
  • 3
  • 9