3

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.

1

6 Answers 6

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.

Sign up to request clarification or add additional context in comments.

9 Comments

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?
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 <script> tag, so it doesn't give you any more headaches.
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?
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.
That worked. :) This helped to understand. Thanks.
|
4
// 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");

7 Comments

Still I get "Uncaught RangeError: Maximum call stack size exceeded." error. :/
RaraituL's solution works! You are probably setting up your call redirection more than once. Read my answer too.
Yes, I did this, but the error happens at the point where I've used console.log(displaySomeDataInConsole); in the .js file.
Should I use _log(displaySomeDataInConsole); in the .js file?
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?
|
2

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 }));

Comments

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)
}

5 Comments

What does this mean: "console.log = (...args) => "
() => {} is an arrow function. more ...args is spread operator, that allows use to get all arguments as an array. more Works similary to function () {var args = [].slice.call(arguments)}. Useful for variadic functions like console.log().
Is this JS? Using this causes Multiple markers at this line - Syntax error on token ">", invalid FunctionExpressionHeader - Syntax error on tokens, CallExpression expected instead
Yes, it's ES6 aka ES2015. What environment are you using? Anyway, if its a production code thats supposed to run in a browser context and you want to use es6 syntax, you should probably use a transpiler, eg. Babel. Most of ES6 syntax works in newer nodejs versions. Otherwise you can just stick to ES5.
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. :)
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);
};

2 Comments

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 Okay, I see. now I already deleted the other answer that likes this post
0

The accepted answers will work with the provided structure EXCEPT in cases where you will need to "setup" the override multiple times on a running instance for example. If you have a live container, or a lambda function, you run the risk of the arguments array building up upon itself.

[ arg1 ] -> [ [arg1] , arg2 ] -> [ [ [ arg1 ] , arg2] , arg3 ] 

Ex:

function x(){
  var log = console.log;
  console.log = function () {
        var args = Array.from(arguments);
        args.push('post fix');
        log.apply(console, args);
    }
}

new x()
console.log(1)
new x()
console.log(2)

OUTPUTS:
1 post fix
2 post fix post fix

SOLUTIONS:

Make sure if you need to use this function as middleware for example, you maintain the reference outside of the middleware function like:

var log = console.log;
function x(){
  console.log = function () {
        var args = Array.from(arguments);
        args.push('post fix');
        log.apply(console, args);
    }
}

new x()
console.log(1)
new x()
console.log(2)

OUTPUTS: 
1 post fix
2 post fix

OR better yet...

const log = console.log;
function middleWare() {
    console.log = (...args) => {
        log(...args, 'post fix');
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.