Override console.log (or any function in general): Is there a proper way to do this?

2.8k Views Asked by At

I find myself doing this quite often both on the browser and in node.js and it's about time I came up with a proper way to do this without debugging it for a while each time.

Here's what I'm currently working on (this is node.js):

var log4js = require("log4js");

log4js.loadAppender('file');
log4js.addAppender(log4js.appenders.file('log.log'));
var logger = log4js.getLogger();
console.log = function () {
    logger.debug.apply(logger, Array.prototype.slice.call(arguments));
};

This is basically a monkey patch to take console.logging code and turn it into proper logging code.

I'm not sure if this is something proper or completely asinine.

Conceptually, I am forcing arguments sent to console.log into an array, which then is passed to apply. All of this is to work around the fact that I don't know how to declare a variadic function in JS. (perhaps this is the canonical way to do so).

Perhaps the same can be achieved with console.log = logger.debug. Oh well, I want to know how I can pass the arguments.

For instance, there are certain things of this sort that won't work for whatever reason in the browser (but does in node):

var l = console.log;
l('hello');

enter image description here

Granted, this is not the same as overriding console.log, this is just to shorten the name of it, but still.

Ah, I actually realized what's wrong here: This will work.

l.call(console, 'hello');

Which means it's just missing a bit of finagling with this.

If you are still looking for the actual question of this question look at the italicized line above.

1

There are 1 best solutions below

0
On

I'm not sure if this is something proper or completely asinine.

For your own projects, it should be fine. Though, I would probably refrain from modifying Node's documented API (beyond the few parts that suggest modification) for any projects you intend to distribute on NPM.


Currently, .apply() is the only way to specify a collection as the arguments to a function call.

logger.debug.apply(logger, Array.prototype.slice.call(arguments));

Though, ECMAScript 6 will be introducing the spread operator as an alternative.

logger.debug(...arguments);

However, the slice probably isn't necessary, since it isn't modifying the collection before passing it.

logger.debug.apply(logger, arguments);

As for l('hello'), you can use .bind() to ensure the context.

var l = console.log.bind(console);
l('hello');

Though, this does depend on what version of a particular engine you're using. With Node 0.10.15 and Chrome 28, console.log is already bound to console. So, the snippet you listed wouldn't throw an error.