Created
April 18, 2020 03:41
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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