npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

express-prometheus-exporter

v1.5.2

Published

RED/USE metrics for express applications

Downloads

101

Readme

Express Prometheus Exporter

This is a middleware for express servers, that expose metrics for prometheus.

The metrics exposed allows to calculate common RED (Request, Error rate, Duration of requests), and USE (Utilisation, Error rate, and Saturation), metrics

Install

Using yarn.

yarn add express-prometheus-exporter

Using npm.

npm install express-prometheus-exporter

Usage

Options

| Name | Description | Default | | :-: | :- | :- | | metricsPath | Url route that will expose the metrics for scraping. | /metrics | | metricsApp | Express app that will expose metrics endpoint, if an app is provided, use it, instead of instantiating a new one | null | | collectDefaultMetrics | Whether or not to collect prom-client default metrics. These metrics are usefull for collecting saturation metrics, for example. | true | | collectGCMetrics | Whether or not to collect garbage collection metrics via module prometheus-gc-stats. Dependency prometheus-gc-stats is marked as optional, hence if this option is set to true but npm/yarn could not install the dependency, no garbage collection metric will be collected. | false | | collectAnyPaths | Whether or not record any request path to the server | false | | requestDurationBuckets | Buckets for the request duration metrics (in seconds) histogram | Uses prom-client utility: Prometheus.exponentialBuckets(0.05, 1.75, 8) | | requestLengthBuckets | Buckets for the request length metrics (in bytes) histogram | no buckets (The request length metrics are not collected): [] | | responseLengthBuckets | Buckets for the response length metrics (in bytes) histogram | no buckets (The response length metrics are not collected) [] | | sampleRate | Define how many response should be recorded per 100 request | 1.0 (100%) | | extraMasks | Optional, list of regexes to be used as argument to url-value-parser, this will cause extra route params, to be replaced with a #val placeholder. | no extra masks: [] | | authenticate | Optional authentication callback, the function should receive as argument, the req object and return truthy for sucessfull authentication, or falsy, otherwise. This option supports Promise results. | null | | prefix | Optional prefix for the metrics name | no prefix added | | customLabels | Optional Array containing extra labels, used together with transformLabels | no extra labels: [] | | transformLabels | Optional function(labels, req, res) adds to the labels object dynamic values for each label in customLabels | null | | normalizeStatus | Optional parameter to disable normalization of the status code. Example of normalized and non-normalized status code respectively: 4xx and 422.| true

Example

const express = require('express');
const createExpressPrometheusExporterMiddleware = require('express-prometheus-exporter');
const app = express();

const PORT = 9091;

app.use(createExpressPrometheusExporterMiddleware({
  metricsPath: '/metrics',
  collectDefaultMetrics: true,
  requestDurationBuckets: [0.1, 0.5, 1, 1.5],
  requestLengthBuckets: [512, 1024, 5120, 10240, 51200, 102400],
  responseLengthBuckets: [512, 1024, 5120, 10240, 51200, 102400],
  sampleRate: 1.0,
  /**
   * Uncomenting the `authenticate` callback will make the `metricsPath` route
   * require authentication. This authentication callback can make a simple
   * basic auth test, or even query a remote server to validate access.
   * To access /metrics you could do:
   * curl -X GET user:password@localhost:9091/metrics
   */
  // authenticate: req => req.headers.authorization === 'Basic dXNlcjpwYXNzd29yZA==',
  /**
   * Uncommenting the `extraMasks` config will use the list of regexes to
   * reformat URL path names and replace the values found with a placeholder value
  */
  // extraMasks: [/..:..:..:..:..:../],
  /**
   * The prefix option will cause all metrics to have the given prefix.
   * E.g.: `app_prefix_http_requests_total`
   */
  // prefix: 'app_prefix_',
  /**
   * Can add custom labels with customLabels and transformLabels options
   */
  // customLabels: ['contentType'],
  // transformLabels(labels, req) {
  //   // eslint-disable-next-line no-param-reassign
  //   labels.contentType = req.headers['content-type'];
  // },
}));

// curl -X GET localhost:9091/hello?name=Chuck%20Norris
app.get('/hello', (req, res) => {
  console.log('GET /hello');
  const { name = 'Anon' } = req.query;
  res.json({ message: `Hello, ${name}!` });
});

app.listen(PORT, () => {
  console.log(`Example api is listening on http://localhost:${PORT}`);
});

Metrics exposed

  • Default metrics from prom-client
  • http_requests_total: Counter for total requests received, has labels route, method, status
  • http_request_duration_seconds: - Duration of HTTP requests in seconds, has labels route, method, status

The labels route and status are normalized:

  • route: will normalize id like route params
  • status: will normalize to status code family groups, like 2XX or 4XX.

Example prometheus queries

In the examples below, Suppose you tagged your application as "myapp", in the prometheus scrapping config.

Running instances

sum(up{app="myapp"})

Overall error rate

Rate of http status code 5XX responses

sum(rate(http_requests_total{status="5XX", app="myapp"}[5m]))

95% of requests served within seconds

histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{app="myapp"}[5m])) by (le))

95% of request length

histogram_quantile(0.95, sum(rate(http_request_length_bytes_bucket{app="myapp"}[5m])) by (le))

95% of response length

histogram_quantile(0.95, sum(rate(http_response_length_bytes_bucket{app="myapp"}[5m])) by (le))

Average response time in seconds

sum(rate(http_request_duration_seconds_sum{app="myapp"}[5m])) by (instance) / sum(rate(http_request_duration_seconds_count{app="myapp"}[5m])) by (instance)

Overall Request rate

sum(rate(http_requests_total{app="myapp"}[5m])) by (instance)

Request rate by route

In this example we are removing some health/status-check routes, replace them with your needs.

sum(rate(http_requests_total{app="myapp", route!~"/|/healthz"}[5m])) by (instance, route)

CPU usage

rate(process_cpu_system_seconds_total{app="myapp"}[5m])
rate(process_cpu_user_seconds_total{app="myapp"}[5m])

Memory usage

nodejs_heap_size_total_bytes{app="myapp"}
nodejs_heap_size_used_bytes{app="myapp"}