Reputation: 1793
I am using the following for getting the JavaScript caller function name:
var callerFunc = arguments.callee.caller.toString();
callerFuncName = (callerFunc.substring(callerFunc.indexOf("function") + 8, callerFunc.indexOf("(")) || "anoynmous")
Is there a way to discover the line number from which the method was called?
Also, is there a way to get the name of the JavaScript file the method was called from? Or the source URL?
Upvotes: 135
Views: 145237
Reputation: 35830
If you need to access the line number of something in Firefox or Opera, just access
(new Error).lineNumber
Note: this does not work on Chrome/Safari.
Upvotes: 28
Reputation: 4959
I realize this is an old question but there is now a method called
console.trace("Message");
that will show you the line number and the chain of method calls that led to the log along with the message you pass it. More info on javascript logging tricks are available here at freecodecamp and this medium blog post
Upvotes: 13
Reputation: 7340
If you need something that is very complete and accurate, for v8 (meaning NodeJS and Chrome) there is the stack-trace
package, which worked for me:
https://www.npmjs.com/package/stack-trace
This has several advantages: being able to produce deep stack-traces, being able to traverse async
calls, and providing the full URL of scripts at every stack-frame.
You can find more information about the v8 stack-track API here.
If you need something that works in more browsers, there is this package:
https://www.npmjs.com/package/stacktrace-js
This library parses the formatted stack-trace strings you normally see in the devtools console, which means it only has access to information that actually appears in a formatted stack-track - unlike the v8 API, you can't get (among other things) the full URL of the script in a stack-frame.
Note that parsing a formatted stack-trace is a somewhat fragile approach, as this formatting could change in the browsers, which would break your app.
As far as I know, there is no safer bet for something cross-browser - if you need something fast, accurate and complete that works in all browsers, you're pretty much out of luck.
Upvotes: 3
Reputation: 1530
It was easier in the past, but at this time with browser updates:
This is the safe Multi Browser Solution
<!DOCTYPE html>
<html lang="en">
<head>
<script>
var lastErr;
function errHand(e) {
lastErr = e;
switch (e.target.nodeName) {
case 'SCRIPT':
alert('script not found: ' + e.srcElement.src);
break;
case 'LINK':
alert('css not found: ' + e.srcElement.href);
}
return false;
}
window.onerror = function (msg, url, lineNo, columnNo, error) {
alert(msg + ' - ' + url + ' - ' + lineNo + ' - ' + columnNo);
return false;
}
</script>
<script src="http://22.com/k.js" onerror="errHand(event)"></script>
<link rel="stylesheet" href="http://22.com/k.css" onerror="errHand(event)" type="text/css" />
</head>
<body>
<script>
not_exist_function();
</script>
</body>
</html>
For NodeJS - Global Error Handling Solution
process.on('uncaughtException', function (err) {
console.error('uncaughtException:\n' + err.stack + '\n');
})
This is very useful, Because it will show up you errors that exist but dont break your main program process.
Upvotes: 2
Reputation: 24035
I was surprised that most of these answers assumed that you wanted to handle an error rather than just output helpful debug traces for normal cases as well.
For example, I like using a console.log
wrapper like this:
consoleLog = function(msg) {//See https://stackoverflow.com/a/27074218/470749
var e = new Error();
if (!e.stack) {
try {
// IE requires the Error to actually be thrown or else the
// Error's 'stack' property is undefined.
throw e;
} catch (e) {
if (!e.stack) {
//return 0; // IE < 10, likely
}
}
}
var stack = e.stack.toString().split(/\r\n|\n/);
if (msg === '') {
msg = '""';
}
console.log(msg, ' [' + stack[1] + ']');
}
This ends up printing an output such as the following to my console:
1462567104174 [getAllPosts@http://me.com/helper.js:362:9]
See https://stackoverflow.com/a/27074218/ and also A proper wrapper for console.log with correct line number?
Upvotes: 20
Reputation: 4558
This is how I have done it, I have tested it in both Firefox and Chrome. This makes it possible to check the filename and line number of the place where the function is called from.
logFileAndLineNumber(new Error());
function logFileAndLineNumber(newErr)
{
if(navigator.userAgent.indexOf("Firefox") != -1)
{
var originPath = newErr.stack.split('\n')[0].split("/");
var fileNameAndLineNumber = originPath[originPath.length - 1].split(">")[0];
console.log(fileNameAndLineNumber);
}else if(navigator.userAgent.indexOf("Chrome") != -1)
{
var originFile = newErr.stack.split('\n')[1].split('/');
var fileName = originFile[originFile.length - 1].split(':')[0];
var lineNumber = originFile[originFile.length - 1].split(':')[1];
console.log(fileName+" line "+lineNumber);
}
}
Upvotes: 4
Reputation: 3433
Line number is actually something static, so if you just want it for logging then it could be preprocessed with something like gulp. I've written a small gulp plugin that does exactly that:
var gulp = require('gulp');
var logLine = require('gulp-log-line');
gulp.task('log-line', function() {
return gulp.src("file.js", {buffer : true})
//Write here the loggers you use.
.pipe(logLine(['console.log']))
.pipe(gulp.dest('./build'))
})
gulp.task('default', ['log-line'])
This will attach the file name and line to all logs from console.log, so console.log(something)
will become console.log('filePath:fileNumber', something)
. The advantage is that now you can concat your files, transpile them... and you will still get the line
Upvotes: 4
Reputation: 1194
My contribution to custom errors in JavaScript:
First, I agree with this @B T guy at Inheriting from the Error object - where is the message property?, we have to built it properly (actually you have to use a js object library, my favorite: https://github.com/jiem/my-class):
window.g3 = window.g3 || {};
g3.Error = function (message, name, original) {
this.original = original;
this.name = name || 'Error.g3';
this.message = message || 'A g3.Error was thrown!';
(original)? this.stack = this.original.stack: this.stack = null;
this.message += '<br>---STACK---<br>' + this.stack;
};
var ClassEmpty = function() {};
ClassEmpty.prototype = Error.prototype;
g3.Error.prototype = new ClassEmpty();
g3.Error.prototype.constructor = g3.Error;
then, we should define a global error handling function (optional) or, they'll end up to the engine:
window.onerror = printError;
function printError(msg, url, line){
document.getElementById('test').innerHTML = msg+'<br>at: '+url+'<br>line: '+line;
return true;
}
finally, we should throw our custom errors carefully:
//hit it!
//throw new g3.Error('Hey, this is an error message!', 'Error.Factory.g3');
throw new g3.Error('Hey, this is an error message!', 'Error.Factory.g3', new Error());
Only, when passing the third parameter as new Error()
we are able to see the stack with function and line numbers!
At 2, the function can also handle error thrown by the engine as well.
Of course, the real question is if we really need it and when; there are cases (99% in my opinion) where a graceful return of false
is enough and leave only some critical points to be shown with the thrown of an error.
Example: http://jsfiddle.net/centurianii/m2sQ3/1/
Upvotes: 2
Reputation: 1205
the following code works for me in Mozilla and Chrome.
Its log function that shows the file's name and the line of the caller.
log: function (arg) {
var toPrint = [];
for (var i = 0; i < arguments.length; ++i) {
toPrint.push(arguments[i]);
}
function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}
var err = getErrorObject(),
caller;
if ($.browser.mozilla) {
caller = err.stack.split("\n")[2];
} else {
caller = err.stack.split("\n")[4];
}
var index = caller.indexOf('.js');
var str = caller.substr(0, index + 3);
index = str.lastIndexOf('/');
str = str.substr(index + 1, str.length);
var info = "\t\tFile: " + str;
if ($.browser.mozilla) {
str = caller;
} else {
index = caller.lastIndexOf(':');
str = caller.substr(0, index);
}
index = str.lastIndexOf(':');
str = str.substr(index + 1, str.length);
info += " Line: " + str;
toPrint.push(info);
console.log.apply(console, toPrint);
}
Upvotes: 2
Reputation: 2975
Here is what I wrote based on info found on this forum:
This is part of a MyDebugNamespace, Debug is apparently reserved and won't do as namespace name.
var DEBUG = true;
...
if (true == DEBUG && !test)
{
var sAlert = "Assertion failed! ";
if (null != message)
sAlert += "\n" + message;
if (null != err)
sAlert += "\n" + "File: " + err.fileName + "\n" + "Line: " + err.lineNumber;
alert(sAlert);
}
...
How to call:
MyDebugNamespace.Assert(new Error(""), (null != someVar), "Something is wrong!")
I included two functions with variable number of arguments calling this base code in my namespace so as to optionally omit message or error in calls.
This works fine with Firefox, IE6 and Chrome report the fileName and lineNumber as undefined.
Upvotes: 2
Reputation: 41
It seems I'm kind of late :), but the discussion is pretty interesting so.. here it goes... Assuming you want to build a error handler, and you're using your own exception handler class like:
function errorHandler(error){
this.errorMessage = error;
}
errorHandler.prototype. displayErrors = function(){
throw new Error(this.errorMessage);
}
And you're wrapping your code like this:
try{
if(condition){
//whatever...
}else{
throw new errorHandler('Some Error Message');
}
}catch(e){
e.displayErrors();
}
Most probably you'll have the error handler in a separate .js file.
You'll notice that in firefox or chrome's error console the code line number(and file name) showed is the line(file) that throws the 'Error' exception and not the 'errorHandler' exception wich you really want in order to make debugging easy. Throwing your own exceptions is great but on large projects locating them can be quite an issue, especially if they have similar messages. So, what you can do is to pass a reference to an actual empty Error object to your error handler, and that reference will hold all the information you want( for example in firefox you can get the file name, and line number etc.. ; in chrome you get something similar if you read the 'stack' property of the Error instance). Long story short , you can do something like this:
function errorHandler(error, errorInstance){
this.errorMessage = error;
this. errorInstance = errorInstance;
}
errorHandler.prototype. displayErrors = function(){
//add the empty error trace to your message
this.errorMessage += ' stack trace: '+ this. errorInstance.stack;
throw new Error(this.errorMessage);
}
try{
if(condition){
//whatever...
}else{
throw new errorHandler('Some Error Message', new Error());
}
}catch(e){
e.displayErrors();
}
Now you can get the actual file and line number that throwed you custom exception.
Upvotes: 4
Reputation: 1206
This works for me in chrome/QtWebView
function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}
var err = getErrorObject();
var caller_line = err.stack.split("\n")[4];
var index = caller_line.indexOf("at ");
var clean = caller_line.slice(index+2, caller_line.length);
Upvotes: 119
Reputation: 39168
This is often achieved by throwing an error from the current context; then analyzing error object for properties like lineNumber
and fileName
(which some browsers have)
function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}
var err = getErrorObject();
err.fileName;
err.lineNumber; // or `err.line` in WebKit
Don't forget that callee.caller
property is deprecated (and was never really in ECMA 3rd ed. in the first place).
Also remember that function decompilation is specified to be implementation dependent and so might yield quite unexpected results. I wrote about it here and here.
Upvotes: 5
Reputation: 10795
If you would like to know the line number for debugging purposes, or only during development (For a reason or another), you could use Firebug (a Firefox extension) and throw an exception.
Edit:
If you really need to do that in production for some reason, you can pre-process your javascript files in order for each function to keep track of the line it is on. I know some frameworks that find the coverage of code use this (such as JSCoverage).
For example, let's say your original call is:
function x() {
1 + 1;
2 + 2;
y();
}
You could write a preprocessor to make it into:
function x() {
var me = arguments.callee;
me.line = 1;
1 + 1;
me.line = 2;
2 + 2;
me.line = 3;
y();
}
Then in y()
, you could use arguments.callee.caller.line
to know the line from which it was called, such as:
function y() {
alert(arguments.callee.caller.line);
}
Upvotes: 3
Reputation:
To determine which line something is on you have to search all the code for the code that occupies the particular line of interest and count the "\n" characters from the top to this of interest and add 1.
I am actually doing this very thing in an application I am writing. It is a best practices validator for HTML and is still heavily under development, but the error output process that you would be interested in is complete.
http://mailmarkup.org/htmlint/htmlint.html
Upvotes: 1
Reputation: 189447
Answers are simple. No and No (No).
By the time javascript is running the concept of source files/urls from which the come is gone.
There is also no way to determine a line number because again by the time of execution the notion of code "lines" is no longer meaningful in Javascript.
Specific implementations may provide API hooks to allow priviledged code access to such details for the purpose of debugging but these APIs are not exposed to ordinary standard Javascript code.
Upvotes: -1