Here's something typical resulting from using $log
:
If I would just use console.log
, I would see the source code location of my call in the console. When using $log
, I see the location of their log call, which is useless to me.
Is there any way to get a more useful result?
We just dropped using $log
completely. It really doesn't provide any benefit that we could see.
Instead, we're now simply using console
, but with a small twist:
/**
* @see https://github.com/h5bp/html5-boilerplate/blob/master/src/js/plugins.js
*/
var method;
var methods = [
"assert", "clear", "count", "debug", "dir", "dirxml", "error",
"exception", "group", "groupCollapsed", "groupEnd", "info", "log",
"markTimeline", "profile", "profileEnd", "table", "time", "timeEnd",
"timeStamp", "trace", "warn"
];
var methodsLength = methods.length;
var console = ( window.console || {} );
while( methodsLength-- ) {
method = methods[ methodsLength ];
// Only stub undefined methods.
if( !console[ method ] ) {
console[ method ] = Function.prototype;
}
}
angular
.module( "util" )
.constant( "console", console );
We're not overriding window.console
as the original html5-boilerplate code does. Instead, we're just creating a new service and inject that whenever we want to use console
.
I'm not quite sure if this is where I want to go with the issue, but @BenjaminGruenbaum suggested to just use decorators and change how $log
works.
This is what it looks like. And Chrome apparently even recognizes the pattern and I can click right through to the source code location.
So here is my proof-of-concept code:
var app = angular.module( "myApp", []);
app.config( function( $provide ) {
$provide.decorator( "$log", function( $delegate ) {
var originalLog = $delegate.log;
$delegate.log = function() {
var stack = new Error().stack;
var location = analyzeStack( stack, 1 );
[].push.call( arguments, location );
originalLog.apply( this, arguments );
};
return $delegate;
} );
} );
app.controller( "ApplicationController", function( $log ) {
$log.log( "Hello World" );
} );
/**
* Take a stack trace and extract a location identifier from it.
* The location identifier represents the location from where the logger was invoked.
* @param {String} stack The traced stack
* @param {Number} [stackIndex=2] The element of the stack you want analyzed.
* @returns {String} A location identifier for the location from where the logger was invoked.
*/
function analyzeStack( stack, stackIndex ) {
stackIndex = stackIndex || 2;
/**
* Group 1: Function name (optional)
* Group 2: File name
* Group 3: Line
* Group 4: Column
*/
var callSitePattern = new RegExp( /at (?:(.*) )?\(?(.*):(\d+):(\d+)\)?/g );
var sites = stack.match( callSitePattern );
// The method that invoked the logger is located at index 2 of the stack
if( sites && stackIndex <= sites.length ) {
var callSiteElementPattern = new RegExp( /at (?:(.*) )?\(?(.*):(\d+):(\d+)\)?/ );
// Pick apart
var callSiteElements = sites[ stackIndex ].match( callSiteElementPattern );
var functionName, fileName, line, column;
// Assume either 4 (no function name) or 5 elements.
if( callSiteElements.length == 5 ) {
functionName = callSiteElements[ 1 ];
fileName = callSiteElements[ 2 ];
line = callSiteElements[ 3 ];
column = callSiteElements[ 4 ];
} else {
functionName = "(unnamed)";
fileName = callSiteElements[ 1 ];
line = callSiteElements[ 2 ];
column = callSiteElements[ 3 ];
}
return functionName + "@" + fileName + ":" + line + ":" + column;
}
return null;
};
I've also put it into a plunkr.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With