{"id":13465020,"url":"https://github.com/siimon/prom-client","last_synced_at":"2025-05-11T03:50:10.148Z","repository":{"id":37433519,"uuid":"46582024","full_name":"siimon/prom-client","owner":"siimon","description":"Prometheus client for node.js","archived":false,"fork":false,"pushed_at":"2024-08-10T12:15:33.000Z","size":1774,"stargazers_count":3259,"open_issues_count":120,"forks_count":383,"subscribers_count":32,"default_branch":"master","last_synced_at":"2025-05-08T17:16:53.217Z","etag":null,"topics":["metrics","monitoring","nodejs","prometheus-client"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/siimon.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-11-20T19:23:13.000Z","updated_at":"2025-05-07T22:28:05.000Z","dependencies_parsed_at":"2023-12-28T11:37:37.384Z","dependency_job_id":"63127602-f3a8-4bf1-bcfa-a43b61afec47","html_url":"https://github.com/siimon/prom-client","commit_stats":{"total_commits":478,"total_committers":112,"mean_commits":4.267857142857143,"dds":0.7489539748953975,"last_synced_commit":"126d4f32afc686b410e1b00ce311526ee3eca645"},"previous_names":[],"tags_count":71,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siimon%2Fprom-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siimon%2Fprom-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siimon%2Fprom-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siimon%2Fprom-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/siimon","download_url":"https://codeload.github.com/siimon/prom-client/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253112125,"owners_count":21856073,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["metrics","monitoring","nodejs","prometheus-client"],"created_at":"2024-07-31T14:00:55.248Z","updated_at":"2025-05-11T03:50:10.130Z","avatar_url":"https://github.com/siimon.png","language":"JavaScript","readme":"# Prometheus client for node.js [![Actions Status](https://github.com/siimon/prom-client/workflows/Node.js%20CI/badge.svg?branch=master)](https://github.com/siimon/prom-client/actions)\n\nA prometheus client for Node.js that supports histogram, summaries, gauges and\ncounters.\n\n## Usage\n\nSee example folder for a sample usage. The library does not bundle any web\nframework. To expose the metrics, respond to Prometheus's scrape requests with\nthe result of `await registry.metrics()`.\n\n### Usage with Node.js's `cluster` module\n\nNode.js's `cluster` module spawns multiple processes and hands off socket\nconnections to those workers. Returning metrics from a worker's local registry\nwill only reveal that individual worker's metrics, which is generally\nundesirable. To solve this, you can aggregate all of the workers' metrics in the\nmaster process. See `example/cluster.js` for an example.\n\nDefault metrics use sensible aggregation methods. (Note, however, that the event\nloop lag mean and percentiles are averaged, which is not perfectly accurate.)\nCustom metrics are summed across workers by default. To use a different\naggregation method, set the `aggregator` property in the metric config to one of\n'sum', 'first', 'min', 'max', 'average' or 'omit'. (See `lib/metrics/version.js`\nfor an example.)\n\nIf you need to expose metrics about an individual worker, you can include a\nvalue that is unique to the worker (such as the worker ID or process ID) in a\nlabel. (See `example/server.js` for an example using\n`worker_${cluster.worker.id}` as a label value.)\n\nMetrics are aggregated from the global registry by default. To use a different\nregistry, call\n`client.AggregatorRegistry.setRegistries(registryOrArrayOfRegistries)` from the\nworker processes.\n\n## API\n\n### Default metrics\n\nThere are some default metrics recommended by Prometheus\n[itself](https://prometheus.io/docs/instrumenting/writing_clientlibs/#standard-and-runtime-collectors).\nTo collect these, call `collectDefaultMetrics`. In addition, some\nNode.js-specific metrics are included, such as event loop lag, active handles,\nGC and Node.js version. See [lib/metrics](lib/metrics) for a list of all\nmetrics.\n\nNOTE: Some of the metrics, concerning File Descriptors and Memory, are only\navailable on Linux.\n\n`collectDefaultMetrics` optionally accepts a config object with following entries:\n\n- `prefix` an optional prefix for metric names. Default: no prefix.\n- `register` to which registry the metrics should be registered. Default: the global default registry.\n- `gcDurationBuckets` with custom buckets for GC duration histogram. Default buckets of GC duration histogram are `[0.001, 0.01, 0.1, 1, 2, 5]` (in seconds).\n- `eventLoopMonitoringPrecision` with sampling rate in milliseconds. Must be greater than zero. Default: 10.\n\nTo register metrics to another registry, pass it in as `register`:\n\n```js\nconst client = require('prom-client');\nconst collectDefaultMetrics = client.collectDefaultMetrics;\nconst Registry = client.Registry;\nconst register = new Registry();\ncollectDefaultMetrics({ register });\n```\n\nTo use custom buckets for GC duration histogram, pass it in as `gcDurationBuckets`:\n\n```js\nconst client = require('prom-client');\nconst collectDefaultMetrics = client.collectDefaultMetrics;\ncollectDefaultMetrics({ gcDurationBuckets: [0.1, 0.2, 0.3] });\n```\n\nTo prefix metric names with your own arbitrary string, pass in a `prefix`:\n\n```js\nconst client = require('prom-client');\nconst collectDefaultMetrics = client.collectDefaultMetrics;\nconst prefix = 'my_application_';\ncollectDefaultMetrics({ prefix });\n```\n\nTo apply generic labels to all default metrics, pass an object to the `labels` property (useful if you're working in a clustered environment):\n\n```js\nconst client = require('prom-client');\nconst collectDefaultMetrics = client.collectDefaultMetrics;\ncollectDefaultMetrics({\n  labels: { NODE_APP_INSTANCE: process.env.NODE_APP_INSTANCE },\n});\n```\n\nYou can get the full list of metrics by inspecting\n`client.collectDefaultMetrics.metricsList`.\n\nDefault metrics are collected on scrape of metrics endpoint,\nnot on an interval.\n\n```js\nconst client = require('prom-client');\n\nconst collectDefaultMetrics = client.collectDefaultMetrics;\n\ncollectDefaultMetrics();\n```\n\n### Custom Metrics\n\nAll metric types have two mandatory parameters: `name` and `help`. Refer to\n\u003chttps://prometheus.io/docs/practices/naming/\u003e for guidance on naming metrics.\n\nFor metrics based on point-in-time observations (e.g. current memory usage, as\nopposed to HTTP request durations observed continuously in a histogram), you\nshould provide a `collect()` function, which will be invoked when Prometheus\nscrapes your metrics endpoint. `collect()` can either be synchronous or return a\npromise. See **Gauge** below for an example. (Note that you should not update\nmetric values in a `setInterval` callback; do so in this `collect` function\ninstead.)\n\nSee [**Labels**](#labels) for information on how to configure labels for all\nmetric types.\n\n#### Counter\n\nCounters go up, and reset when the process restarts.\n\n```js\nconst client = require('prom-client');\nconst counter = new client.Counter({\n  name: 'metric_name',\n  help: 'metric_help',\n});\ncounter.inc(); // Increment by 1\ncounter.inc(10); // Increment by 10\n```\n\n#### Gauge\n\nGauges are similar to Counters but a Gauge's value can be decreased.\n\n```js\nconst client = require('prom-client');\nconst gauge = new client.Gauge({ name: 'metric_name', help: 'metric_help' });\ngauge.set(10); // Set to 10\ngauge.inc(); // Increment 1\ngauge.inc(10); // Increment 10\ngauge.dec(); // Decrement by 1\ngauge.dec(10); // Decrement by 10\n```\n\n##### Configuration\n\nIf the gauge is used for a point-in-time observation, you should provide a\n`collect` function:\n\n```js\nconst client = require('prom-client');\nnew client.Gauge({\n  name: 'metric_name',\n  help: 'metric_help',\n  collect() {\n    // Invoked when the registry collects its metrics' values.\n    // This can be synchronous or it can return a promise/be an async function.\n    this.set(/* the current value */);\n  },\n});\n```\n\n```js\n// Async version:\nconst client = require('prom-client');\nnew client.Gauge({\n  name: 'metric_name',\n  help: 'metric_help',\n  async collect() {\n    // Invoked when the registry collects its metrics' values.\n    const currentValue = await somethingAsync();\n    this.set(currentValue);\n  },\n});\n```\n\nNote that you should not use arrow functions for `collect` because arrow\nfunctions will not have the correct value for `this`.\n\n##### Utility Functions\n\n```js\n// Set value to current time in seconds:\ngauge.setToCurrentTime();\n\n// Record durations:\nconst end = gauge.startTimer();\nhttp.get('url', res =\u003e {\n  end();\n});\n```\n\n#### Histogram\n\nHistograms track sizes and frequency of events.\n\n##### Configuration\n\nThe defaults buckets are intended to cover usual web/RPC requests, but they can\nbe overridden. (See also [**Bucket Generators**](#bucket-generators).)\n\n```js\nconst client = require('prom-client');\nnew client.Histogram({\n  name: 'metric_name',\n  help: 'metric_help',\n  buckets: [0.1, 5, 15, 50, 100, 500],\n});\n```\n\n##### Examples\n\n```js\nconst client = require('prom-client');\nconst histogram = new client.Histogram({\n  name: 'metric_name',\n  help: 'metric_help',\n});\nhistogram.observe(10); // Observe value in histogram\n```\n\n##### Utility Methods\n\n```js\nconst end = histogram.startTimer();\nxhrRequest(function (err, res) {\n  const seconds = end(); // Observes and returns the value to xhrRequests duration in seconds\n});\n```\n\n#### Summary\n\nSummaries calculate percentiles of observed values.\n\n##### Configuration\n\nThe default percentiles are: 0.01, 0.05, 0.5, 0.9, 0.95, 0.99, 0.999. But they\ncan be overridden by specifying a `percentiles` array. (See also\n[**Bucket Generators**](#bucket-generators).)\n\n```js\nconst client = require('prom-client');\nnew client.Summary({\n  name: 'metric_name',\n  help: 'metric_help',\n  percentiles: [0.01, 0.1, 0.9, 0.99],\n});\n```\n\nTo enable the sliding window functionality for summaries you need to add\n`maxAgeSeconds` and `ageBuckets` to the config like this:\n\n```js\nconst client = require('prom-client');\nnew client.Summary({\n  name: 'metric_name',\n  help: 'metric_help',\n  maxAgeSeconds: 600,\n  ageBuckets: 5,\n  pruneAgedBuckets: false,\n});\n```\n\nThe `maxAgeSeconds` will tell how old a bucket can be before it is reset and\n`ageBuckets` configures how many buckets we will have in our sliding window for\nthe summary. If `pruneAgedBuckets` is `false` (default), the metric value will\nalways be present, even when empty (its percentile values will be `0`). Set\n`pruneAgedBuckets` to `true` if you don't want to export it when it is empty.\n\n##### Examples\n\n```js\nconst client = require('prom-client');\nconst summary = new client.Summary({\n  name: 'metric_name',\n  help: 'metric_help',\n});\nsummary.observe(10);\n```\n\n##### Utility Methods\n\n```js\nconst end = summary.startTimer();\nxhrRequest(function (err, res) {\n  end(); // Observes the value to xhrRequests duration in seconds\n});\n```\n\n### Labels\n\nAll metrics can take a `labelNames` property in the configuration object. All\nlabel names that the metric support needs to be declared here. There are two\nways to add values to the labels:\n\n```js\nconst client = require('prom-client');\nconst gauge = new client.Gauge({\n  name: 'metric_name',\n  help: 'metric_help',\n  labelNames: ['method', 'statusCode'],\n});\n\n// 1st version: Set value to 100 with \"method\" set to \"GET\" and \"statusCode\" to \"200\"\ngauge.set({ method: 'GET', statusCode: '200' }, 100);\n// 2nd version: Same effect as above\ngauge.labels({ method: 'GET', statusCode: '200' }).set(100);\n// 3rd version: And again the same effect as above\ngauge.labels('GET', '200').set(100);\n```\n\nIt is also possible to use timers with labels, both before and after the timer\nis created:\n\n```js\nconst end = startTimer({ method: 'GET' }); // Set method to GET, we don't know statusCode yet\nxhrRequest(function (err, res) {\n  if (err) {\n    end({ statusCode: '500' }); // Sets value to xhrRequest duration in seconds with statusCode 500\n  } else {\n    end({ statusCode: '200' }); // Sets value to xhrRequest duration in seconds with statusCode 200\n  }\n});\n```\n\n#### Zeroing metrics with Labels\n\nMetrics with labels can not be exported before they have been observed at least\nonce since the possible label values are not known before they're observed.\n\nFor histograms, this can be solved by explicitly zeroing all expected label values:\n\n```js\nconst histogram = new client.Histogram({\n  name: 'metric_name',\n  help: 'metric_help',\n  buckets: [0.1, 5, 15, 50, 100, 500],\n  labels: ['method'],\n});\nhistogram.zero({ method: 'GET' });\nhistogram.zero({ method: 'POST' });\n```\n\n#### Strongly typed Labels\n\nTypescript can also enforce label names using `as const`\n\n```typescript\nimport * as client from 'prom-client';\n\nconst counter = new client.Counter({\n  name: 'metric_name',\n  help: 'metric_help',\n  // add `as const` here to enforce label names\n  labelNames: ['method'] as const,\n});\n\n// Ok\ncounter.inc({ method: 1 });\n\n// this is an error since `'methods'` is not a valid `labelName`\n// @ts-expect-error\ncounter.inc({ methods: 1 });\n```\n\n#### Default Labels (segmented by registry)\n\nStatic labels may be applied to every metric emitted by a registry:\n\n```js\nconst client = require('prom-client');\nconst defaultLabels = { serviceName: 'api-v1' };\nclient.register.setDefaultLabels(defaultLabels);\n```\n\nThis will output metrics in the following way:\n\n```\n# HELP process_resident_memory_bytes Resident memory size in bytes.\n# TYPE process_resident_memory_bytes gauge\nprocess_resident_memory_bytes{serviceName=\"api-v1\"} 33853440 1498510040309\n```\n\nDefault labels will be overridden if there is a name conflict.\n\n`register.clear()` will clear default labels.\n\n### Exemplars\n\nThe exemplars defined in the OpenMetrics specification can be enabled on Counter\nand Histogram metric types. The default metrics have support for OpenTelemetry,\nthey will populate the exemplars with the labels `{traceId, spanId}` and their\ncorresponding values.\n\nThe format for `inc()` and `observe()` calls are different if exemplars are\nenabled. They get a single object with the format\n`{labels, value, exemplarLabels}`.\n\nWhen using exemplars, the registry used for metrics should be set to OpenMetrics\ntype (including the global or default registry if no registries are specified).\n\n### Registry type\n\nThe library supports both the old Prometheus format and the OpenMetrics format.\nThe format can be set per registry. For default metrics:\n\n```js\nconst Prometheus = require('prom-client');\nPrometheus.register.setContentType(\n  Prometheus.Registry.OPENMETRICS_CONTENT_TYPE,\n);\n```\n\nCurrently available registry types are defined by the content types:\n\n**PROMETHEUS_CONTENT_TYPE** - version 0.0.4 of the original Prometheus metrics,\nthis is currently the default registry type.\n\n**OPENMETRICS_CONTENT_TYPE** - defaults to version 1.0.0 of the\n[OpenMetrics standard](https://github.com/OpenObservability/OpenMetrics/blob/d99b705f611b75fec8f450b05e344e02eea6921d/specification/OpenMetrics.md).\n\nThe HTTP Content-Type string for each registry type is exposed both at module\nlevel (`prometheusContentType` and `openMetricsContentType`) and as static\nproperties on the `Registry` object.\n\nThe `contentType` constant exposed by the module returns the default content\ntype when creating a new registry, currently defaults to Prometheus type.\n\n### Multiple registries\n\nBy default, metrics are automatically registered to the global registry (located\nat `require('prom-client').register`). You can prevent this by specifying\n`registers: []` in the metric constructor configuration.\n\nUsing non-global registries requires creating a Registry instance and passing it\ninside `registers` in the metric configuration object. Alternatively you can\npass an empty `registers` array and register it manually.\n\nRegistry has a `merge` function that enables you to expose multiple registries\non the same endpoint. If the same metric name exists in both registries, an\nerror will be thrown.\n\nMerging registries of different types is undefined. The user needs to make sure\nall used registries have the same type (Prometheus or OpenMetrics versions).\n\n```js\nconst client = require('prom-client');\nconst registry = new client.Registry();\nconst counter = new client.Counter({\n  name: 'metric_name',\n  help: 'metric_help',\n  registers: [registry], // specify a non-default registry\n});\nconst histogram = new client.Histogram({\n  name: 'metric_name',\n  help: 'metric_help',\n  registers: [], // don't automatically register this metric\n});\nregistry.registerMetric(histogram); // register metric manually\ncounter.inc();\n\nconst mergedRegistries = client.Registry.merge([registry, client.register]);\n```\n\nIf you want to use multiple or non-default registries with the Node.js `cluster`\nmodule, you will need to set the registry/registries to aggregate from:\n\n```js\nconst AggregatorRegistry = client.AggregatorRegistry;\nAggregatorRegistry.setRegistries(registry);\n// or for multiple registries:\nAggregatorRegistry.setRegistries([registry1, registry2]);\n```\n\n### Register\n\nYou can get all metrics by running `await register.metrics()`, which will return\na string in the Prometheus exposition format.\n\n#### Getting a single metric value in Prometheus exposition format\n\nIf you need to output a single metric in the Prometheus exposition format, you\ncan use `await register.getSingleMetricAsString(*name of metric*)`, which will\nreturn a string for Prometheus to consume.\n\n#### Getting a single metric\n\nIf you need to get a reference to a previously registered metric, you can use\n`register.getSingleMetric(*name of metric*)`.\n\n#### Removing metrics\n\nYou can remove all metrics by calling `register.clear()`. You can also remove a\nsingle metric by calling `register.removeSingleMetric(*name of metric*)`.\n\n#### Resetting metrics\n\nIf you need to reset all metrics, you can use `register.resetMetrics()`. The\nmetrics will remain present in the register and can be used without the need to\ninstantiate them again, like you would need to do after `register.clear()`.\n\n#### Cluster metrics\n\nYou can get aggregated metrics for all workers in a Node.js cluster with\n`await register.clusterMetrics()`. This method returns a promise that resolves\nwith a metrics string suitable for Prometheus to consume.\n\n```js\nconst metrics = await register.clusterMetrics();\n\n// - or -\n\nregister\n  .clusterMetrics()\n  .then(metrics =\u003e {\n    /* ... */\n  })\n  .catch(err =\u003e {\n    /* ... */\n  });\n```\n\n### Pushgateway\n\nIt is possible to push metrics via a\n[Pushgateway](https://github.com/prometheus/pushgateway).\n\n```js\nconst client = require('prom-client');\nlet gateway = new client.Pushgateway('http://127.0.0.1:9091');\n\ngateway.pushAdd({ jobName: 'test' })\n\t.then(({resp, body}) =\u003e {\n\t\t/* ... */\n\t})\n\t.catch(err =\u003e {\n\t\t/* ... */\n\t})); //Add metric and overwrite old ones\ngateway.push({ jobName: 'test' })\n\t.then(({resp, body}) =\u003e {\n\t\t/* ... */\n\t})\n\t.catch(err =\u003e {\n\t\t/* ... */\n\t})); //Overwrite all metrics (use PUT)\ngateway.delete({ jobName: 'test' })\n\t.then(({resp, body}) =\u003e {\n\t\t/* ... */\n\t})\n\t.catch(err =\u003e {\n\t\t/* ... */\n\t})); //Delete all metrics for jobName\n\n//All gateway requests can have groupings on it\ngateway.pushAdd({ jobName: 'test', groupings: { key: 'value' } })\n\t.then(({resp, body}) =\u003e {\n\t\t/* ... */\n\t})\n\t.catch(err =\u003e {\n\t\t/* ... */\n\t}));\n\n// It's possible to extend the Pushgateway with request options from nodes core\n// http/https library. In particular, you might want to provide an agent so that\n// TCP connections are reused.\ngateway = new client.Pushgateway('http://127.0.0.1:9091', {\n  timeout: 5000, //Set the request timeout to 5000ms\n  agent: new http.Agent({\n    keepAlive: true,\n    keepAliveMsec: 10000,\n    maxSockets: 5,\n  }),\n});\n```\n\nSome gateways such as [Gravel Gateway](https://github.com/sinkingpoint/prometheus-gravel-gateway) do not support grouping by job name, exposing a plain `/metrics` endpoint instead of `/metrics/job/\u003cjobName\u003e`. It's possible to configure a gateway instance to not require a jobName in the options argument.\n\n```js\ngravelGateway = new client.Pushgateway('http://127.0.0.1:9091', {\n  timeout: 5000,\n  requireJobName: false,\n});\ngravelGateway.pushAdd();\n```\n\n### Bucket Generators\n\nFor convenience, there are two bucket generator functions - linear and\nexponential.\n\n```js\nconst client = require('prom-client');\nnew client.Histogram({\n  name: 'metric_name',\n  help: 'metric_help',\n  buckets: client.linearBuckets(0, 10, 20), //Create 20 buckets, starting on 0 and a width of 10\n});\n\nnew client.Histogram({\n  name: 'metric_name',\n  help: 'metric_help',\n  buckets: client.exponentialBuckets(1, 2, 5), //Create 5 buckets, starting on 1 and with a factor of 2\n});\n```\n\n### Garbage Collection Metrics\n\nTo avoid native dependencies in this module, GC statistics for bytes reclaimed\nin each GC sweep are kept in a separate module:\nhttps://github.com/SimenB/node-prometheus-gc-stats. (Note that that metric may\nno longer be accurate now that v8 uses parallel garbage collection.)\n","funding_links":[],"categories":["JavaScript","Repository","HarmonyOS"],"sub_categories":["Application Performance Monitoring (APM)","Windows Manager"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsiimon%2Fprom-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsiimon%2Fprom-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsiimon%2Fprom-client/lists"}