Last active
June 6, 2023 13:18
-
-
Save i-like-robots/ffce87d7330e51474b31fa0f0dec32a3 to your computer and use it in GitHub Desktop.
Instrument Node.js HTTP requests
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
// Based on <https://blog.bearer.sh/http-api-instrumentation-nodejs/> | |
const http = require('http') | |
const https = require('https') | |
const { URL } = require('url') | |
const Metrics = require('metrics') | |
const { performance } = require('perf_hooks') | |
const metrics = {} | |
const metricTypes = { | |
counter: () => new Metrics.Counter(), | |
histogram: () => Metrics.Histogram.createUniformHistogram(), | |
} | |
function getServiceName(url) { | |
const { host } = new URL(url) | |
return host.replace(/\./g, '-') | |
} | |
function getMetric(url, type, key) { | |
const service = getServiceName(url) | |
metrics[service] ??= {} | |
metrics[service][key] ??= metricTypes[type]() | |
return metrics[service][key] | |
} | |
function patchModule(module) { | |
const original = module.request | |
function newRequest(outgoing) { | |
// Using perf.now() instead of Date.now() not because we need the resolution | |
// but because we can avoid being bound to the system's time and its quirks. | |
const startTime = performance.now() | |
const request = original.apply(this, arguments) | |
const { emit } = request | |
request.emit = function (event, response) { | |
if (event === 'response') { | |
response.on('end', () => { | |
const endTime = performance.now() | |
const { statusCode } = response | |
const time = Math.ceil(endTime - startTime) | |
const host = outgoing.host || outgoing.hostname | |
getMetric(host, 'counter', `status_${statusCode}.count`).inc(1) | |
getMetric(host, 'histogram', `status_${statusCode}.response_time`).update(time) | |
}) | |
} | |
return emit.apply(this, arguments) | |
} | |
return request | |
} | |
module.request = newRequest | |
} | |
function instrumentRequests() { | |
patchModule(http) | |
patchModule(https) | |
} | |
module.exports = instrumentRequests |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment