/*! * Connect - profiler * Copyright(c) 2011 TJ Holowaychuk * MIT Licensed */ /** * Profile the duration of a request. * * Typically this middleware should be utilized * _above_ all others, as it proxies the `res.end()` * method, being first allows it to encapsulate all * other middleware. * * Example Output: * * GET / * response time 2ms * memory rss 52.00kb * memory vsize 2.07mb * heap before 3.76mb / 8.15mb * heap after 3.80mb / 8.15mb * * @api public */ module.exports = function profiler(){ return function(req, res, next){ var end = res.end , start = snapshot(); // state snapshot function snapshot() { return { mem: process.memoryUsage() , time: new Date }; } // proxy res.end() res.end = function(data, encoding){ res.end = end; res.end(data, encoding); compare(req, start, snapshot()) }; next(); } }; /** * Compare `start` / `end` snapshots. * * @param {IncomingRequest} req * @param {Object} start * @param {Object} end * @api private */ function compare(req, start, end) { console.log(); row(req.method, req.url); row('response time:', (end.time - start.time) + 'ms'); row('memory rss:', formatBytes(end.mem.rss - start.mem.rss)); row('memory vsize:', formatBytes(end.mem.vsize - start.mem.vsize)); row('heap before:', formatBytes(start.mem.heapUsed) + ' / ' + formatBytes(start.mem.heapTotal)); row('heap after:', formatBytes(end.mem.heapUsed) + ' / ' + formatBytes(end.mem.heapTotal)); console.log(); } /** * Row helper * * @param {String} key * @param {String} val * @api private */ function row(key, val) { console.log(' \033[90m%s\033[0m \033[36m%s\033[0m', key, val); } /** * Format byte-size. * * @param {Number} bytes * @return {String} * @api private */ function formatBytes(bytes) { var kb = 1024 , mb = 1024 * kb , gb = 1024 * mb; if (bytes < kb) return bytes + 'b'; if (bytes < mb) return (bytes / kb).toFixed(2) + 'kb'; if (bytes < gb) return (bytes / mb).toFixed(2) + 'mb'; return (bytes / gb).toFixed(2) + 'gb'; };