diff --git a/plugins/node/instrumentation-runtime-node/test/event_loop_lag.test.ts b/plugins/node/instrumentation-runtime-node/test/event_loop_lag.test.ts new file mode 100644 index 0000000000..9fb948e9d0 --- /dev/null +++ b/plugins/node/instrumentation-runtime-node/test/event_loop_lag.test.ts @@ -0,0 +1,75 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { MeterProvider, DataPointType } from '@opentelemetry/sdk-metrics'; + +import { RuntimeNodeInstrumentation } from '../src'; +import * as assert from 'assert'; +import { TestMetricReader } from './testMetricsReader'; +import { metricNames } from '../src/metrics/eventLoopLagCollector'; + +const MEASUREMENT_INTERVAL = 10; + +describe('nodejs.event_loop.lag', function () { + let metricReader: TestMetricReader; + let meterProvider: MeterProvider; + + beforeEach(() => { + metricReader = new TestMetricReader(); + meterProvider = new MeterProvider(); + meterProvider.addMetricReader(metricReader); + }); + + for (const metricName of metricNames) { + it(`should write nodejs.${metricName.name} after monitoringPrecision`, async function () { + // arrange + const instrumentation = new RuntimeNodeInstrumentation({ + monitoringPrecision: MEASUREMENT_INTERVAL, + }); + instrumentation.setMeterProvider(meterProvider); + + // act + await new Promise(resolve => + setTimeout(resolve, MEASUREMENT_INTERVAL * 5) + ); + const { resourceMetrics, errors } = await metricReader.collect(); + + // assert + assert.deepEqual( + errors, + [], + 'expected no errors from the callback during collection' + ); + const scopeMetrics = resourceMetrics.scopeMetrics; + const metric = scopeMetrics[0].metrics.find( + x => x.descriptor.name === 'nodejs.' + metricName.name + ); + + assert.notEqual(metric, undefined, `nodejs.${metricName.name} not found`); + + assert.strictEqual( + metric!.dataPointType, + DataPointType.GAUGE, + 'expected gauge' + ); + + assert.strictEqual( + metric!.descriptor.name, + 'nodejs.' + metricName.name, + 'descriptor.name' + ); + }); + } +}); diff --git a/plugins/node/instrumentation-runtime-node/test/event_loop_utilization.test.ts b/plugins/node/instrumentation-runtime-node/test/event_loop_utilization.test.ts index ccc3a04ff7..78d4cde2d0 100644 --- a/plugins/node/instrumentation-runtime-node/test/event_loop_utilization.test.ts +++ b/plugins/node/instrumentation-runtime-node/test/event_loop_utilization.test.ts @@ -13,27 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - MeterProvider, - DataPointType, - MetricReader, -} from '@opentelemetry/sdk-metrics'; +import { MeterProvider, DataPointType } from '@opentelemetry/sdk-metrics'; import { RuntimeNodeInstrumentation } from '../src'; import * as assert from 'assert'; +import { TestMetricReader } from './testMetricsReader'; const MEASUREMENT_INTERVAL = 10; -class TestMetricReader extends MetricReader { - constructor() { - super(); - } - - protected async onForceFlush(): Promise {} - - protected async onShutdown(): Promise {} -} - describe('nodejs.event_loop.utilization', function () { let metricReader: TestMetricReader; let meterProvider: MeterProvider; @@ -47,7 +34,7 @@ describe('nodejs.event_loop.utilization', function () { it('should not export before being enabled', async function () { // arrange const instrumentation = new RuntimeNodeInstrumentation({ - eventLoopUtilizationMeasurementInterval: MEASUREMENT_INTERVAL, + monitoringPrecision: MEASUREMENT_INTERVAL, enabled: false, }); instrumentation.setMeterProvider(meterProvider); @@ -62,32 +49,10 @@ describe('nodejs.event_loop.utilization', function () { assert.strictEqual(scopeMetrics.length, 0); }); - it('should not record result when collecting immediately with custom config', async function () { - const instrumentation = new RuntimeNodeInstrumentation({ - eventLoopUtilizationMeasurementInterval: MEASUREMENT_INTERVAL, - }); - instrumentation.setMeterProvider(meterProvider); - - assert.deepEqual( - (await metricReader.collect()).resourceMetrics.scopeMetrics, - [] - ); - }); - - it('should not record result when collecting immediately with default config', async function () { - const instrumentation = new RuntimeNodeInstrumentation(); - instrumentation.setMeterProvider(meterProvider); - - assert.deepEqual( - (await metricReader.collect()).resourceMetrics.scopeMetrics, - [] - ); - }); - - it('should write event loop utilization metrics after eventLoopUtilizationMeasurementInterval', async function () { + it('should write event loop utilization metrics after monitoringPrecision', async function () { // arrange const instrumentation = new RuntimeNodeInstrumentation({ - eventLoopUtilizationMeasurementInterval: MEASUREMENT_INTERVAL, + monitoringPrecision: MEASUREMENT_INTERVAL, }); instrumentation.setMeterProvider(meterProvider); @@ -102,42 +67,42 @@ describe('nodejs.event_loop.utilization', function () { 'expected no errors from the callback during collection' ); const scopeMetrics = resourceMetrics.scopeMetrics; - assert.strictEqual( - scopeMetrics.length, - 1, - 'expected one scope (one meter created by instrumentation)' - ); - const metrics = scopeMetrics[0].metrics; - assert.strictEqual( - metrics.length, - 1, - 'expected one metric (one metric created by instrumentation)' + const utilizationMetric = scopeMetrics[0].metrics.find( + x => x.descriptor.name === 'nodejs.event_loop.utilization' ); + + assert.notEqual(utilizationMetric, undefined, 'metric not found'); + assert.strictEqual( - metrics[0].dataPointType, + utilizationMetric!.dataPointType, DataPointType.GAUGE, 'expected gauge' ); + assert.strictEqual( - metrics[0].descriptor.name, + utilizationMetric!.descriptor.name, 'nodejs.event_loop.utilization', 'descriptor.name' ); + assert.strictEqual( - metrics[0].descriptor.description, + utilizationMetric!.descriptor.description, 'Event loop utilization' ); + assert.strictEqual( - metrics[0].descriptor.unit, + utilizationMetric!.descriptor.unit, '1', 'expected default unit' ); + assert.strictEqual( - metrics[0].dataPoints.length, + utilizationMetric!.dataPoints.length, 1, 'expected one data point' ); - const val = metrics[0].dataPoints[0].value; + + const val = utilizationMetric!.dataPoints[0].value; assert.strictEqual(val > 0, true, `val (${val}) > 0`); assert.strictEqual(val <= 1, true, `val (${val}) <= 1`); }); diff --git a/plugins/node/instrumentation-runtime-node/test/heap_size_and_used.test.ts b/plugins/node/instrumentation-runtime-node/test/heap_size_and_used.test.ts new file mode 100644 index 0000000000..731c105874 --- /dev/null +++ b/plugins/node/instrumentation-runtime-node/test/heap_size_and_used.test.ts @@ -0,0 +1,75 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { MeterProvider, DataPointType } from '@opentelemetry/sdk-metrics'; + +import { RuntimeNodeInstrumentation } from '../src'; +import * as assert from 'assert'; +import { TestMetricReader } from './testMetricsReader'; +import { metricNames } from '../src/metrics/heapSizeAndUsedCollector'; + +const MEASUREMENT_INTERVAL = 10; + +describe('nodejs.heap_size', function () { + let metricReader: TestMetricReader; + let meterProvider: MeterProvider; + + beforeEach(() => { + metricReader = new TestMetricReader(); + meterProvider = new MeterProvider(); + meterProvider.addMetricReader(metricReader); + }); + + for (const metricName of metricNames) { + it(`should write nodejs.${metricName.name} after monitoringPrecision`, async function () { + // arrange + const instrumentation = new RuntimeNodeInstrumentation({ + monitoringPrecision: MEASUREMENT_INTERVAL, + }); + instrumentation.setMeterProvider(meterProvider); + + // act + await new Promise(resolve => + setTimeout(resolve, MEASUREMENT_INTERVAL * 5) + ); + const { resourceMetrics, errors } = await metricReader.collect(); + + // assert + assert.deepEqual( + errors, + [], + 'expected no errors from the callback during collection' + ); + const scopeMetrics = resourceMetrics.scopeMetrics; + const metric = scopeMetrics[0].metrics.find( + x => x.descriptor.name === 'nodejs.' + metricName.name + ); + + assert.notEqual(metric, undefined, `nodejs.${metricName.name} not found`); + + assert.strictEqual( + metric!.dataPointType, + DataPointType.GAUGE, + 'expected gauge' + ); + + assert.strictEqual( + metric!.descriptor.name, + 'nodejs.' + metricName.name, + 'descriptor.name' + ); + }); + } +}); diff --git a/plugins/node/instrumentation-runtime-node/test/heap_space_and_used.test.ts b/plugins/node/instrumentation-runtime-node/test/heap_space_and_used.test.ts new file mode 100644 index 0000000000..aabefb64f9 --- /dev/null +++ b/plugins/node/instrumentation-runtime-node/test/heap_space_and_used.test.ts @@ -0,0 +1,75 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { MeterProvider, DataPointType } from '@opentelemetry/sdk-metrics'; + +import { RuntimeNodeInstrumentation } from '../src'; +import * as assert from 'assert'; +import { TestMetricReader } from './testMetricsReader'; +import { metricNames } from '../src/metrics/heapSpacesSizeAndUsedCollector'; + +const MEASUREMENT_INTERVAL = 10; + +describe('nodejs.heap_space', function () { + let metricReader: TestMetricReader; + let meterProvider: MeterProvider; + + beforeEach(() => { + metricReader = new TestMetricReader(); + meterProvider = new MeterProvider(); + meterProvider.addMetricReader(metricReader); + }); + + for (const metricName of metricNames) { + it(`should write nodejs.${metricName.name} after monitoringPrecision`, async function () { + // arrange + const instrumentation = new RuntimeNodeInstrumentation({ + monitoringPrecision: MEASUREMENT_INTERVAL, + }); + instrumentation.setMeterProvider(meterProvider); + + // act + await new Promise(resolve => + setTimeout(resolve, MEASUREMENT_INTERVAL * 5) + ); + const { resourceMetrics, errors } = await metricReader.collect(); + + // assert + assert.deepEqual( + errors, + [], + 'expected no errors from the callback during collection' + ); + const scopeMetrics = resourceMetrics.scopeMetrics; + const metric = scopeMetrics[0].metrics.find( + x => x.descriptor.name === 'nodejs.' + metricName.name + ); + + assert.notEqual(metric, undefined, `nodejs.${metricName.name} not found`); + + assert.strictEqual( + metric!.dataPointType, + DataPointType.GAUGE, + 'expected gauge' + ); + + assert.strictEqual( + metric!.descriptor.name, + 'nodejs.' + metricName.name, + 'descriptor.name' + ); + }); + } +}); diff --git a/plugins/node/instrumentation-runtime-node/test/instrumentation.test.ts b/plugins/node/instrumentation-runtime-node/test/instrumentation.test.ts new file mode 100644 index 0000000000..615e232eed --- /dev/null +++ b/plugins/node/instrumentation-runtime-node/test/instrumentation.test.ts @@ -0,0 +1,107 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { MeterProvider } from '@opentelemetry/sdk-metrics'; + +import { RuntimeNodeInstrumentation } from '../src'; +import * as assert from 'assert'; +import { TestMetricReader } from './testMetricsReader'; + +const MEASUREMENT_INTERVAL = 10; + +describe('instrumentation', function () { + let metricReader: TestMetricReader; + let meterProvider: MeterProvider; + + beforeEach(() => { + metricReader = new TestMetricReader(); + meterProvider = new MeterProvider(); + meterProvider.addMetricReader(metricReader); + }); + + it('should not export before being enabled', async function () { + // arrange + const instrumentation = new RuntimeNodeInstrumentation({ + monitoringPrecision: MEASUREMENT_INTERVAL, + enabled: false, + }); + instrumentation.setMeterProvider(meterProvider); + + // act + await new Promise(resolve => setTimeout(resolve, MEASUREMENT_INTERVAL * 5)); + const { resourceMetrics, errors } = await metricReader.collect(); + + // assert + assert.deepEqual(errors, []); + const scopeMetrics = resourceMetrics.scopeMetrics; + assert.strictEqual(scopeMetrics.length, 0); + }); + + it('should export after being enabled', async function () { + // arrange + const instrumentation = new RuntimeNodeInstrumentation({ + monitoringPrecision: MEASUREMENT_INTERVAL, + enabled: false, + }); + instrumentation.setMeterProvider(meterProvider); + + // act + await new Promise(resolve => setTimeout(resolve, MEASUREMENT_INTERVAL * 5)); + const firstCollections = await metricReader.collect(); + + // assert + assert.deepEqual(firstCollections.errors, []); + const scopeMetrics = firstCollections.resourceMetrics.scopeMetrics; + assert.strictEqual(scopeMetrics.length, 0); + + instrumentation.enable(); + await new Promise(resolve => setTimeout(resolve, MEASUREMENT_INTERVAL * 5)); + + const secondCollection = await metricReader.collect(); + assert.deepEqual( + secondCollection.errors, + [], + 'expected no errors from the callback during collection' + ); + const secondScopeMetrics = secondCollection.resourceMetrics.scopeMetrics; + assert.strictEqual( + secondScopeMetrics.length, + 1, + 'expected one scope (one meter created by instrumentation)' + ); + }); + + it('should not record result when collecting immediately with custom config', async function () { + const instrumentation = new RuntimeNodeInstrumentation({ + monitoringPrecision: MEASUREMENT_INTERVAL, + }); + instrumentation.setMeterProvider(meterProvider); + + assert.deepEqual( + (await metricReader.collect()).resourceMetrics.scopeMetrics, + [] + ); + }); + + it('should not record result when collecting immediately with default config', async function () { + const instrumentation = new RuntimeNodeInstrumentation(); + instrumentation.setMeterProvider(meterProvider); + + assert.deepEqual( + (await metricReader.collect()).resourceMetrics.scopeMetrics, + [] + ); + }); +}); diff --git a/plugins/node/instrumentation-runtime-node/test/testMetricsReader.ts b/plugins/node/instrumentation-runtime-node/test/testMetricsReader.ts new file mode 100644 index 0000000000..f40d1d7382 --- /dev/null +++ b/plugins/node/instrumentation-runtime-node/test/testMetricsReader.ts @@ -0,0 +1,25 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { MetricReader } from '@opentelemetry/sdk-metrics'; +export class TestMetricReader extends MetricReader { + constructor() { + super(); + } + + protected async onForceFlush(): Promise {} + + protected async onShutdown(): Promise {} +}