@platformatic/metrics 2.74.3 → 3.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/eslint.config.js CHANGED
@@ -1,3 +1,3 @@
1
- 'use strict'
1
+ import neostandard from 'neostandard'
2
2
 
3
- module.exports = require('neostandard')({ ts: true })
3
+ export default neostandard()
package/index.js CHANGED
@@ -1,59 +1,42 @@
1
- 'use strict'
1
+ import collectHttpMetrics from '@platformatic/http-metrics'
2
+ import os from 'node:os'
3
+ import { performance } from 'node:perf_hooks'
4
+ import client from 'prom-client'
2
5
 
3
- const os = require('node:os')
4
- const { eventLoopUtilization } = require('node:perf_hooks').performance
5
- const client = require('prom-client')
6
- const collectHttpMetrics = require('@platformatic/http-metrics')
6
+ export * as client from 'prom-client'
7
7
 
8
+ const { eventLoopUtilization } = performance
8
9
  const { Registry, Gauge, Counter, collectDefaultMetrics } = client
9
10
 
10
- async function collectMetrics (serviceId, workerId, metricsConfig = {}, registry = undefined) {
11
- if (!registry) {
12
- registry = new Registry()
13
- }
11
+ export const kMetricsGroups = Symbol('plt.metrics.MetricsGroups')
14
12
 
15
- const labels = { ...metricsConfig.labels, serviceId }
16
- if (workerId >= 0) {
17
- labels.workerId = workerId
18
- }
19
- registry.setDefaultLabels(labels)
13
+ export function registerMetricsGroup (registry, group) {
14
+ registry[kMetricsGroups] ??= new Set()
15
+ registry[kMetricsGroups].add(group)
16
+ }
20
17
 
21
- if (metricsConfig.defaultMetrics) {
22
- collectDefaultMetrics({ register: registry })
23
- collectEluMetric(registry)
24
- await collectThreadCpuMetrics(registry)
25
- }
18
+ export function hasMetricsGroup (registry, group) {
19
+ return registry[kMetricsGroups]?.has(group)
20
+ }
26
21
 
27
- if (metricsConfig.httpMetrics) {
28
- collectHttpMetrics(registry, {
29
- customLabels: ['telemetry_id'],
30
- getCustomLabels: req => {
31
- const telemetryId = req.headers?.['x-plt-telemetry-id'] ?? 'unknown'
32
- return { telemetry_id: telemetryId }
33
- },
34
- histogram: {
35
- name: 'http_request_all_duration_seconds',
36
- help: 'request duration in seconds summary for all requests',
37
- collect: function () {
38
- process.nextTick(() => this.reset())
39
- }
40
- },
41
- summary: {
42
- name: 'http_request_all_summary_seconds',
43
- help: 'request duration in seconds histogram for all requests',
44
- collect: function () {
45
- process.nextTick(() => this.reset())
46
- }
47
- }
48
- })
49
- }
22
+ // Use this method when dealing with metrics registration in async functions.
23
+ // This will ensure that the group is registered only once.
24
+ export function ensureMetricsGroup (registry, group) {
25
+ registry[kMetricsGroups] ??= new Set()
50
26
 
51
- return {
52
- registry,
27
+ if (registry[kMetricsGroups]?.has(group)) {
28
+ return true
53
29
  }
30
+
31
+ registry[kMetricsGroups].add(group)
32
+ return false
54
33
  }
55
34
 
56
- async function collectThreadCpuMetrics (registry) {
35
+ export async function collectThreadCpuMetrics (registry) {
36
+ if (ensureMetricsGroup(registry, 'threadCpuUsage')) {
37
+ return
38
+ }
39
+
57
40
  let threadCpuUsage
58
41
 
59
42
  try {
@@ -117,7 +100,11 @@ async function collectThreadCpuMetrics (registry) {
117
100
  registry.registerMetric(threadCpuPercentUsageGaugeMetric)
118
101
  }
119
102
 
120
- function collectEluMetric (register) {
103
+ export function collectEluMetric (registry) {
104
+ if (ensureMetricsGroup(registry, 'elu')) {
105
+ return
106
+ }
107
+
121
108
  let startELU = eventLoopUtilization()
122
109
  const eluMetric = new Gauge({
123
110
  name: 'nodejs_eventloop_utilization',
@@ -128,9 +115,9 @@ function collectEluMetric (register) {
128
115
  eluMetric.set(result)
129
116
  startELU = endELU
130
117
  },
131
- registers: [register]
118
+ registers: [registry]
132
119
  })
133
- register.registerMetric(eluMetric)
120
+ registry.registerMetric(eluMetric)
134
121
 
135
122
  let previousIdleTime = 0
136
123
  let previousTotalTime = 0
@@ -161,9 +148,56 @@ function collectEluMetric (register) {
161
148
  previousIdleTime = idleTime
162
149
  previousTotalTime = totalTime
163
150
  },
164
- registers: [register]
151
+ registers: [registry]
165
152
  })
166
- register.registerMetric(cpuMetric)
153
+ registry.registerMetric(cpuMetric)
167
154
  }
168
155
 
169
- module.exports = { collectMetrics, client }
156
+ export async function collectMetrics (serviceId, workerId, metricsConfig = {}, registry = undefined) {
157
+ if (!registry) {
158
+ registry = new Registry()
159
+ }
160
+
161
+ const labels = { ...metricsConfig.labels, serviceId }
162
+ if (workerId >= 0) {
163
+ labels.workerId = workerId
164
+ }
165
+ registry.setDefaultLabels(labels)
166
+
167
+ if (metricsConfig.defaultMetrics) {
168
+ if (!ensureMetricsGroup(registry, 'default')) {
169
+ collectDefaultMetrics({ register: registry })
170
+ }
171
+
172
+ collectEluMetric(registry)
173
+ await collectThreadCpuMetrics(registry)
174
+ }
175
+
176
+ if (metricsConfig.httpMetrics && !ensureMetricsGroup(registry, 'http')) {
177
+ collectHttpMetrics(registry, {
178
+ customLabels: ['telemetry_id'],
179
+ getCustomLabels: req => {
180
+ const telemetryId = req.headers?.['x-plt-telemetry-id'] ?? 'unknown'
181
+ return { telemetry_id: telemetryId }
182
+ },
183
+ histogram: {
184
+ name: 'http_request_all_duration_seconds',
185
+ help: 'request duration in seconds summary for all requests',
186
+ collect: function () {
187
+ process.nextTick(() => this.reset())
188
+ }
189
+ },
190
+ summary: {
191
+ name: 'http_request_all_summary_seconds',
192
+ help: 'request duration in seconds histogram for all requests',
193
+ collect: function () {
194
+ process.nextTick(() => this.reset())
195
+ }
196
+ }
197
+ })
198
+ }
199
+
200
+ return {
201
+ registry
202
+ }
203
+ }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@platformatic/metrics",
3
- "version": "2.74.3",
3
+ "version": "3.0.0-alpha.2",
4
4
  "description": "Platformatic Stackable Metrics",
5
5
  "main": "index.js",
6
- "type": "commonjs",
6
+ "type": "module",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/platformatic/platformatic.git"
@@ -26,6 +26,9 @@
26
26
  "eslint": "9",
27
27
  "neostandard": "^0.12.0"
28
28
  },
29
+ "engines": {
30
+ "node": ">=22.18.0"
31
+ },
29
32
  "scripts": {
30
33
  "test": "npm run lint && borp",
31
34
  "lint": "eslint"
package/test/helper.js CHANGED
@@ -1,6 +1,6 @@
1
- const assert = require('node:assert')
1
+ import { ok } from 'node:assert'
2
2
 
3
- const expectedMetrics = [
3
+ export const expectedMetrics = [
4
4
  {
5
5
  name: 'nodejs_active_handles',
6
6
  type: 'gauge'
@@ -127,47 +127,42 @@ const expectedMetrics = [
127
127
  }
128
128
  ]
129
129
 
130
- function assertMetric (metrics, metric) {
131
- assert.ok(metrics.includes(`# HELP ${metric.name} `), `Metric ${metric.name} not found`)
132
- assert.ok(metrics.includes(`# TYPE ${metric.name} ${metric.type}`), `Metric ${metric.name} type ${metric.type} not found`)
133
-
134
- if (metric.type === 'summary') {
135
- assertSummary(metrics, metric)
136
- } else if (metric.type === 'histogram') {
137
- assertHistogram(metrics, metric)
138
- }
139
- }
140
-
141
130
  function assertSummary (metrics, metric) {
142
- assert.ok(metrics.includes(`${metric.name}{quantile="0.01"`))
143
- assert.ok(metrics.includes('http_request_all_summary_seconds{quantile="0.01"'))
144
- assert.ok(metrics.includes('http_request_all_summary_seconds{quantile="0.05"'))
145
- assert.ok(metrics.includes('http_request_all_summary_seconds{quantile="0.5"'))
146
- assert.ok(metrics.includes('http_request_all_summary_seconds{quantile="0.9"'))
147
- assert.ok(metrics.includes('http_request_all_summary_seconds{quantile="0.95"'))
148
- assert.ok(metrics.includes('http_request_all_summary_seconds{quantile="0.99"'))
149
- assert.ok(metrics.includes('http_request_all_summary_seconds{quantile="0.999"'))
150
- assert.ok(metrics.includes('http_request_all_summary_seconds_sum{'))
151
- assert.ok(metrics.includes('http_request_all_summary_seconds_count{'))
131
+ ok(metrics.includes(`${metric.name}{quantile="0.01"`))
132
+ ok(metrics.includes('http_request_all_summary_seconds{quantile="0.01"'))
133
+ ok(metrics.includes('http_request_all_summary_seconds{quantile="0.05"'))
134
+ ok(metrics.includes('http_request_all_summary_seconds{quantile="0.5"'))
135
+ ok(metrics.includes('http_request_all_summary_seconds{quantile="0.9"'))
136
+ ok(metrics.includes('http_request_all_summary_seconds{quantile="0.95"'))
137
+ ok(metrics.includes('http_request_all_summary_seconds{quantile="0.99"'))
138
+ ok(metrics.includes('http_request_all_summary_seconds{quantile="0.999"'))
139
+ ok(metrics.includes('http_request_all_summary_seconds_sum{'))
140
+ ok(metrics.includes('http_request_all_summary_seconds_count{'))
152
141
  }
153
142
 
154
143
  function assertHistogram (metrics, metric) {
155
- assert.ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.005"'))
156
- assert.ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.01"'))
157
- assert.ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.025"'))
158
- assert.ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.05"'))
159
- assert.ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.1"'))
160
- assert.ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.25"'))
161
- assert.ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.5"'))
162
- assert.ok(metrics.includes('http_request_all_duration_seconds_bucket{le="1"'))
163
- assert.ok(metrics.includes('http_request_all_duration_seconds_bucket{le="2.5"'))
164
- assert.ok(metrics.includes('http_request_all_duration_seconds_bucket{le="5"'))
165
- assert.ok(metrics.includes('http_request_all_duration_seconds_bucket{le="10"'))
166
- assert.ok(metrics.includes('http_request_all_duration_seconds_sum{'))
167
- assert.ok(metrics.includes('http_request_all_duration_seconds_count{'))
144
+ ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.005"'))
145
+ ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.01"'))
146
+ ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.025"'))
147
+ ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.05"'))
148
+ ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.1"'))
149
+ ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.25"'))
150
+ ok(metrics.includes('http_request_all_duration_seconds_bucket{le="0.5"'))
151
+ ok(metrics.includes('http_request_all_duration_seconds_bucket{le="1"'))
152
+ ok(metrics.includes('http_request_all_duration_seconds_bucket{le="2.5"'))
153
+ ok(metrics.includes('http_request_all_duration_seconds_bucket{le="5"'))
154
+ ok(metrics.includes('http_request_all_duration_seconds_bucket{le="10"'))
155
+ ok(metrics.includes('http_request_all_duration_seconds_sum{'))
156
+ ok(metrics.includes('http_request_all_duration_seconds_count{'))
168
157
  }
169
158
 
170
- module.exports = {
171
- expectedMetrics,
172
- assertMetric
159
+ export function assertMetric (metrics, metric) {
160
+ ok(metrics.includes(`# HELP ${metric.name} `), `Metric ${metric.name} not found`)
161
+ ok(metrics.includes(`# TYPE ${metric.name} ${metric.type}`), `Metric ${metric.name} type ${metric.type} not found`)
162
+
163
+ if (metric.type === 'summary') {
164
+ assertSummary(metrics, metric)
165
+ } else if (metric.type === 'histogram') {
166
+ assertHistogram(metrics, metric)
167
+ }
173
168
  }
@@ -1,8 +1,6 @@
1
- 'use strict'
2
-
3
- const assert = require('node:assert')
4
- const { test } = require('node:test')
5
- const { collectMetrics, client } = require('..')
1
+ import assert from 'node:assert'
2
+ import { test } from 'node:test'
3
+ import { client, collectMetrics } from '../index.js'
6
4
 
7
5
  const nextTick = () => new Promise(resolve => process.nextTick(resolve))
8
6