Skip to content

Commit b9e49b1

Browse files
committed
perf_hooks: move metrics under perf_hooks
1 parent 5023771 commit b9e49b1

12 files changed

Lines changed: 213 additions & 28 deletions

doc/api/metrics.md

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@
44

55
> Stability: 1 - Experimental
66
7-
<!-- source_link=lib/metrics.js -->
7+
<!-- source_link=lib/internal/perf/metrics.js -->
88

9-
The `node:metrics` module provides an API for application instrumentation and
9+
The metrics API provides an API for application instrumentation and
1010
performance monitoring. It offers various metric types and built-in exporters
1111
for popular monitoring systems.
1212

13-
The module can be accessed using:
13+
The metrics API can be accessed using:
1414

1515
```mjs
16-
import * as metrics from 'node:metrics';
16+
import { metrics } from 'node:perf_hooks';
1717
```
1818

1919
```cjs
20-
const metrics = require('node:metrics');
20+
const { metrics } = require('node:perf_hooks');
2121
```
2222

2323
## Overview
@@ -30,7 +30,8 @@ flexible consumption patterns.
3030
### Example
3131

3232
```mjs
33-
import { counter } from 'node:metrics';
33+
import { metrics } from 'node:perf_hooks';
34+
const { counter } = metrics;
3435

3536
// Create counter metrics
3637
const apiCalls = counter('api.calls', { service: 'web' });
@@ -49,7 +50,8 @@ function handleRequest(req, res) {
4950
```
5051

5152
```cjs
52-
const { counter } = require('node:metrics');
53+
const { metrics } = require('node:perf_hooks');
54+
const { counter } = metrics;
5355

5456
// Create counter metrics
5557
const apiCalls = counter('api.calls', { service: 'web' });
@@ -82,7 +84,8 @@ added: REPLACEME
8284
Creates a counter metric that tracks cumulative values.
8385

8486
```mjs
85-
import { counter } from 'node:metrics';
87+
import { metrics } from 'node:perf_hooks';
88+
const { counter } = metrics;
8689

8790
const errorCount = counter('errors.total', { component: 'database' });
8891

@@ -105,7 +108,8 @@ added: REPLACEME
105108
Creates a gauge metric that represents a single value at a point in time.
106109

107110
```mjs
108-
import { gauge } from 'node:metrics';
111+
import { metrics } from 'node:perf_hooks';
112+
const { gauge } = metrics;
109113
import { memoryUsage } from 'node:process';
110114

111115
const memory = gauge('memory.usage.bytes');
@@ -128,7 +132,8 @@ added: REPLACEME
128132
Creates a gauge that samples a value on-demand by calling the provided function.
129133

130134
```mjs
131-
import { pullGauge } from 'node:metrics';
135+
import { metrics } from 'node:perf_hooks';
136+
const { pullGauge } = metrics;
132137
import { cpuUsage } from 'node:process';
133138

134139
const cpu = pullGauge('cpu.usage', () => {
@@ -292,7 +297,8 @@ specific methods provided by each metric type (e.g., `increment`, `reset`,
292297
metadata.
293298

294299
```mjs
295-
import { gauge } from 'node:metrics';
300+
import { metrics } from 'node:perf_hooks';
301+
const { gauge } = metrics;
296302

297303
const memoryUsage = gauge('memory.usage', { service: 'web' });
298304

@@ -332,7 +338,8 @@ added: REPLACEME
332338
Increments the counter by the specified amount.
333339

334340
```mjs
335-
import { counter } from 'node:metrics';
341+
import { metrics } from 'node:perf_hooks';
342+
const { counter } = metrics;
336343

337344
const apiCalls = counter('api.calls', { service: 'web' });
338345

@@ -354,7 +361,8 @@ added: REPLACEME
354361
Decrements the counter by the specified amount.
355362

356363
```mjs
357-
import { counter } from 'node:metrics';
364+
import { metrics } from 'node:perf_hooks';
365+
const { counter } = metrics;
358366

359367
const errorCount = counter('errors.total', { component: 'database' });
360368

@@ -376,7 +384,8 @@ added: REPLACEME
376384
Creates a timer that will increment this counter with its duration when stopped.
377385

378386
```mjs
379-
import { counter } from 'node:metrics';
387+
import { metrics } from 'node:perf_hooks';
388+
const { counter } = metrics;
380389

381390
const requestDuration = counter('request.duration.ms');
382391

@@ -417,7 +426,8 @@ added: REPLACEME
417426
Sets the gauge to a specific value and reports it.
418427

419428
```mjs
420-
import { gauge } from 'node:metrics';
429+
import { metrics } from 'node:perf_hooks';
430+
const { gauge } = metrics;
421431
import { memoryUsage } from 'node:process';
422432

423433
const memory = gauge('memory.usage.bytes');
@@ -439,7 +449,8 @@ added: REPLACEME
439449
Creates a timer that will set this gauge to its duration when stopped.
440450

441451
```mjs
442-
import { gauge } from 'node:metrics';
452+
import { metrics } from 'node:perf_hooks';
453+
const { gauge } = metrics;
443454

444455
const responseTime = gauge('response.time.ms');
445456

@@ -497,7 +508,8 @@ added: REPLACEME
497508
Stops the timer and reports the duration. Can only be called once.
498509

499510
```mjs
500-
import { counter } from 'node:metrics';
511+
import { metrics } from 'node:perf_hooks';
512+
const { counter } = metrics;
501513

502514
const dbQueryDuration = counter('db.query.duration');
503515

@@ -518,7 +530,8 @@ added: REPLACEME
518530
Allows `using` syntax to automatically stop the timer when done.
519531

520532
```mjs
521-
import { counter } from 'node:metrics';
533+
import { metrics } from 'node:perf_hooks';
534+
const { counter } = metrics;
522535

523536
const dbQueryDuration = counter('db.query.duration');
524537

@@ -553,7 +566,8 @@ added: REPLACEME
553566
Calls the configured function to get the current value and reports it.
554567

555568
```mjs
556-
import { pullGauge } from 'node:metrics';
569+
import { metrics } from 'node:perf_hooks';
570+
const { pullGauge } = metrics;
557571
import { cpuUsage } from 'node:process';
558572

559573
const cpu = pullGauge('cpu.usage', () => {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const {
3939
subscribe,
4040
unsubscribe,
4141
} = require('diagnostics_channel');
42-
const { performance } = require('perf_hooks');
42+
const { performance } = require('internal/perf/performance');
4343

4444
const newMetricChannel = channel('metrics:new');
4545

lib/perf_hooks.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ const {
2929

3030
const monitorEventLoopDelay = require('internal/perf/event_loop_delay');
3131

32+
const metrics = require('internal/perf/metrics');
33+
3234
module.exports = {
3335
Performance,
3436
PerformanceEntry,
@@ -40,6 +42,7 @@ module.exports = {
4042
monitorEventLoopDelay,
4143
createHistogram,
4244
performance,
45+
metrics,
4346
};
4447

4548
ObjectDefineProperty(module.exports, 'constants', {

test/parallel/test-metrics-counter.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const common = require('../common');
44

55
const assert = require('assert');
66
const { subscribe } = require('node:diagnostics_channel');
7-
const { counter, Counter, Metric, MetricReport } = require('node:metrics');
7+
const { metrics } = require('node:perf_hooks');
8+
const { counter, Counter, Metric, MetricReport } = metrics;
89

910
const testCounter = counter('test', { base: 'test' });
1011
assert.ok(testCounter instanceof Counter);

test/parallel/test-metrics-gauge.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const common = require('../common');
44

55
const assert = require('assert');
66
const { subscribe } = require('node:diagnostics_channel');
7-
const { gauge, Gauge, Metric, MetricReport } = require('node:metrics');
7+
const { metrics } = require('node:perf_hooks');
8+
const { gauge, Gauge, Metric, MetricReport } = metrics;
89

910
const testGauge = gauge('test', { base: 'test' });
1011
assert.ok(testGauge instanceof Gauge);

test/parallel/test-metrics-metric-report.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
require('../common');
44

55
const assert = require('assert');
6-
const { MetricReport } = require('node:metrics');
6+
const { metrics } = require('node:perf_hooks');
7+
const { MetricReport } = metrics;
78

89
const report = new MetricReport('counter', 'test-counter', 123, {
910
meta: 'test'

test/parallel/test-metrics-metric.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const common = require('../common');
44

55
const assert = require('assert');
66
const { subscribe } = require('node:diagnostics_channel');
7-
const { Metric, MetricReport } = require('node:metrics');
7+
const { metrics } = require('node:perf_hooks');
8+
const { Metric, MetricReport } = metrics;
89

910
const metric = new Metric('counter', 'test-counter', { base: 'test' });
1011

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
5+
const assert = require('assert');
6+
const { subscribe } = require('node:diagnostics_channel');
7+
const { metrics } = require('node:perf_hooks');
8+
const { pullGauge, PullGauge, Metric, MetricReport } = metrics;
9+
10+
// Test values to return from the pull function
11+
const values = [ 1, 5, 10, 4, 6 ];
12+
let currentIndex = 0;
13+
14+
const testPullGauge = pullGauge('test', () => {
15+
return values[currentIndex];
16+
}, { base: 'test' });
17+
18+
assert.ok(testPullGauge instanceof PullGauge);
19+
assert.ok(testPullGauge instanceof Metric);
20+
assert.strictEqual(testPullGauge.value, 0);
21+
22+
assert.strictEqual(testPullGauge.type, 'pullGauge');
23+
assert.strictEqual(testPullGauge.name, 'test');
24+
assert.deepStrictEqual(testPullGauge.meta, { base: 'test' });
25+
assert.strictEqual(testPullGauge.channelName, 'metrics:pullGauge:test');
26+
27+
// Subscribe to metric reports
28+
let reportCount = 0;
29+
subscribe(testPullGauge.channelName, common.mustCall((report) => {
30+
assert.ok(report instanceof MetricReport);
31+
assert.strictEqual(report.type, 'pullGauge');
32+
assert.strictEqual(report.name, 'test');
33+
assert.ok(report.time > 0);
34+
assert.strictEqual(report.value, values[reportCount]);
35+
36+
if (reportCount < values.length - 1) {
37+
assert.deepStrictEqual(report.meta, { base: 'test' });
38+
} else {
39+
// Last sample includes additional metadata
40+
assert.deepStrictEqual(report.meta, { base: 'test', extra: 'metadata' });
41+
}
42+
43+
reportCount++;
44+
}, values.length));
45+
46+
// Test sampling
47+
for (let i = 0; i < values.length; i++) {
48+
currentIndex = i;
49+
50+
if (i === values.length - 1) {
51+
// Test sampling with additional metadata
52+
const value = testPullGauge.sample({ extra: 'metadata' });
53+
assert.strictEqual(value, values[i]);
54+
} else {
55+
const value = testPullGauge.sample();
56+
assert.strictEqual(value, values[i]);
57+
}
58+
}
59+
60+
// Verify all reports were received
61+
assert.strictEqual(reportCount, values.length);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const { metrics } = require('node:perf_hooks');
6+
const { Timer } = metrics;
7+
8+
// Test that Timer properties are read-only
9+
const timer = new Timer(() => {});
10+
11+
// Verify initial values
12+
assert.ok(typeof timer.start === 'number');
13+
assert.ok(timer.start > 0);
14+
assert.strictEqual(timer.end, undefined);
15+
assert.strictEqual(timer.duration, undefined);
16+
17+
// Try to modify properties (should throw)
18+
const originalStart = timer.start;
19+
assert.throws(() => {
20+
timer.start = 0;
21+
}, TypeError);
22+
assert.strictEqual(timer.start, originalStart); // Should remain unchanged
23+
24+
assert.throws(() => {
25+
timer.end = 123;
26+
}, TypeError);
27+
assert.strictEqual(timer.end, undefined); // Should remain undefined
28+
29+
assert.throws(() => {
30+
timer.duration = 456;
31+
}, TypeError);
32+
assert.strictEqual(timer.duration, undefined); // Should remain undefined
33+
34+
// Stop the timer and verify values are still read-only
35+
timer.stop();
36+
assert.ok(typeof timer.end === 'number');
37+
assert.ok(typeof timer.duration === 'number');
38+
assert.ok(timer.end > timer.start);
39+
assert.ok(timer.duration > 0);
40+
41+
// Try to modify after stopping (should throw)
42+
const stoppedEnd = timer.end;
43+
const stoppedDuration = timer.duration;
44+
assert.throws(() => {
45+
timer.end = 0;
46+
}, TypeError);
47+
assert.throws(() => {
48+
timer.duration = 0;
49+
}, TypeError);
50+
assert.strictEqual(timer.end, stoppedEnd);
51+
assert.strictEqual(timer.duration, stoppedDuration);

0 commit comments

Comments
 (0)