2

I want to override console.log method to invoke a set of tasks whenever console.log is called. I referred other Stackoverflow answers but that give me the error:

Uncaught RangeError: Maximum call stack size exceeded.

This is what I want to do:

backupconsolelog = console.log;

console.log = function(arguments)
{
    //do my tasks;

    backupconsolelog(arguments);
}

Update 1: Somehow managed to over-ride console.log successfully, but I'm now unable to execute console.log(displaySomethingInConsole) in the same .js file where over-riding is done. This somehow causes recursive call to console.log, and gives again Uncaught RangeError: Maximum call stack size exceeded.

How do I use console.log() in the same .js file?

Update 2: I've have a check() function which is called by over-rided console.log. But, there was a console.log call inside the check() function which caused Maximum call stack size exceeded. error.

Update 3: Error again! :(

Uncaught TypeError: Illegal invocation

var _log = window.console.log;
window.console.log = function () {
_log.apply(this, arguments);
check();
};

_log("aaa");
check() {};

Update 4: Binding console to _log, i.e., console.log.bind(console) cleared it.

Community
  • 1
  • 1
unix_root
  • 479
  • 6
  • 18

5 Answers5

5

If you get a Maximum call stack size exceeded error, it almost definitely means your function is recursively calling itself infinitely. The solution you have found, and the one RaraituL has shown, should work perfectly. You are probably calling the part of your code that sets up the call redirection 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;
// Congratulations, you now have infinite recursion

You could add some debugging information (not using console.log, obviously, try debugger; instead to create an automatic breakpoint) where you set up the redirection to see where and when your code is called.

UPDATE

This might belong in a comment: Your console.log redirection function calls some function called check, apparently. This check function then calls console.log, which if your function - not the original one. Have the check function call the original implementation instead.

backupconsolelog = console.log.bind(console);

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

function check() {
    // This will call your function above, so don't do it!
    console.log('Foo');

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

UPDATE 2

The inner workings of the brower's console.log implementation may or may not depend on the console being set for the this reference. Because of this, you should store console.log bound to console, like in my code.

Community
  • 1
  • 1
Anders Marzi Tornblad
  • 17,122
  • 9
  • 50
  • 62
  • Got it! I have used some other console.log() messages in the same .js file where I have over-rided the console.log() method, thus causing recursive call. But, if I need to display something in the console from the same .js file(where over-riding is done), how can I do it? – unix_root Feb 22 '16 at 09:03
  • No, from what I can understand, that shouldn't cause a recursive call. Try editing your question to include more of the code that is giving you problems. RaraituL's solution *(and mine)* **does** work as long as you are only calling it once. Move that little piece of code to another ` – Anders Marzi Tornblad Feb 22 '16 at 09:07
  • check() is my own function which is being called from console.log over-rided function. But, inside check(), I have used console.log() again. Is this the issue? – unix_root Feb 22 '16 at 09:10
  • Yes! So much yes!! `console.log` is now **your** function, which calls `check()`, which calls `console.log`, which is **your** function, which calls `check()`, and so on... Make `check` call `backupconsolelog()` instead. – Anders Marzi Tornblad Feb 22 '16 at 09:13
  • Next time on Stack Overflow, include more code *(and the **actual** code)* in your question. If the call to `check()` were included in your original question, someone would have asked what was going on inside the `check` function. – Anders Marzi Tornblad Feb 22 '16 at 09:17
  • Can you please look into Update 3? – unix_root Feb 22 '16 at 09:33
  • Yes, you are calling `_log` directly, which makes the `this` reference undefined. Do this instead *(as in my code)*: `var _log = console.log.bind(console);` to store the function original reference. – Anders Marzi Tornblad Feb 22 '16 at 09:37
  • 1
    That worked. :) [This](https://stackoverflow.com/a/28668819/5132413) helped to understand. Thanks. – unix_root Feb 22 '16 at 09:45
  • Couldn't you use `backupconsolelog.apply(console, arguments);` instead of binding? – mbomb007 Jun 26 '18 at 19:16
3
// keep reference to original function
var _log = window.console.log;

// overwrite function
window.console.log = function () {
    _log.apply(this, arguments);
    alert(arguments);
};

console.log("hello world");
Catalin
  • 10,580
  • 15
  • 68
  • 134
  • Still I get "Uncaught RangeError: Maximum call stack size exceeded." error. :/ – unix_root Feb 22 '16 at 07:42
  • RaraituL's solution works! You are probably setting up your call redirection more than once. Read my answer too. – Anders Marzi Tornblad Feb 22 '16 at 07:52
  • Yes, I did this, but the error happens at the point where I've used console.log(displaySomeDataInConsole); in the .js file. – unix_root Feb 22 '16 at 08:46
  • Should I use _log(displaySomeDataInConsole); in the .js file? – unix_root Feb 22 '16 at 08:49
  • Got it! I have used some other console.log() messages in the same .js file where I have over-rided the console.log() method, thus causing recursive call. But, if I need to display something in the console from the same .js file(where over-riding is done), how can I do it? – unix_root Feb 22 '16 at 09:03
  • By applying the original `log` function on your overwrite, the console output will work just like before. – Catalin Feb 22 '16 at 09:06
  • Actually, using console.log inside my custom function check() which is already invoked by over-rided console.log() is the issue. Using _log cleared it. Thanks. – unix_root Feb 22 '16 at 09:20
0

You probably need to bind original method to console:

var old = console.log.bind(console)
console.log = (...args) => {
  // perform task
  alert('test')
  old.apply(null, args)
}
Kuba Kutiak
  • 92
  • 1
  • 3
  • What does this mean: _"console.log = (...args) => "_ – unix_root Feb 22 '16 at 09:05
  • () => {} is an arrow function. [more](http://www.2ality.com/2012/04/arrow-functions.html) ...args is spread operator, that allows use to get all arguments as an array. [more](http://www.2ality.com/2015/01/es6-destructuring.html) Works similary to function () {var args = [].slice.call(arguments)}. Useful for variadic functions like console.log(). – Kuba Kutiak Feb 22 '16 at 09:31
  • Is this JS? Using this causes `Multiple markers at this line - Syntax error on token ">", invalid FunctionExpressionHeader - Syntax error on tokens, CallExpression expected instead` – unix_root Feb 22 '16 at 09:57
  • Yes, it's ES6 aka ES2015. What environment are you using? Anyway, if it`s a production code that`s supposed to run in a browser context and you want to use es6 syntax, you should probably use a transpiler, eg. [Babel](https://babeljs.io/). Most of ES6 syntax works in newer nodejs versions. Otherwise you can just stick to ES5. – Kuba Kutiak Feb 22 '16 at 10:19
  • Yeah, I use Eclipse, and the code is supposed to run in browser (client side). Yet to learn about Babel and ES2015, thanks for the info. :) – unix_root Feb 22 '16 at 10:53
0

After some problems, I managed to get console.log replacement with winston + express to work.

I use winston-sugar as it makes configuration easier but anything should work. (.config/winston.json is created when you do npm install winston-sugar) People wanting to replace console.log with something else can just look at the last 5 lines as it gives very clean code.

I think this is a very neat way to get express logged into files along with console.log

const morgan = require('morgan');
const winstonLoader = require('winston-sugar');
winstonLoader.config('./config/winston.json');
const log = winstonLoader.getLogger('app');
log.stream = {
  write: function (message, encoding) {
    log.info(message);
  },
};

// Add some lines indicating that the program started to track restarts.
log.info('----------------------------------');
log.info('--');
log.info('-- Starting program');
log.info('--');
log.info('----------------------------------');

console.log = (...args) => log.info(...args);
console.info = (...args) => log.info(...args);
console.warn = (...args) => log.warn(...args);
console.error = (...args) => log.error(...args);
console.debug = (...args) => log.debug(...args);

And later in the code if you are running express.

// app.use(morgan('combined')); //replaced with the next line to get morgan logs into the winston logfiles.
app.use(morgan('combined', { stream: log.stream }));
Griffin
  • 407
  • 2
  • 7
0

This works for me.

let originalConsole = Object.assign({}, console);
console.log = (value) => {
    //some cool condition
    if (true) {
        value = "new_log : " + value
    }
    originalConsole.log(value);
};
  • Please do not post the exact same answer to multiple questions. If you feel like the question all are asking for the same thing, flag to close them as duplicates of each other. – Bergi Oct 19 '20 at 05:36
  • @Bergi Okay, I see. now I already deleted the other answer that likes this post – Chinnawat Sirima Oct 19 '20 at 06:33