Source: nodeHttpRequestMetrics.js

const { Stopwatch } = require('measured-core');

/**
 * The default reporting interval for requests
 * @type {number}
 */
const DEFAULT_REQUEST_METRICS_REPORTING_INTERVAL_IN_SECONDS = 10;

/**
 * This module has functions needed to create middlewares for frameworks such as express and koa.
 * It also exports the 2 functions needed to implement your own middleware.
 * If you implement a middleware for a framework not implemented here, please contribute it back.
 *
 * @module node-http-request-metrics
 */
module.exports = {
  /**
   * Creates an Express middleware that reports a timer on request data.
   * With this middleware you will get requests counts and latency percentiles all filterable by status codes, http method, and uri paths.
   *
   * @param {SelfReportingMetricsRegistry} metricsRegistry
   * @param {number} [reportingIntervalInSeconds]
   * @return {Function}
   */
  createExpressMiddleware: (metricsRegistry, reportingIntervalInSeconds) => {
    return (req, res, next) => {
      const stopwatch = module.exports.onRequestStart();

      res.on('finish', () => {
        const { method } = req;
        const { statusCode } = res;
        const uri = req.route ? req.route.path : '_unknown';
        module.exports.onRequestEnd(metricsRegistry, stopwatch, method, statusCode, uri, reportingIntervalInSeconds);
      });

      next();
    };
  },

  /**
   * Creates a Koa middleware that reports a timer on request data.
   * With this middleware you will get requests counts and latency percentiles all filterable by status codes, http method, and uri paths.
   *
   * @param {SelfReportingMetricsRegistry} metricsRegistry
   * @param {number} [reportingIntervalInSeconds]
   * @return {Function}
   */
  createKoaMiddleware: (metricsRegistry, reportingIntervalInSeconds) => async (ctx, next) => {
    const stopwatch = module.exports.onRequestStart();
    const { req, res } = ctx;

    res.once('finish', () => {
      const { method } = req;
      const { statusCode } = res;
      const uri = ctx._matchedRoute || '_unknown';
      module.exports.onRequestEnd(metricsRegistry, stopwatch, method, statusCode, uri, reportingIntervalInSeconds);
    });

    await next();
  },

  /**
   * At the start of the request, create a stopwatch, that starts tracking how long the request is taking.
   * @return {Stopwatch}
   */
  onRequestStart: () => {
    return new Stopwatch();
  },

  /**
   * When the request ends stop the stop watch and create or update the timer for requests that tracked by method, status code, path.
   * The timers (meters and histograms) that get reported will be filterable by status codes, http method, the uri path.
   * You will be able to create dash boards such as success percentage, latency percentiles by uri path and method, etc.
   *
   * @param {SelfReportingMetricsRegistry} metricsRegistry The Self Reporting Metrics Registry
   * @param {Stopwatch} stopwatch The stopwatch created by onRequestStart
   * @param {string} method The Http Method for the request
   * @param {string|number} statusCode The status code for the response
   * @param {string} [uri] The uri path for the request. Please note to avoid out of control time series dimension creation spread,
   * you would want to strip out ids and or other variables from the uri path.
   * @param {number} [reportingIntervalInSeconds] override the reporting interval defaults to every 10 seconds.
   */
  onRequestEnd: (metricsRegistry, stopwatch, method, statusCode, uri, reportingIntervalInSeconds) => {
    reportingIntervalInSeconds = reportingIntervalInSeconds || DEFAULT_REQUEST_METRICS_REPORTING_INTERVAL_IN_SECONDS;

    const customDimensions = {
      statusCode: `${statusCode}`,
      method: `${method}`
    };

    if (uri) {
      customDimensions.uri = uri;
    }

    // get or create the timer for the request count/latency timer
    const requestTimer = metricsRegistry.getOrCreateTimer('requests', customDimensions, reportingIntervalInSeconds);

    // stop the request latency counter
    const time = stopwatch.end();
    requestTimer.update(time);
  }
};