Prometheus Middleware for Node.js HTTP Servers
raw JSON →The `prometheus-middleware` package provides a straightforward solution for integrating Prometheus metrics into Node.js HTTP applications. Currently at version 1.4.2, it appears to maintain an active development cadence given its continuous integration setup and recent releases. It acts as an abstraction layer, setting up an HTTP server to expose metrics, instantiating and exposing a `prom-client` instance, and patching the native Node.js HTTP server to automatically track request-response times. A key differentiator is its out-of-the-box support for popular Node.js HTTP frameworks like Express and Fastify, along with the default Node.js HTTP server. It also includes sensible defaults, such as normalizing 404 error paths to prevent high cardinality issues in Prometheus, and automatically collects metrics for event loop, garbage collection, CPU, and memory usage. Developers can also easily define custom metrics using the underlying `prom-client` instance.
Common errors
error Error [ERR_REQUIRE_ESM]: require() of ES Module ...prometheus-middleware.js not supported. ↓
"type": "module" in package.json), use import APM from 'prometheus-middleware';. If it's CommonJS, use const APM = require('prometheus-middleware');. error TypeError: APM is not a constructor ↓
const APM = require('prometheus-middleware');. For ESM, use import APM from 'prometheus-middleware'; or import { APM } from 'prometheus-middleware';. error metrics_path_label_cardinality_high ↓
prometheus-middleware configuration. The default behavior normalizes 404 paths. If this is not sufficient, consider implementing custom path normalization using a library like express-url-trimmer before prometheus-middleware in your HTTP server's middleware chain, or ensure NORMALIZE_ENDPOINT is not set to false without careful consideration. Warnings
gotcha By default, the middleware normalizes the 'path' label for HTTP 404 responses to avoid high cardinality issues in Prometheus. If your monitoring strategy requires unique path labels for all 404s, you must explicitly set `NORMALIZE_ENDPOINT: false` in the configuration. ↓
breaking The package requires Node.js version 16.0.0 or higher. Running on older Node.js versions will result in startup failures. ↓
gotcha While the documentation states `16.x` is supported, the compatibility table explicitly marks it as 'not tested'. Prioritize Node.js 18.x, 20.x, or 22.x for environments where thorough testing has been performed by the library authors. ↓
Install
npm install prometheus-middleware yarn add prometheus-middleware pnpm add prometheus-middleware Imports
- APM wrong
import { APM } from 'prometheus-middleware'.APM;correctimport APM from 'prometheus-middleware'; // Or for the class itself: import { APM } from 'prometheus-middleware'; - APM (CommonJS)
const APM = require('prometheus-middleware'); - APM.client.Counter
import APM from 'prometheus-middleware'; const apm = new APM(); const counter = new apm.client.Counter({ name: 'my_counter', help: 'A custom counter metric' });
Quickstart
import APM from 'prometheus-middleware';
import http from 'http';
const apm = new APM({
PORT: 9350,
METRICS_ROUTE: '/metrics'
});
apm.init();
// Example of adding a custom metric
const customRequestsCounter = new apm.client.Counter({
name: 'custom_http_requests_total',
help: 'Total number of custom HTTP requests',
labelNames: ['method', 'route', 'code']
});
// Create a simple HTTP server to demonstrate the middleware
const server = http.createServer((req, res) => {
if (req.url === '/test') {
customRequestsCounter.inc({ method: req.method, route: '/test', code: 200 });
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from /test\n');
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found\n');
}
});
server.listen(3000, () => {
console.log('HTTP server listening on port 3000');
console.log('Prometheus metrics available at http://localhost:9350/metrics');
});
// Graceful shutdown to destroy the APM instance and its HTTP server
process.on('SIGTERM', () => {
console.log('SIGTERM received, destroying APM...');
apm.destroy();
server.close(() => {
console.log('HTTP server closed.');
process.exit(0);
});
});