Skip to content

Commit b0c20ee

Browse files
committed
test(instr-runtime-node): add tests for gcDurationBuckets config
Add tests verifying that the GC duration histogram is created correctly with both default and custom bucket boundaries.
1 parent c627f76 commit b0c20ee

File tree

2 files changed

+133
-1
lines changed

2 files changed

+133
-1
lines changed

packages/instrumentation-runtime-node/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"compile": "tsc -p .",
1616
"compile:with-dependencies": "nx run-many -t compile -p @opentelemetry/instrumentation-runtime-node",
1717
"prepublishOnly": "npm run compile",
18-
"test": "nyc --no-clean mocha 'test/**/*.test.ts'",
18+
"test": "nyc --no-clean mocha --expose-gc 'test/**/*.test.ts'",
1919
"version:update": "node ../../scripts/version-update.js"
2020
},
2121
"author": "OpenTelemetry Authors",
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as assert from 'assert';
18+
import { MeterProvider, DataPointType } from '@opentelemetry/sdk-metrics';
19+
import { RuntimeNodeInstrumentation } from '../src';
20+
import { TestMetricReader } from './testMetricsReader';
21+
import { METRIC_V8JS_GC_DURATION } from '../src/semconv';
22+
23+
const MEASUREMENT_INTERVAL = 10;
24+
25+
// Helper to trigger GC by allocating memory
26+
function triggerGC() {
27+
const arrays = [];
28+
for (let i = 0; i < 100; i++) {
29+
arrays.push(new Array(10000).fill(i));
30+
}
31+
// Allow garbage collection by clearing references
32+
arrays.length = 0;
33+
if (global.gc) {
34+
global.gc();
35+
}
36+
}
37+
38+
describe('v8js.gc.duration', function () {
39+
let metricReader: TestMetricReader;
40+
let meterProvider: MeterProvider;
41+
let instrumentation: RuntimeNodeInstrumentation;
42+
43+
beforeEach(() => {
44+
metricReader = new TestMetricReader();
45+
meterProvider = new MeterProvider({
46+
readers: [metricReader],
47+
});
48+
});
49+
50+
afterEach(() => {
51+
instrumentation.disable();
52+
});
53+
54+
it('should create histogram with default gcDurationBuckets', async function () {
55+
// arrange
56+
instrumentation = new RuntimeNodeInstrumentation({
57+
monitoringPrecision: MEASUREMENT_INTERVAL,
58+
});
59+
instrumentation.setMeterProvider(meterProvider);
60+
61+
// act - trigger GC
62+
triggerGC();
63+
await new Promise(resolve =>
64+
setTimeout(resolve, MEASUREMENT_INTERVAL * 10)
65+
);
66+
triggerGC();
67+
await new Promise(resolve => setTimeout(resolve, MEASUREMENT_INTERVAL * 5));
68+
69+
const { resourceMetrics, errors } = await metricReader.collect();
70+
71+
// assert
72+
assert.deepEqual(
73+
errors,
74+
[],
75+
'expected no errors from the callback during collection'
76+
);
77+
const scopeMetrics = resourceMetrics.scopeMetrics;
78+
const metric = scopeMetrics[0]?.metrics.find(
79+
x => x.descriptor.name === METRIC_V8JS_GC_DURATION
80+
);
81+
82+
assert.notEqual(metric, undefined, `${METRIC_V8JS_GC_DURATION} not found`);
83+
assert.strictEqual(
84+
metric!.dataPointType,
85+
DataPointType.HISTOGRAM,
86+
'expected histogram'
87+
);
88+
assert.strictEqual(
89+
metric!.descriptor.unit,
90+
's',
91+
'expected unit to be seconds'
92+
);
93+
});
94+
95+
it('should allow custom gcDurationBuckets configuration', async function () {
96+
// arrange
97+
const customBuckets = [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1];
98+
instrumentation = new RuntimeNodeInstrumentation({
99+
monitoringPrecision: MEASUREMENT_INTERVAL,
100+
gcDurationBuckets: customBuckets,
101+
});
102+
instrumentation.setMeterProvider(meterProvider);
103+
104+
// act - trigger GC
105+
triggerGC();
106+
await new Promise(resolve =>
107+
setTimeout(resolve, MEASUREMENT_INTERVAL * 10)
108+
);
109+
triggerGC();
110+
await new Promise(resolve => setTimeout(resolve, MEASUREMENT_INTERVAL * 5));
111+
112+
const { resourceMetrics, errors } = await metricReader.collect();
113+
114+
// assert
115+
assert.deepEqual(
116+
errors,
117+
[],
118+
'expected no errors from the callback during collection'
119+
);
120+
const scopeMetrics = resourceMetrics.scopeMetrics;
121+
const metric = scopeMetrics[0]?.metrics.find(
122+
x => x.descriptor.name === METRIC_V8JS_GC_DURATION
123+
);
124+
125+
assert.notEqual(metric, undefined, `${METRIC_V8JS_GC_DURATION} not found`);
126+
assert.strictEqual(
127+
metric!.dataPointType,
128+
DataPointType.HISTOGRAM,
129+
'expected histogram'
130+
);
131+
});
132+
});

0 commit comments

Comments
 (0)