Skip to content

Instantly share code, notes, and snippets.

@dt-rush
Created April 18, 2020 03:41
Show Gist options
  • Save dt-rush/d6cc7127698fd222f670f469fcc4b67d to your computer and use it in GitHub Desktop.
Save dt-rush/d6cc7127698fd222f670f469fcc4b67d to your computer and use it in GitHub Desktop.
Simple express HTTP API request metrics gathering, demonstrating how `req.connection.bytesRead` is weird
const express = require('express');
const bodyParser = require('body-parser');
const onFinished = require('on-finished');
// it may be necessary to modify the request object in various ways, this can
// be done in this function. For example, a `_metrics_gatherer` object is
// added to req and req.connection for the purposes of metrics observing functions
const modifyReq = (req) => {
req._metrics_gatherer = {};
if (!req.connection._metrics_gatherer) {
req.connection._metrics_gatherer = {};
}
}
// A specific sequence of steps is used to keep track of the changing values of
// req.connection.bytesRead and req.connection.bytesWritten
//
// These two quantities are observed when the request arrives and when it
// has finished to subtract the difference, rather than simply observing them
// when the request has finished, because the net.Socket objects (as
// `.connection` on Request objects) are re-used by express, and so
// connection.bytesRead will, at the very start of the request, give us the
// bytesRead/bytesWritten by the last request to use the same net.Socket object.
const observeBytesRW = (req, res) => {
const bytesReadPreviously = req.connection._metrics_gatherer.bytesRead || 0;
const bytesWrittenPreviously = req.connection._metrics_gatherer.bytesWritten || 0;
return () => {
const bytesReadDelta = req.connection.bytesRead - bytesReadPreviously;
const bytesWrittenDelta = req.connection.bytesWritten - bytesWrittenPreviously;
req.connection._metrics_gatherer.bytesRead = req.connection.bytesRead;
req.connection._metrics_gatherer.bytesWritten = req.connection.bytesWritten;
console.log(`bytesReadDelta: ${bytesReadDelta}`);
console.log(`bytesWrittenDelta: ${bytesWrittenDelta}`);
};
};
// observe the request latency using process.hrtime
const observeLatency = (req, res) => {
const t0 = process.hrtime();
return () => {
const t1 = process.hrtime();
const dt = (t1[0] - t0[0]) + (t1[1] - t0[1]) / 1e6;
console.log(`dt: ${dt}`);
};
};
// attach a middleware to all requests to observe various metrics
const metricsMiddleware = (req, res, next) => {
modifyReq(req);
const onFinishFuncs = [
observeBytesRW(req, res),
observeLatency(req, res)
];
onFinished(res, () => {
onFinishFuncs.forEach(f => f());
});
next();
};
const server = () => {
const app = express();
app.use(bodyParser.json());
app.use(metricsMiddleware)
app.all('*', (req, res) => {
res.send(req.body);
});
const server = app.listen(process.env.PORT || 3001);
console.log(`listening on ${process.env.PORT || 3001}`);
};
server();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment