opentelemetry-js/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MeterSharedState.test.ts

187 lines
6.6 KiB
TypeScript

/*
* 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 * as assert from 'assert';
import * as sinon from 'sinon';
import {
AggregationTemporality,
Meter,
MeterProvider,
DataPointType,
ResourceMetrics
} from '../../src';
import { assertMetricData, defaultInstrumentationScope, defaultResource, sleep } from '../util';
import { TestMetricReader } from '../export/TestMetricReader';
import { MeterSharedState } from '../../src/state/MeterSharedState';
describe('MeterSharedState', () => {
afterEach(() => {
sinon.restore();
});
describe('collect', () => {
function setupInstruments() {
const meterProvider = new MeterProvider({ resource: defaultResource });
const cumulativeReader = new TestMetricReader(() => AggregationTemporality.CUMULATIVE);
meterProvider.addMetricReader(cumulativeReader);
const cumulativeCollector = cumulativeReader.getMetricCollector();
const deltaReader = new TestMetricReader(() => AggregationTemporality.DELTA);
meterProvider.addMetricReader(deltaReader);
const deltaCollector = deltaReader.getMetricCollector();
const metricCollectors = [cumulativeCollector, deltaCollector];
const meter = meterProvider.getMeter(defaultInstrumentationScope.name, defaultInstrumentationScope.version, {
schemaUrl: defaultInstrumentationScope.schemaUrl,
}) as Meter;
const meterSharedState = meter['_meterSharedState'] as MeterSharedState;
return { metricCollectors, cumulativeCollector, deltaCollector, meter, meterSharedState, meterProvider };
}
it('should collect sync metrics', async () => {
/** preparing test instrumentations */
const { metricCollectors, meter } = setupInstruments();
/** creating metric events */
const counter = meter.createCounter('test');
/** collect metrics */
counter.add(1);
await Promise.all(metricCollectors.map(async collector => {
const result = await collector.collect();
assert.strictEqual(result.scopeMetrics.length, 1);
assert.strictEqual(result.scopeMetrics[0].metrics.length, 1);
assertMetricData(result.scopeMetrics[0].metrics[0], DataPointType.SINGULAR, {
name: 'test',
});
}));
});
it('should collect sync metrics with views', async () => {
/** preparing test instrumentations */
const { metricCollectors, meter, meterProvider } = setupInstruments();
/** creating metric events */
meterProvider.addView({ name: 'foo' }, { instrument: { name: 'test' } });
meterProvider.addView({ name: 'bar' }, { instrument: { name: 'test' } });
const counter = meter.createCounter('test');
/** collect metrics */
counter.add(1);
await Promise.all(metricCollectors.map(async collector => {
const result = await collector.collect();
assert.strictEqual(result.scopeMetrics.length, 1);
assert.strictEqual(result.scopeMetrics[0].metrics.length, 2);
assertMetricData(result.scopeMetrics[0].metrics[0], DataPointType.SINGULAR, {
name: 'foo',
});
assertMetricData(result.scopeMetrics[0].metrics[1], DataPointType.SINGULAR, {
name: 'bar',
});
}));
});
it('should collect async metrics with callbacks', async () => {
/** preparing test instrumentations */
const { metricCollectors, meter } = setupInstruments();
/** creating metric events */
let observableCalledCount = 0;
meter.createObservableCounter('test', observableResult => {
observableCalledCount++;
observableResult.observe(1);
// async observers.
return sleep(10);
});
/** collect metrics */
await Promise.all([
// initiate collection concurrently.
...metricCollectors.map(collector => collector.collect()),
sleep(1).then(() => metricCollectors[0].collect()),
]);
// the callback is called each time the collection initiated.
assert.strictEqual(observableCalledCount, 3);
/** collect metrics */
await Promise.all([
// initiate collection concurrently.
...metricCollectors.map(collector => collector.collect()),
sleep(1).then(() => metricCollectors[0].collect()),
]);
assert.strictEqual(observableCalledCount, 6);
});
it('should call observable callback with view-ed async instruments', async () => {
/** preparing test instrumentations */
const { metricCollectors, meter, meterProvider } = setupInstruments();
/** creating metric events */
meterProvider.addView({ name: 'foo' }, {
instrument: {
name: 'test',
},
});
meterProvider.addView({ name: 'bar' }, {
instrument: {
name: 'test',
},
});
let observableCalledCount = 0;
meter.createObservableCounter('test', observableResult => {
observableCalledCount++;
observableResult.observe(1);
// async observers.
return sleep(10);
});
function verifyResult(resourceMetrics: ResourceMetrics) {
assert.strictEqual(resourceMetrics.scopeMetrics.length, 1);
assert.strictEqual(resourceMetrics.scopeMetrics[0].metrics.length, 2);
assertMetricData(resourceMetrics.scopeMetrics[0].metrics[0], DataPointType.SINGULAR, {
name: 'foo'
});
assertMetricData(resourceMetrics.scopeMetrics[0].metrics[1], DataPointType.SINGULAR, {
name: 'bar'
});
}
/** collect metrics */
await Promise.all([
// initiate collection concurrently.
...metricCollectors.map(collector => collector.collect().then(verifyResult)),
sleep(1).then(() => metricCollectors[0].collect().then(verifyResult)),
]);
assert.strictEqual(observableCalledCount, 6);
/** collect metrics */
await Promise.all([
// initiate collection concurrently.
...metricCollectors.map(collector => collector.collect().then(verifyResult)),
sleep(1).then(() => metricCollectors[0].collect().then(verifyResult)),
]);
assert.strictEqual(observableCalledCount, 12);
});
});
});