Renaud
Renaud

Reputation: 4668

need reference to the $log.log call line number

When I use angular $log service, all the lines in the console show up with a reference to angular.js:5687 instead of the line where I called the $log.log function.

How can I get a reference to the line where I called $log? Also I have my own service that wraps around $log, how can I reference calls to my service instead of $log?

For example in Logger.js:

 1) angular.module('MyApp').factory('Logger', function($log){
 2)    return { log : function(msg) { $log.log(msg); };
 3) });

And in SomeCtrl.js

 1) angular.module('MyApp').controller('SomeCtrl', function($scope, $log, Logger) {
 ...
10) $log.log('Hi from $log');     // reference to SomeCtrl.js:10
 ...
25) Logger.log('Hi from Logger'); // reference to SomeCtrl.js:25

Upvotes: 2

Views: 1487

Answers (2)

Renaud
Renaud

Reputation: 4668

Credit to @Langdon for pointing me in the right direction.

[NOTE] this solution will only work in Chrome. For more info look at:

Here is the workaround I implemented:

Object.defineProperty(window, '__stack', {
  get : function() {
     var orig = Error.prepareStackTrace;
     Error.prepareStackTrace = function(_, stack) {
        return stack;
     };
     var err = new Error;
     Error.captureStackTrace(err, arguments.callee);
     var stack = err.stack;
     Error.prepareStackTrace = orig;
     return stack;
  }
});

Logger.log = function(msg) {
  var stack = __stack;
  var link = stack[1].getFileName() + ':' + stack[1].getLineNumber();
  console.groupCollapsed("%c" + msg, "font-weight: normal;");
  $log.log(link); // or console.log(link) if you're not using angular.
  console.groupEnd();
};

[NOTE] In the chrome dev tools console I do not know how to overwrite the link that is given on the right. I have looked for documentation about that but I didn't find anything. Please let me if you know if you find out as this would look much neater.

Upvotes: 1

Langdon
Langdon

Reputation: 20073

Since I assume you're logging only in development and, like most developers, you're developing in Chrome, you can add a property to the global scope like so:

via Accessing line number in V8 JavaScript (Chrome & Node.js)

Object.defineProperty(window, '__stack', {
  get: function(){
    var orig = Error.prepareStackTrace;
    Error.prepareStackTrace = function(_, stack){ return stack; };
    var err = new Error;
    Error.captureStackTrace(err, arguments.callee);
    var stack = err.stack;
    Error.prepareStackTrace = orig;
    return stack;
  }
});

Object.defineProperty(window, '__line', {
  get: function(){
    return __stack[1].getLineNumber();
  }
});

console.log(__line);

And now you can use __line anywhere in your code.

Edit: It doesn't look like you can get the filename from the call stack. If you're writing clean JavaScript, each file should have its own scope in which you could define var filename = 'test.js';, so your could look like:

Defined globally somewhere:

Object.defineProperty(window, '__prevLine', {
    get: function () {
        console.log('__line', __stack);
        return __stack[2].getLineNumber();
    }
});

function log(s) {
    console.log(s, __prevLine)
}

And your implementation:

(function () {
    var _scriptName = 'test.js';

    // ... lots of code

    log('something happened', _scriptName);
}());

Here's a fiddle that demonstrates the idea:

http://jsfiddle.net/langdonx/zJJ8r/

Upvotes: 1

Related Questions