Overriding console.log in JavaScript

#javascript #debugging #stackoverflow

Written by Anders Marzi Tornblad

StackOverflow user unix_root was having trouble replacing console.log with their own function. The goal was to invoke a set of custom tasks whenever console.log was called. Unfortunately, their solution generated Uncaught RangeError: Maximum call stack size exceeded errors, which almost definitely means their function is recursively calling itself infinitely. This might point to a few different root causes.

Only set up once

It might be that the part of the code that sets up the console.log redirection gets called more than once:

// First time:
backupconsolelog = console.log.bind(console);

console.log = function() {
    backupconsolelog.apply(this, arguments);
    /* Do other stuff */
}
// console.log is now redirected correctly

// Second time:
backupconsolelog = console.log.bind(console);
// Congratulations, you now have infinite recursion

To find this type of error, you could add the statement debugger; where the redirection is set up, to see where, and how many times, that code is called. Make sure to only do the setup exactly once!

Beware logging from within the logging

Another reason for the infinite recursion could be that the extra code in the replacement function also calls console.log causing recursion. For example, there might be some function called check that gets called inside the replacement function. This check function then calls console.log, which is now the replacement function, and not the original one. Here, the solution is to always call the stored-away original function:

backupconsolelog = console.log.bind(console);

console.log = function() {
    check();
    backupconsolelog.apply(this, arguments);
}

function check() {
    // This will call your replacement function and cause infinite recursion, so don't do it!
    // console.log('Checked!');

    // Instead call the browser's original implementation:
    backupconsolelog('Checked!');
}

Finding the root cause of stack overrun errors is almost never easy, especially in dynamic languages, where functions can be replaced, and it's not very clear at write-time what function will eventuall get called. I almost always resort to debugging statement by statement until I understand what is going on.