Custom console log function, a console.log wrapper

The only way I've seen to reliably extract this kind of info is to throw an error and then extract the caller info from the stack trace, something along the lines of:

function log( msgOrObj ){
    if(dev_mode){

        try {
            in_val_id(); // force an error by calling an non-existent method
        catch(err) {
            // some regex/string manipulation here to extract function name
            // line num, etc. from err.stack
            var caller = ...
            var lineNo = ...
        }

        console.log({
            'message': msgOrObj,
            'caller': caller,
            'lineNo': lineNo
        });
    }
}

The stack in Chrome is in this form:

ReferenceError: in_val_id is not defined
at log (<anonymous>:4:13)
at <anonymous>:2:14
at <anonymous>:2:28
at Object.InjectedScript._evaluateOn (<anonymous>:581:39)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:540:52)
at Object.InjectedScript.evaluate (<anonymous>:459:21) 

you can extract the function name with:

caller = err.stack.split('\n')[3].split('at ')[1].split(' (')[0];

using a regex here might be more performant. You'll probably need different approaches to extract this info with different browsers.

A word of warning though; throwing and handling errors is expensive so outputting a lot of log messages in this way is likely to impact on general performance, though this may be acceptable if it is specifically for a debug mode


Yes but it's very hacky and not cross browser-safe. You can use this as a starting point. It borrows from this answer.

window.trace = function stackTrace() {
    var err = new Error();
    return err.stack;
}

window.my_log = function (x) {
    var line = trace();
    var lines = line.split("\n");
    console.log(x + " " + lines[2].substring(lines[2].indexOf("("), lines[2].lastIndexOf(")") + 1))
}


window.my_log("What light through yonder window breaks?")

Produces:

What light through yonder window breaks? (<anonymous>:2:42) 

So, this is what I went for in the end (where shout is a bespoke function only running in dev mode):

function log( msgOrObj ){
    if(dev_mode){
        if( typeof(window.console) != 'undefined' ){
            try {  invalidfunctionthrowanerrorplease(); }
            catch(err) {  var logStack = err.stack;  }
            var fullTrace = logStack.split('\n');
            for( var i = 0 ; i < fullTrace.length ; ++i ){
                fullTrace[i] = fullTrace[i].replace(/\s+/g, ' ');
            }
            var caller = fullTrace[1],
                callerParts = caller.split('@'),
                line = '';

            //CHROME & SAFARI
            if( callerParts.length == 1 ){
                callerParts = fullTrace[2].split('('), caller = false;
                //we have an object caller
                if( callerParts.length > 1 ){
                    caller = callerParts[0].replace('at Object.','');
                    line = callerParts[1].split(':');
                    line = line[2];
                }
                //called from outside of an object
                else {
                    callerParts[0] = callerParts[0].replace('at ','');
                    callerParts = callerParts[0].split(':');
                    caller = callerParts[0]+callerParts[1];
                    line = callerParts[2];
                }
            }
            //FIREFOX
            else {
                var callerParts2 = callerParts[1].split(':');
                line = callerParts2.pop();
                callerParts[1] = callerParts2.join(':');
                caller = (callerParts[0] == '') ? callerParts[1] : callerParts[0];
            }
            console.log( ' ' );
            console.warn( 'Console log: '+ caller + ' ( line '+ line +' )' );
            console.log( msgOrObj );
            console.log({'Full trace:': fullTrace });
            console.log( ' ' );
        } else {
            shout('This browser does not support console.log!')
        }
    }
}

log() when declared before the rest of the application can be called anywhere from within the app and give the developer all the information required plus will not run out of dev mode.

(http://webconfiguration.blogspot.co.uk/2013/12/javascript-console-log-wrapper-with.html)