verstappen_doodle
verstappen_doodle

Reputation: 549

Override console.log in JavaScript

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.

Upvotes: 3

Views: 7455

Answers (6)

Vontei
Vontei

Reputation: 1897

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

Upvotes: 0

Chinnawat Sirima
Chinnawat Sirima

Reputation: 410

This works for me.

let originalConsole = Object.assign({}, console);
console.log = (value) => {
    //some cool condition
    if (true) {
        value = "new_log : " + value
    }
    originalConsole.log(value);
};

Upvotes: 0

Griffin
Griffin

Reputation: 851

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

Upvotes: 2

Anders Marzi Tornblad
Anders Marzi Tornblad

Reputation: 19305

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.

Upvotes: 5

Kuba Kutiak
Kuba Kutiak

Reputation: 92

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

Upvotes: 0

Catalin
Catalin

Reputation: 11721

// 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");

Upvotes: 4

Related Questions