884 lines
24 KiB
TypeScript
884 lines
24 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 { InstrumentationScope } from '@opentelemetry/core';
|
|
import { Resource } from '@opentelemetry/resources';
|
|
import {
|
|
DataPoint,
|
|
DataPointType,
|
|
Histogram,
|
|
InstrumentType,
|
|
MeterProvider,
|
|
} from '../src';
|
|
import { InstrumentDescriptor } from '../src/InstrumentDescriptor';
|
|
import {
|
|
TestDeltaMetricReader,
|
|
TestMetricReader,
|
|
} from './export/TestMetricReader';
|
|
import {
|
|
assertDataPoint,
|
|
assertMetricData,
|
|
commonAttributes,
|
|
commonValues,
|
|
defaultInstrumentationScope,
|
|
defaultResource,
|
|
} from './util';
|
|
import { ObservableResult, ValueType } from '@opentelemetry/api';
|
|
import { IMetricReader } from '../src/export/MetricReader';
|
|
|
|
describe('Instruments', () => {
|
|
describe('Counter', () => {
|
|
it('should add common values and attributes without exceptions', async () => {
|
|
const { meter, cumulativeReader } = setup();
|
|
const counter = meter.createCounter('test', {
|
|
description: 'foobar',
|
|
unit: 'kB',
|
|
});
|
|
|
|
for (const values of commonValues) {
|
|
for (const attributes of commonAttributes) {
|
|
counter.add(values, attributes);
|
|
}
|
|
}
|
|
|
|
await validateExport(cumulativeReader, {
|
|
descriptor: {
|
|
name: 'test',
|
|
description: 'foobar',
|
|
unit: 'kB',
|
|
type: InstrumentType.COUNTER,
|
|
valueType: ValueType.DOUBLE,
|
|
advice: {},
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should add valid INT values', async () => {
|
|
const { meter, cumulativeReader } = setup();
|
|
const counter = meter.createCounter('test', {
|
|
valueType: ValueType.INT,
|
|
});
|
|
|
|
counter.add(1);
|
|
counter.add(1, { foo: 'bar' });
|
|
// floating-point values should be trunc-ed.
|
|
counter.add(1.1);
|
|
// non-finite/non-number values should be ignored.
|
|
counter.add(Infinity);
|
|
counter.add(-Infinity);
|
|
counter.add(NaN);
|
|
counter.add('1' as any);
|
|
await validateExport(cumulativeReader, {
|
|
descriptor: {
|
|
name: 'test',
|
|
description: '',
|
|
unit: '',
|
|
type: InstrumentType.COUNTER,
|
|
valueType: ValueType.INT,
|
|
advice: {},
|
|
},
|
|
dataPointType: DataPointType.SUM,
|
|
isMonotonic: true,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 2,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 1,
|
|
},
|
|
],
|
|
});
|
|
|
|
// add negative values should not be observable.
|
|
counter.add(-1.1);
|
|
await validateExport(cumulativeReader, {
|
|
dataPointType: DataPointType.SUM,
|
|
isMonotonic: true,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 2,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 1,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('should add valid DOUBLE values', async () => {
|
|
const { meter, cumulativeReader } = setup();
|
|
const counter = meter.createCounter('test', {
|
|
valueType: ValueType.DOUBLE,
|
|
});
|
|
|
|
counter.add(1);
|
|
counter.add(1, { foo: 'bar' });
|
|
// add floating-point values.
|
|
counter.add(1.1);
|
|
counter.add(1.2, { foo: 'bar' });
|
|
// non-number values should be ignored.
|
|
counter.add('1' as any);
|
|
|
|
await validateExport(cumulativeReader, {
|
|
dataPointType: DataPointType.SUM,
|
|
isMonotonic: true,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 2.1,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 2.2,
|
|
},
|
|
],
|
|
});
|
|
|
|
// add negative values should not be observable.
|
|
counter.add(-1.1);
|
|
await validateExport(cumulativeReader, {
|
|
dataPointType: DataPointType.SUM,
|
|
isMonotonic: true,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 2.1,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 2.2,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('UpDownCounter', () => {
|
|
it('should add common values and attributes without exceptions', async () => {
|
|
const { meter, cumulativeReader } = setup();
|
|
const upDownCounter = meter.createUpDownCounter('test', {
|
|
description: 'foobar',
|
|
unit: 'kB',
|
|
});
|
|
|
|
for (const values of commonValues) {
|
|
for (const attributes of commonAttributes) {
|
|
upDownCounter.add(values, attributes);
|
|
}
|
|
}
|
|
|
|
await validateExport(cumulativeReader, {
|
|
descriptor: {
|
|
name: 'test',
|
|
description: 'foobar',
|
|
unit: 'kB',
|
|
type: InstrumentType.UP_DOWN_COUNTER,
|
|
valueType: ValueType.DOUBLE,
|
|
advice: {},
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should add INT values', async () => {
|
|
const { meter, deltaReader } = setup();
|
|
const upDownCounter = meter.createUpDownCounter('test', {
|
|
valueType: ValueType.INT,
|
|
});
|
|
|
|
upDownCounter.add(3);
|
|
upDownCounter.add(-1.1);
|
|
upDownCounter.add(4, { foo: 'bar' });
|
|
upDownCounter.add(1.1, { foo: 'bar' });
|
|
|
|
// non-finite/non-number values should be ignored.
|
|
upDownCounter.add(Infinity);
|
|
upDownCounter.add(-Infinity);
|
|
upDownCounter.add(NaN);
|
|
upDownCounter.add('1' as any);
|
|
|
|
await validateExport(deltaReader, {
|
|
descriptor: {
|
|
name: 'test',
|
|
description: '',
|
|
unit: '',
|
|
type: InstrumentType.UP_DOWN_COUNTER,
|
|
valueType: ValueType.INT,
|
|
advice: {},
|
|
},
|
|
dataPointType: DataPointType.SUM,
|
|
isMonotonic: false,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 2,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 5,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('should add DOUBLE values', async () => {
|
|
const { meter, deltaReader } = setup();
|
|
const upDownCounter = meter.createUpDownCounter('test', {
|
|
valueType: ValueType.DOUBLE,
|
|
});
|
|
|
|
upDownCounter.add(3);
|
|
upDownCounter.add(-1.1);
|
|
upDownCounter.add(4, { foo: 'bar' });
|
|
upDownCounter.add(1.1, { foo: 'bar' });
|
|
// non-number values should be ignored.
|
|
upDownCounter.add('1' as any);
|
|
|
|
await validateExport(deltaReader, {
|
|
dataPointType: DataPointType.SUM,
|
|
isMonotonic: false,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 1.9,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 5.1,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Histogram', () => {
|
|
it('should record common values and attributes without exceptions', async () => {
|
|
const { meter, cumulativeReader } = setup();
|
|
const histogram = meter.createHistogram('test', {
|
|
description: 'foobar',
|
|
unit: 'kB',
|
|
});
|
|
|
|
for (const values of commonValues) {
|
|
for (const attributes of commonAttributes) {
|
|
histogram.record(values, attributes);
|
|
}
|
|
}
|
|
|
|
await validateExport(cumulativeReader, {
|
|
descriptor: {
|
|
name: 'test',
|
|
description: 'foobar',
|
|
unit: 'kB',
|
|
type: InstrumentType.HISTOGRAM,
|
|
valueType: ValueType.DOUBLE,
|
|
advice: {},
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should record INT values', async () => {
|
|
const { meter, deltaReader } = setup();
|
|
const histogram = meter.createHistogram('test', {
|
|
valueType: ValueType.INT,
|
|
});
|
|
|
|
histogram.record(10);
|
|
// 0.1 should be trunc-ed to 0
|
|
histogram.record(0.1);
|
|
histogram.record(100, { foo: 'bar' });
|
|
histogram.record(0.1, { foo: 'bar' });
|
|
// non-finite/non-number values should be ignored.
|
|
histogram.record(Infinity);
|
|
histogram.record(-Infinity);
|
|
histogram.record(NaN);
|
|
histogram.record('1' as any);
|
|
|
|
await validateExport(deltaReader, {
|
|
descriptor: {
|
|
name: 'test',
|
|
description: '',
|
|
unit: '',
|
|
type: InstrumentType.HISTOGRAM,
|
|
valueType: ValueType.INT,
|
|
advice: {},
|
|
},
|
|
dataPointType: DataPointType.HISTOGRAM,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: {
|
|
buckets: {
|
|
boundaries: [
|
|
0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000,
|
|
7500, 10000,
|
|
],
|
|
counts: [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
},
|
|
count: 2,
|
|
sum: 10,
|
|
max: 10,
|
|
min: 0,
|
|
},
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: {
|
|
buckets: {
|
|
boundaries: [
|
|
0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000,
|
|
7500, 10000,
|
|
],
|
|
counts: [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
},
|
|
count: 2,
|
|
sum: 100,
|
|
max: 100,
|
|
min: 0,
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('should recognize metric advice', async () => {
|
|
const { meter, deltaReader } = setup();
|
|
const histogram = meter.createHistogram('test', {
|
|
valueType: ValueType.INT,
|
|
advice: {
|
|
// Set explicit boundaries that are different from the default one.
|
|
explicitBucketBoundaries: [1, 9, 100],
|
|
},
|
|
});
|
|
|
|
histogram.record(10);
|
|
histogram.record(0);
|
|
histogram.record(100, { foo: 'bar' });
|
|
histogram.record(0, { foo: 'bar' });
|
|
await validateExport(deltaReader, {
|
|
descriptor: {
|
|
name: 'test',
|
|
description: '',
|
|
unit: '',
|
|
type: InstrumentType.HISTOGRAM,
|
|
valueType: ValueType.INT,
|
|
advice: {
|
|
explicitBucketBoundaries: [1, 9, 100],
|
|
},
|
|
},
|
|
dataPointType: DataPointType.HISTOGRAM,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: {
|
|
buckets: {
|
|
boundaries: [1, 9, 100],
|
|
counts: [1, 0, 1, 0],
|
|
},
|
|
count: 2,
|
|
sum: 10,
|
|
max: 10,
|
|
min: 0,
|
|
},
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: {
|
|
buckets: {
|
|
boundaries: [1, 9, 100],
|
|
counts: [1, 0, 1, 0],
|
|
},
|
|
count: 2,
|
|
sum: 100,
|
|
max: 100,
|
|
min: 0,
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('should allow metric advice with empty explicit boundaries', function () {
|
|
const meter = new MeterProvider({
|
|
readers: [new TestMetricReader()],
|
|
}).getMeter('meter');
|
|
|
|
assert.doesNotThrow(() => {
|
|
meter.createHistogram('histogram', {
|
|
advice: {
|
|
explicitBucketBoundaries: [],
|
|
},
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should collect min and max', async () => {
|
|
const { meter, deltaReader, cumulativeReader } = setup();
|
|
const histogram = meter.createHistogram('test', {
|
|
valueType: ValueType.INT,
|
|
});
|
|
|
|
histogram.record(10);
|
|
histogram.record(100);
|
|
await deltaReader.collect();
|
|
await cumulativeReader.collect();
|
|
|
|
histogram.record(20);
|
|
histogram.record(90);
|
|
|
|
// Delta should only have min/max of values recorded after the collection.
|
|
await validateExport(deltaReader, {
|
|
descriptor: {
|
|
name: 'test',
|
|
description: '',
|
|
unit: '',
|
|
type: InstrumentType.HISTOGRAM,
|
|
valueType: ValueType.INT,
|
|
advice: {},
|
|
},
|
|
dataPointType: DataPointType.HISTOGRAM,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: {
|
|
buckets: {
|
|
boundaries: [
|
|
0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000,
|
|
7500, 10000,
|
|
],
|
|
counts: [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
},
|
|
count: 2,
|
|
sum: 110,
|
|
min: 20,
|
|
max: 90,
|
|
},
|
|
},
|
|
],
|
|
});
|
|
|
|
// Cumulative should have min/max of all recorded values.
|
|
await validateExport(cumulativeReader, {
|
|
descriptor: {
|
|
name: 'test',
|
|
description: '',
|
|
unit: '',
|
|
type: InstrumentType.HISTOGRAM,
|
|
valueType: ValueType.INT,
|
|
advice: {},
|
|
},
|
|
dataPointType: DataPointType.HISTOGRAM,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: {
|
|
buckets: {
|
|
boundaries: [
|
|
0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000,
|
|
7500, 10000,
|
|
],
|
|
counts: [0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
},
|
|
count: 4,
|
|
sum: 220,
|
|
min: 10,
|
|
max: 100,
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('should not record negative INT values', async () => {
|
|
const { meter, deltaReader } = setup();
|
|
const histogram = meter.createHistogram('test', {
|
|
valueType: ValueType.DOUBLE,
|
|
});
|
|
|
|
histogram.record(-1, { foo: 'bar' });
|
|
const result = await deltaReader.collect();
|
|
|
|
// nothing observed
|
|
assert.equal(result.resourceMetrics.scopeMetrics.length, 0);
|
|
});
|
|
|
|
it('should record DOUBLE values', async () => {
|
|
const { meter, deltaReader } = setup();
|
|
const histogram = meter.createHistogram('test', {
|
|
valueType: ValueType.DOUBLE,
|
|
});
|
|
|
|
histogram.record(10);
|
|
histogram.record(0.1);
|
|
histogram.record(100, { foo: 'bar' });
|
|
histogram.record(0.1, { foo: 'bar' });
|
|
// non-number values should be ignored.
|
|
histogram.record('1' as any);
|
|
histogram.record(NaN);
|
|
|
|
await validateExport(deltaReader, {
|
|
dataPointType: DataPointType.HISTOGRAM,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: {
|
|
buckets: {
|
|
boundaries: [
|
|
0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000,
|
|
7500, 10000,
|
|
],
|
|
counts: [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
},
|
|
count: 2,
|
|
sum: 10.1,
|
|
max: 10,
|
|
min: 0.1,
|
|
},
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: {
|
|
buckets: {
|
|
boundaries: [
|
|
0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000,
|
|
7500, 10000,
|
|
],
|
|
counts: [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
},
|
|
count: 2,
|
|
sum: 100.1,
|
|
max: 100,
|
|
min: 0.1,
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('should not record negative DOUBLE values', async () => {
|
|
const { meter, deltaReader } = setup();
|
|
const histogram = meter.createHistogram('test', {
|
|
valueType: ValueType.DOUBLE,
|
|
});
|
|
|
|
histogram.record(-0.5, { foo: 'bar' });
|
|
const result = await deltaReader.collect();
|
|
|
|
// nothing observed
|
|
assert.equal(result.resourceMetrics.scopeMetrics.length, 0);
|
|
});
|
|
});
|
|
|
|
describe('ObservableCounter', () => {
|
|
it('should observe common values and attributes without exceptions', async () => {
|
|
const { meter, deltaReader } = setup();
|
|
const callback = sinon.spy((observableResult: ObservableResult) => {
|
|
for (const values of commonValues) {
|
|
for (const attributes of commonAttributes) {
|
|
observableResult.observe(values, attributes);
|
|
}
|
|
}
|
|
});
|
|
const observableCounter = meter.createObservableCounter('test');
|
|
observableCounter.addCallback(callback);
|
|
|
|
await deltaReader.collect();
|
|
assert.strictEqual(callback.callCount, 1);
|
|
});
|
|
|
|
it('should observe values', async () => {
|
|
const { meter, cumulativeReader } = setup();
|
|
let callCount = 0;
|
|
const observableCounter = meter.createObservableCounter('test');
|
|
observableCounter.addCallback(observableResult => {
|
|
observableResult.observe(++callCount);
|
|
observableResult.observe(1, { foo: 'bar' });
|
|
});
|
|
|
|
await validateExport(cumulativeReader, {
|
|
dataPointType: DataPointType.SUM,
|
|
isMonotonic: false,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 1,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 1,
|
|
},
|
|
],
|
|
});
|
|
await validateExport(cumulativeReader, {
|
|
dataPointType: DataPointType.SUM,
|
|
isMonotonic: false,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 2,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 1,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('ObservableUpDownCounter', () => {
|
|
it('should observe common values and attributes without exceptions', async () => {
|
|
const { meter, deltaReader } = setup();
|
|
const callback = sinon.spy((observableResult: ObservableResult) => {
|
|
for (const values of commonValues) {
|
|
for (const attributes of commonAttributes) {
|
|
observableResult.observe(values, attributes);
|
|
}
|
|
}
|
|
});
|
|
const observableUpDownCounter =
|
|
meter.createObservableUpDownCounter('test');
|
|
observableUpDownCounter.addCallback(callback);
|
|
|
|
await deltaReader.collect();
|
|
assert.strictEqual(callback.callCount, 1);
|
|
});
|
|
|
|
it('should observe values', async () => {
|
|
const { meter, cumulativeReader } = setup();
|
|
let callCount = 0;
|
|
const observableUpDownCounter =
|
|
meter.createObservableUpDownCounter('test');
|
|
observableUpDownCounter.addCallback(observableResult => {
|
|
observableResult.observe(++callCount);
|
|
observableResult.observe(1, { foo: 'bar' });
|
|
});
|
|
|
|
await validateExport(cumulativeReader, {
|
|
dataPointType: DataPointType.SUM,
|
|
isMonotonic: false,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 1,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 1,
|
|
},
|
|
],
|
|
});
|
|
await validateExport(cumulativeReader, {
|
|
dataPointType: DataPointType.SUM,
|
|
isMonotonic: false,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 2,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 1,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('ObservableGauge', () => {
|
|
it('should observe common values and attributes without exceptions', async () => {
|
|
const { meter, deltaReader } = setup();
|
|
const callback = sinon.spy((observableResult: ObservableResult) => {
|
|
for (const values of commonValues) {
|
|
for (const attributes of commonAttributes) {
|
|
observableResult.observe(values, attributes);
|
|
}
|
|
}
|
|
});
|
|
const observableGauge = meter.createObservableGauge('test');
|
|
observableGauge.addCallback(callback);
|
|
|
|
await deltaReader.collect();
|
|
assert.strictEqual(callback.callCount, 1);
|
|
});
|
|
|
|
it('should observe values', async () => {
|
|
const { meter, cumulativeReader } = setup();
|
|
let num = 0;
|
|
const observableGauge = meter.createObservableGauge('test');
|
|
observableGauge.addCallback(observableResult => {
|
|
num += 10;
|
|
if (num === 30) {
|
|
observableResult.observe(-1);
|
|
} else {
|
|
observableResult.observe(num);
|
|
}
|
|
observableResult.observe(1, { foo: 'bar' });
|
|
});
|
|
|
|
await validateExport(cumulativeReader, {
|
|
dataPointType: DataPointType.GAUGE,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 10,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 1,
|
|
},
|
|
],
|
|
});
|
|
await validateExport(cumulativeReader, {
|
|
dataPointType: DataPointType.GAUGE,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: 20,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 1,
|
|
},
|
|
],
|
|
});
|
|
await validateExport(cumulativeReader, {
|
|
dataPointType: DataPointType.GAUGE,
|
|
dataPoints: [
|
|
{
|
|
attributes: {},
|
|
value: -1,
|
|
},
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 1,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Gauge', () => {
|
|
it('should record common values and attributes without exceptions', async () => {
|
|
const { meter } = setup();
|
|
const gauge = meter.createGauge('test');
|
|
|
|
for (const values of commonValues) {
|
|
for (const attributes of commonAttributes) {
|
|
gauge.record(values, attributes);
|
|
}
|
|
}
|
|
});
|
|
|
|
it('should record values', async () => {
|
|
const { meter, cumulativeReader } = setup();
|
|
const gauge = meter.createGauge('test');
|
|
|
|
gauge.record(1, { foo: 'bar' });
|
|
gauge.record(-1);
|
|
|
|
await validateExport(cumulativeReader, {
|
|
dataPointType: DataPointType.GAUGE,
|
|
dataPoints: [
|
|
{
|
|
attributes: { foo: 'bar' },
|
|
value: 1,
|
|
},
|
|
{
|
|
attributes: {},
|
|
value: -1,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
function setup() {
|
|
const deltaReader = new TestDeltaMetricReader();
|
|
const cumulativeReader = new TestMetricReader();
|
|
const meterProvider = new MeterProvider({
|
|
resource: defaultResource,
|
|
readers: [deltaReader, cumulativeReader],
|
|
});
|
|
const meter = meterProvider.getMeter(
|
|
defaultInstrumentationScope.name,
|
|
defaultInstrumentationScope.version,
|
|
{
|
|
schemaUrl: defaultInstrumentationScope.schemaUrl,
|
|
}
|
|
);
|
|
|
|
return {
|
|
meterProvider,
|
|
meter,
|
|
deltaReader,
|
|
cumulativeReader,
|
|
};
|
|
}
|
|
|
|
interface ValidateMetricData {
|
|
resource?: Resource;
|
|
instrumentationScope?: InstrumentationScope;
|
|
descriptor?: InstrumentDescriptor;
|
|
dataPointType?: DataPointType;
|
|
dataPoints?: Partial<DataPoint<number | Partial<Histogram>>>[];
|
|
isMonotonic?: boolean;
|
|
}
|
|
|
|
async function validateExport(
|
|
reader: IMetricReader,
|
|
expected: ValidateMetricData
|
|
) {
|
|
const { resourceMetrics, errors } = await reader.collect();
|
|
|
|
assert.strictEqual(errors.length, 0);
|
|
assert.notStrictEqual(resourceMetrics, undefined);
|
|
|
|
const { resource, scopeMetrics } = resourceMetrics!;
|
|
|
|
const { scope, metrics } = scopeMetrics[0];
|
|
|
|
assert.ok(!resource.asyncAttributesPending);
|
|
assert.deepStrictEqual(resource.attributes, defaultResource.attributes);
|
|
assert.deepStrictEqual(scope, defaultInstrumentationScope);
|
|
|
|
const metric = metrics[0];
|
|
|
|
assertMetricData(metric, expected.dataPointType, expected.descriptor ?? null);
|
|
|
|
if (expected.dataPoints == null) {
|
|
return;
|
|
}
|
|
assert.strictEqual(metric.dataPoints.length, expected.dataPoints.length);
|
|
|
|
for (let idx = 0; idx < metric.dataPoints.length; idx++) {
|
|
const expectedDataPoint = expected.dataPoints[idx];
|
|
assertDataPoint(
|
|
metric.dataPoints[idx],
|
|
expectedDataPoint.attributes ?? {},
|
|
expectedDataPoint.value as any,
|
|
expectedDataPoint.startTime,
|
|
expectedDataPoint.endTime
|
|
);
|
|
}
|
|
}
|