Skip to main content

@map-colonies/prometheus

Overview

This package provides Express middleware for integrating Prometheus metrics into Node.js applications, making it easy to collect and expose application and request metrics.

Built on top of express-prom-bundle and prom-client, this package provides a simplified, opinionated configuration for MapColonies services.

Installation

npm install @map-colonies/prometheus prom-client

or

pnpm add @map-colonies/prometheus prom-client

[!NOTE] prom-client is a peer dependency and must be installed alongside this package.

Usage

Basic Setup

The simplest way to get started is to use both the metrics collection and endpoint middlewares:

import { collectMetricsExpressMiddleware, metricsMiddleware } from '@map-colonies/prometheus';
import express from 'express';
import { Registry } from 'prom-client';

const app = express();
const registry = new Registry();

// Collect metrics from all requests
app.use(collectMetricsExpressMiddleware({ registry }));

// Expose metrics at /metrics endpoint
app.get('/metrics', metricsMiddleware(registry));

// Your application routes
app.get('/', (req, res) => {
res.json({ status: 'ok' });
});

app.listen(8080, () => console.log('Server listening on port 8080'));

Collect Metrics Middleware

The collectMetricsExpressMiddleware automatically measures request duration and counts, optionally collecting Node.js runtime metrics and service version information.

import { collectMetricsExpressMiddleware } from '@map-colonies/prometheus';
import express from 'express';
import { Registry } from 'prom-client';

const app = express();

const metricsMiddleware = collectMetricsExpressMiddleware({
registry: new Registry(),
labels: { environment: 'production', team: 'platform' },
collectNodeMetrics: true,
collectServiceVersion: true
});

app.use(metricsMiddleware);

Metrics Endpoint Middleware

The metricsMiddleware provides a simple handler to expose collected metrics:

import { metricsMiddleware } from '@map-colonies/prometheus';
import { Registry } from 'prom-client';

const registry = new Registry();

// Use as a route handler (with default metrics collection)
app.get('/metrics', metricsMiddleware(registry));

// Or disable default metrics collection at the endpoint
app.get('/metrics', metricsMiddleware(registry, false));

// Or add labels to default metrics
app.get('/metrics', metricsMiddleware(registry, true, { environment: 'production' }));

Configuration Options

collectMetricsExpressMiddleware(options)

OptionTypeRequiredDefaultDescription
registryRegistryYes-The Prometheus registry to use for metrics
collectNodeMetricsbooleanNotrueWhether to collect Node.js runtime metrics (CPU, memory, event loop, etc.)
collectServiceVersionbooleanNotrueWhether to collect service version metrics from package.json
includeOperationIdbooleanNotrueAdd operation ID based on OpenAPI operationId to the metrics
labelsRecord<string, string>No{}Additional static labels to attach to all metrics
customLabelsobjectNoundefinedObject containing extra labels, useful together with transformLabels
transformLabelsfunctionNoundefinedFunction to transform labels with request and response objects

[!NOTE] If you are not running the express-openapi-validator middleware, it's recommended to turn off the includeOperationId option as the operation label will always be null.

metricsMiddleware(registry, shouldCollectDefaultMetrics?, defaultMetricsLabels?)

ParameterTypeRequiredDefaultDescription
registryRegistryYes-The Prometheus registry containing the metrics to expose
shouldCollectDefaultMetricsbooleanNotrueWhether to collect Node.js default metrics when exposing the endpoint
defaultMetricsLabelsRecord<string, string>NoundefinedLabels to add to the default metrics

Default Labels

The middleware automatically adds the following labels to all metrics:

  • hostname: The system hostname (from os.hostname())
  • service_name: The service name from package.json

Additional labels can be provided via the labels option.

Collected Metrics

The middleware automatically collects the following metrics:

Request Metrics

  • http_request_duration_seconds (Histogram): Time taken to process requests, labeled by:
    • method: HTTP method (GET, POST, etc.)
    • status_code: HTTP response status code
    • operation: OpenAPI operation ID (if includeOperationId is enabled and express-openapi-validator is used)

Node.js Runtime Metrics

When collectNodeMetrics is enabled, the following metrics are collected:

  • Process CPU usage
  • Process memory usage (heap, external, RSS)
  • Event loop lag
  • Active handles and requests
  • Garbage collection statistics

Service Information

When collectServiceVersion is enabled:

  • service_version (Gauge): Service version information from package.json, labeled by:
    • service_version_major: Major version number
    • service_version_minor: Minor version number
    • service_version_patch: Patch version number
    • service_version_prerelease: Prerelease version (if applicable)

Advanced Examples

Custom Labels

import { collectMetricsExpressMiddleware } from '@map-colonies/prometheus';
import { Registry } from 'prom-client';

const registry = new Registry();

const middleware = collectMetricsExpressMiddleware({
registry,
labels: {
environment: process.env.NODE_ENV || 'development',
region: process.env.AWS_REGION || 'us-east-1',
version: process.env.APP_VERSION || '1.0.0'
}
});

app.use(middleware);

Transform Labels Based on Request

import { collectMetricsExpressMiddleware } from '@map-colonies/prometheus';
import { Registry } from 'prom-client';

const registry = new Registry();

const middleware = collectMetricsExpressMiddleware({
registry,
customLabels: {
tenant: '',
user_type: ''
},
transformLabels: (labels, req, res) => {
// Add dynamic labels based on request
labels.tenant = req.headers['x-tenant-id'] || 'unknown';
labels.user_type = req.user?.type || 'anonymous';
return labels;
}
});

app.use(middleware);

Selective Metric Collection

import { collectMetricsExpressMiddleware } from '@map-colonies/prometheus';
import { Registry } from 'prom-client';

const registry = new Registry();

const middleware = collectMetricsExpressMiddleware({
registry,
collectNodeMetrics: true,
collectServiceVersion: true,
includeOperationId: false // No OpenAPI validator
});

app.use(middleware);

Best Practices

  1. Use a single registry: Share one Registry instance across your application to avoid duplicate metric collection.

  2. Add meaningful labels: Use the labels option to add context-specific information (environment, region, etc.).

  3. Avoid high-cardinality labels: Don't use user IDs, timestamps, or other high-cardinality values as labels, as this can cause memory issues.

  4. Monitor metric cardinality: Regularly check the number of unique label combinations to prevent cardinality explosions.

Integration with Prometheus

To scrape metrics from your application, configure Prometheus with a scrape config:

scrape_configs:
- job_name: 'my-nodejs-app'
scrape_interval: 15s
static_configs:
- targets: ['localhost:8080']
metrics_path: '/metrics'
note

This page was generated from a remote source. you can find it on https://github.com/MapColonies/infra-packages/blob/master/packages/README.md