In Node.js is there any way to listen to all events emitted by an EventEmitter object?
e.g., can you do something like...
event_emitter.on(\
Since Node.js v6.0.0, the new class
syntax and argument spread operator is fully supported, so it's pretty safe and fairly easy to implement the desired functionality with simple inheritance and an method override:
'use strict';
var EventEmitter = require('events');
class MyEmitter extends EventEmitter {
emit(type, ...args) {
super.emit('*', ...args);
return super.emit(type, ...args) || super.emit('', ...args);
}
}
This implementation relies on the fact that the original emit
method of the EventEmitter
returns true
/false
depending if the event was handled by some listener or not. Notice that the override includes a return
statement, so we keep this behavior for other consumers.
Here the idea is to use the star event (*
) to create handlers that gets executed on every single event (say, for logging purposes) and the empty event (''
) for a default or catch all handler, that gets executed if nothing else catches that event.
We make sure to call the star (*
) event first, because in case of error
events without any handlers, the result is actually an exception being thrown. For more details, take a look at the implementation of the EventEmitter.
For example:
var emitter = new MyEmitter();
emitter.on('foo', () => console.log('foo event triggered'));
emitter.on('*', () => console.log('star event triggered'));
emitter.on('', () => console.log('catch all event triggered'));
emitter.emit('foo');
// Prints:
// star event triggered
// foo event triggered
emitter.emit('bar');
// Prints:
// star event triggered
// catch all event triggered
Finally, if an EventEmitter instance already exists but you want to adjust that specific instance to the new behavior, it can be easily done by patching the method at runtime like this:
emitter.emit = MyEmitter.prototype.emit;
You can also use another event emitter implementation like https://github.com/ozantunca/DispatcherJS. The implementation would be like:
dispatcher.on('*', function () {});
DispatcherJS also supports namespaces and even dependencies to determine which callbacks are going to be called first.
Be aware that all solutions described above will involve some sort of hacking around node.js EventEmitter internal implementation.
The right answer to this question would be: the default EventEmitter implementation does not support that, you need to hack around it.
If you take a look on node.js source code for EventEmitter, you can see listeners are retrieved from a hash using event type as a key, and it will just return without any further action if the key is not found:
https://github.com/nodejs/node/blob/98819dfa5853d7c8355d70aa1aa7783677c391e5/lib/events.js#L176-L179
That's why something like eventEmitter.on('*', ()=>...)
can't work by default.
This is based on the answer that Martin provided above. I'm a bit new to node, so I needed to work out his answer for myself. The method at the end, logAllEmitterEvents is the important bit.
var events = require('events');
var hungryAnimalEventEmitter = new events.EventEmitter();
function emitHungryAnimalEvents()
{
hungryAnimalEventEmitter.emit("HungryCat");
hungryAnimalEventEmitter.emit("HungryDog");
hungryAnimalEventEmitter.emit("Fed");
}
var meow = function meow()
{
console.log('meow meow meow');
}
hungryAnimalEventEmitter.on('HungryCat', meow);
logAllEmitterEvents(hungryAnimalEventEmitter);
emitHungryAnimalEvents();
function logAllEmitterEvents(eventEmitter)
{
var emitToLog = eventEmitter.emit;
eventEmitter.emit = function () {
var event = arguments[0];
console.log("event emitted: " + event);
emitToLog.apply(eventEmitter, arguments);
}
}
Here's a debug tool inspired by Martin's answer (https://stackoverflow.com/a/18087021/1264797). I just now used this to figure out what was going wrong in a set of streams by logging all of their events to the console. Works great. As Martin illustrates, OP could use it by replacing the console.log() call with a websocket sender.
function debug_emitter(emitter, name) {
var orig_emit = emitter.emit;
emitter.emit = function() {
var emitArgs = arguments;
console.log("emitter " + name + " " + util.inspect(emitArgs));
orig_emit.apply(emitter, arguments);
}
}
With ES6 classes it's very easy:
class Emitter extends require('events') {
emit(type, ...args) {
console.log(type + " emitted")
super.emit(type, ...args)
}
}