Skip to content

Instantly share code, notes, and snippets.

@dt-rush
Created April 18, 2020 03:41
Show Gist options
  • Select an option

  • Save dt-rush/d6cc7127698fd222f670f469fcc4b67d to your computer and use it in GitHub Desktop.

Select an option

Save dt-rush/d6cc7127698fd222f670f469fcc4b67d to your computer and use it in GitHub Desktop.

Revisions

  1. dt-rush created this gist Apr 18, 2020.
    71 changes: 71 additions & 0 deletions request-metrics-gatherer.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    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();