This question is related to Express under Node.js.
Background
With Express, you stack up several "middleware" modules to handle a specific HTTP request.
app.use(express.logger());
app.use(express.favicon()));
app.use(express.cookieParser());
app.use(express.session());
app.use(app.router);
When a request comes in, Express goes through all of the functions in the stack until a module handles the request. Specifically, each middleware module is a function (req, res, next)
, and that function will call next()
to call the next module in the stack. Functions can modify data in the req
or res
objects if they choose.
The Problem
I was interested in making custom log middleware modules for my Express application, and I needed to use more than one module at a time. The data I need to log cannot be logged until the response has been sent to the client. (I am tracking bytes sent, and the amount of time a connection was established.) Unfortunately, Node.js's HTTP response object does not raise an end
event. Presumably, this is because it is up to the application to do any "end" work prior to calling .end()
on the response object in the first place. Express does not expose a hook prior to .end()
being called.
Express/Connect's built-in logger middleware is able to track how long a request was running, so I decided to see what method they use. They actually replace the res.end
function with their own. When their own res.end
function is called, it swaps the old res.end
back in place, finishes logging, then calls res.end
with the parameters that their own res.end
was called with. Their method works, but can be problematic when a handful of modules try to do this. (The order in which res.end
function replacement occurs becomes critical.)
My Solution
I have used their method to patch res
to fire end
events so that any module in the chain can subscribe to that event in the usual way.
function (req, res, next) {
var end = res.end;
res.end = function () {
res.end = end;
res.emit('end');
res.end.apply(this, arguments);
}
next();
}
Then, all my logger module has to do is:
res.on('end', function () { /* log here */ });
Is there any problem with what I have done? Is there a better way to do it?