UNPKG

@sourceregistry/node-prometheus

Version:

A lightweight, zero-dependency TypeScript library for creating and exposing Prometheus metrics in standard exposition and OpenMetrics format.

337 lines (244 loc) β€’ 8.62 kB
# πŸ“Š @sourceregistry/node-prometheus > **A lightweight, zero-dependency TypeScript library for creating and exposing Prometheus & OpenMetrics-compatible metrics.** [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![npm version](https://img.shields.io/npm/v/@sourceregistry/node-prometheus.svg)](https://www.npmjs.com/package/@sourceregistry/node-prometheus) Supports: - βœ… Counter - βœ… Gauge - βœ… Histogram - βœ… Summary - βœ… Untyped Exports metrics in **Prometheus exposition format** and **OpenMetrics v1.0.0** β€” ready for modern observability stacks. --- ## πŸš€ Installation ```bash npm install @sourceregistry/node-prometheus ``` > βœ… Zero external dependencies β€” pure TypeScript. --- ## 🧩 Usage Examples ### Counter ```ts import { Counter } from '@sourceregistry/node-prometheus'; let requestCount = 0; const counter = new Counter({ name: 'http_requests_total', description: 'Total number of HTTP requests', reader: () => [requestCount] }); // Later... requestCount++; ``` ### Gauge ```ts import { Gauge } from '@sourceregistry/node-prometheus'; const gauge = new Gauge({ name: 'current_temperature_celsius', description: 'Current temperature in Celsius', reader: () => [getTemperature()] // e.g., returns 23.5 }); ``` ### Histogram ```ts import { Histogram } from '@sourceregistry/node-prometheus'; const histogram = new Histogram({ name: 'response_time_seconds', description: 'HTTP response time in seconds', buckets: [0.1, 0.5, 1, 2.5, 5] }); histogram.observe(0.73); // Updates buckets, sum, and count ``` ### Summary ```ts import { Summary } from '@sourceregistry/node-prometheus'; const summary = new Summary({ name: 'request_duration_seconds', description: 'Request duration with quantiles', quantiles: [0.5, 0.9, 0.99], calculate: (value, quantile) => { // Example: simple moving average const current = /* your state */ 0; return current * 0.9 + value * 0.1; } }); summary.observe(1.2); ``` ### Untyped ```ts import { Untyped } from '@sourceregistry/node-prometheus'; const untyped = new Untyped({ name: 'some_legacy_metric', value: 42 }); untyped.set(43); ``` ### Combine Multiple Metrics (with Format Support) Use `Metric.concat()` to serialize multiple metrics into a single string. You can specify `'prometheus'` (default) or `'openmetrics'` format. ```ts import { Metric, Counter, Gauge } from '@sourceregistry/node-prometheus'; let requestCount = 0; const counter = new Counter({ name: 'http_requests_total', description: 'Total HTTP requests', reader: () => [requestCount] }); const gauge = new Gauge({ name: 'cpu_usage_percent', description: 'Current CPU usage', reader: () => [Math.random() * 100] }); // Serialize in Prometheus format (default) const promOutput = await Metric.concat('prometheus', counter, gauge); console.log(promOutput); // # HELP http_requests_total ... // # TYPE http_requests_total counter // http_requests_total 0 1712345678901 // ... // Serialize in OpenMetrics format const omOutput = await Metric.concat('openmetrics', counter, gauge); console.log(omOutput); // # HELP http_requests_total ... // # TYPE http_requests_total counter // http_requests_total 0 1712345678901 // ... // # EOF ``` > βœ… In OpenMetrics mode, `# EOF` is automatically appended, and trailing whitespace is trimmed. --- ## 🌐 HTTP Server Example (Auto-negotiates Prometheus/OpenMetrics) This example uses `Metric.concat(format, ...)` to serve the correct format based on the client’s `Accept` header. ```ts // examples/server.ts import { createServer } from 'http'; import { Counter, Gauge, Histogram, Metric, Untyped } from '@sourceregistry/node-prometheus'; const gauge = new Gauge({ name: 'random_gauge', description: 'Random gauge value updated on each scrape', reader: () => [Math.random() * 100], }); const histogram = new Histogram({ name: 'random_histogram', description: 'Histogram of random values', buckets: [0.1, 0.2, 0.5, 1.0], }); let hits = 0; const counter = new Counter({ name: 'http_requests_total', description: 'Total HTTP requests handled', reader: () => [[hits, { method: 'GET', endpoint: '/metrics' }]], }); const untyped = new Untyped({ name: 'uptime_seconds', description: 'Server uptime in seconds', value: [0, Date.now()], }); // Simulate background metric updates setInterval(() => { histogram.observe(Math.random()); const uptime = (Date.now() - untyped.get()[1]) / 1000; untyped.set(uptime); }, 2000); // HTTP Server with OpenMetrics negotiation createServer(async (req, res) => { console.log(`Scraped at ${new Date().toISOString()}`); hits++; const acceptHeader = req.headers['accept'] || ''; const format = acceptHeader.includes('application/openmetrics-text') ? 'openmetrics' : 'prometheus'; res.writeHead(200, { 'Content-Type': format === 'openmetrics' ? 'application/openmetrics-text; version=1.0.0; charset=utf-8' : 'text/plain; version=0.0.4; charset=utf-8', }); const output = await Metric.concat(format, gauge, histogram, counter, untyped); res.end(output); }).listen(8080, '0.0.0.0', () => { console.log('βœ… Metrics server: http://localhost:8080'); }); ``` Run it: ```bash npm run example::http.server ``` Then test: ```bash curl -H "Accept: application/openmetrics-text" http://localhost:8080 curl http://localhost:8080 # defaults to Prometheus format ``` --- ## πŸ“ Prometheus Exposition Format Compatible with classic Prometheus scrapers: ``` # HELP http_requests_total Total number of HTTP requests # TYPE http_requests_total counter http_requests_total{method="GET",endpoint="/metrics"} 5 1712345678901 # HELP response_time_seconds HTTP response time in seconds # TYPE response_time_seconds histogram response_time_seconds_bucket{le="0.1"} 3 response_time_seconds_bucket{le="0.5"} 15 response_time_seconds_bucket{le="1"} 20 response_time_seconds_bucket{le="+Inf"} 20 response_time_seconds_sum 12.34 response_time_seconds_count 20 ``` --- ## πŸ“ OpenMetrics Format (Modern Standard) When client sends `Accept: application/openmetrics-text`, server responds with: ``` # HELP random_gauge Random gauge value updated on each scrape # TYPE random_gauge gauge random_gauge 42.17 1712345678901 # HELP random_histogram Histogram of random values # TYPE random_histogram histogram random_histogram_bucket{le="0.1"} 3 1712345678901 random_histogram_bucket{le="0.2"} 7 1712345678901 random_histogram_bucket{le="0.5"} 15 1712345678901 random_histogram_bucket{le="1.0"} 20 1712345678901 random_histogram_bucket{le="+Inf"} 20 1712345678901 random_histogram_sum 12.34 1712345678901 random_histogram_count 20 1712345678901 # HELP http_requests_total Total HTTP requests handled # TYPE http_requests_total counter http_requests_total{method="GET",endpoint="/metrics"} 5 1712345678901 # HELP uptime_seconds Server uptime in seconds # TYPE uptime_seconds untyped uptime_seconds 124.3 1712345678901 # EOF ``` > βœ… Required: `+Inf` bucket, `# EOF`, correct `Content-Type`. --- ## πŸ› οΈ Features - βœ… **Type-safe** β€” Full TypeScript support with JSDoc. - βœ… **Async/Sync Readers** β€” Gauge/Counter support both. - βœ… **Label Support** β€” Per-metric and per-sample labels. - βœ… **Timestamps** β€” Optional sample timestamps. - βœ… **Validation** β€” Input sanitization and error handling. - βœ… **Extensible** β€” Easy to extend or override behavior. - βœ… **OpenMetrics Ready** β€” Auto-negotiation support in HTTP example. - βœ… **Zero Dependencies** β€” Pure TypeScript, no bloat. --- ## πŸ§ͺ Testing Comes with **Vitest-compatible tests** covering all metric types, serialization, edge cases, and error handling. Run tests: ```bash npm test # Watch mode npm run test:ui # GUI npm run test:coverage # Coverage report ``` --- ## πŸ‘Ύ Examples See the [`examples/`](./examples) folder in this repository for: - Basic metric usage - HTTP server with Prometheus/OpenMetrics support - Histogram/Summary simulations --- ## πŸ“œ License **Apache License 2.0** β€” See [LICENSE](./LICENSE) for details. --- ## 🀝 Contributing PRs welcome! Please ensure: - βœ… Code matches existing style and JSDoc standards - βœ… Tests are added for new features - βœ… No external dependencies added - βœ… `npm run build` and `npm test` pass --- > πŸ’‘ **Note**: This library generates exposition format only. You must expose it via HTTP (e.g., Express, Fastify, or plain `http`) for Prometheus to scrape. See the HTTP example above to get started quickly.