feat(metrics): prototype experimental advice support (#3876)

Co-authored-by: Marc Pichler <marc.pichler@dynatrace.com>
This commit is contained in:
Chengzhong Wu 2023-10-11 16:05:03 +08:00 committed by GitHub
parent f8e187b473
commit b6e532bf52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 252 additions and 56 deletions

View File

@ -11,6 +11,8 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/
### :rocket: (Enhancement)
* feat(metrics): prototype experimental advice support [#3876](https://github.com/open-telemetry/opentelemetry-js/pull/3876) @legendecas
### :bug: (Bug Fix)
### :books: (Refine Doc)

View File

@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
## Unreleased
### :rocket: (Enhancement)
* feat(metrics): prototype experimental advice support [#3876](https://github.com/open-telemetry/opentelemetry-js/pull/3876) @legendecas
## 1.6.0
### :bug: (Bug Fix)

View File

@ -51,6 +51,7 @@ export {
ObservableUpDownCounter,
UpDownCounter,
BatchObservableCallback,
MetricAdvice,
MetricAttributes,
MetricAttributeValue,
ObservableCallback,

View File

@ -18,6 +18,18 @@ import { Attributes, AttributeValue } from '../common/Attributes';
import { Context } from '../context/types';
import { BatchObservableResult, ObservableResult } from './ObservableResult';
/**
* Advisory options influencing aggregation configuration parameters.
* @experimental
*/
export interface MetricAdvice {
/**
* Hint the explicit bucket boundaries for SDK if the metric is been
* aggregated with a HistogramAggregator.
*/
explicitBucketBoundaries?: number[];
}
/**
* Options needed for metric creation
*/
@ -39,6 +51,12 @@ export interface MetricOptions {
* @default {@link ValueType.DOUBLE}
*/
valueType?: ValueType;
/**
* The advice influencing aggregation configuration parameters.
* @experimental
*/
advice?: MetricAdvice;
}
/** The Type of value. It describes how the data is reported. */

View File

@ -14,7 +14,12 @@
* limitations under the License.
*/
import { MetricOptions, ValueType, diag } from '@opentelemetry/api';
import {
MetricAdvice,
MetricOptions,
ValueType,
diag,
} from '@opentelemetry/api';
import { View } from './view/View';
import { equalsCaseInsensitive } from './utils';
@ -31,7 +36,10 @@ export enum InstrumentType {
}
/**
* An interface describing the instrument.
* An internal interface describing the instrument.
*
* This is intentionally distinguished from the public MetricDescriptor (a.k.a. InstrumentDescriptor)
* which may not contains internal fields like metric advice.
*/
export interface InstrumentDescriptor {
readonly name: string;
@ -39,6 +47,10 @@ export interface InstrumentDescriptor {
readonly unit: string;
readonly type: InstrumentType;
readonly valueType: ValueType;
/**
* @experimental
*/
readonly advice: MetricAdvice;
}
export function createInstrumentDescriptor(
@ -57,6 +69,7 @@ export function createInstrumentDescriptor(
description: options?.description ?? '',
unit: options?.unit ?? '',
valueType: options?.valueType ?? ValueType.DOUBLE,
advice: options?.advice ?? {},
};
}
@ -70,6 +83,7 @@ export function createInstrumentDescriptorWithView(
type: instrument.type,
unit: instrument.unit,
valueType: instrument.valueType,
advice: instrument.advice,
};
}

View File

@ -24,7 +24,6 @@ import {
} from '@opentelemetry/api';
import { AttributeHashMap } from './state/HashMap';
import { isObservableInstrument, ObservableInstrument } from './Instruments';
import { InstrumentDescriptor } from '.';
/**
* The class implements {@link ObservableResult} interface.
@ -35,7 +34,10 @@ export class ObservableResultImpl implements ObservableResult {
*/
_buffer = new AttributeHashMap<number>();
constructor(private _descriptor: InstrumentDescriptor) {}
constructor(
private _instrumentName: string,
private _valueType: ValueType
) {}
/**
* Observe a measurement of the value associated with the given attributes.
@ -43,16 +45,13 @@ export class ObservableResultImpl implements ObservableResult {
observe(value: number, attributes: MetricAttributes = {}): void {
if (typeof value !== 'number') {
diag.warn(
`non-number value provided to metric ${this._descriptor.name}: ${value}`
`non-number value provided to metric ${this._instrumentName}: ${value}`
);
return;
}
if (
this._descriptor.valueType === ValueType.INT &&
!Number.isInteger(value)
) {
if (this._valueType === ValueType.INT && !Number.isInteger(value)) {
diag.warn(
`INT value type cannot accept a floating-point value for ${this._descriptor.name}, ignoring the fractional digits.`
`INT value type cannot accept a floating-point value for ${this._instrumentName}, ignoring the fractional digits.`
);
value = Math.trunc(value);
// ignore non-finite values.

View File

@ -16,8 +16,7 @@
import { HrTime } from '@opentelemetry/api';
import { AggregationTemporality } from '../export/AggregationTemporality';
import { MetricData } from '../export/MetricData';
import { InstrumentDescriptor } from '../InstrumentDescriptor';
import { MetricData, MetricDescriptor } from '../export/MetricData';
import { Maybe } from '../utils';
import { AggregatorKind, Aggregator, AccumulationRecord } from './types';
@ -38,7 +37,7 @@ export class DropAggregator implements Aggregator<undefined> {
}
toMetricData(
_descriptor: InstrumentDescriptor,
_descriptor: MetricDescriptor,
_aggregationTemporality: AggregationTemporality,
_accumulationByAttributes: AccumulationRecord<undefined>[],
_endTime: HrTime

View File

@ -24,9 +24,10 @@ import {
import {
DataPointType,
ExponentialHistogramMetricData,
MetricDescriptor,
} from '../export/MetricData';
import { diag, HrTime } from '@opentelemetry/api';
import { InstrumentDescriptor, InstrumentType } from '../InstrumentDescriptor';
import { InstrumentType } from '../InstrumentDescriptor';
import { Maybe } from '../utils';
import { AggregationTemporality } from '../export/AggregationTemporality';
import { Buckets } from './exponential-histogram/Buckets';
@ -555,7 +556,7 @@ export class ExponentialHistogramAggregator
}
toMetricData(
descriptor: InstrumentDescriptor,
descriptor: MetricDescriptor,
aggregationTemporality: AggregationTemporality,
accumulationByAttributes: AccumulationRecord<ExponentialHistogramAccumulation>[],
endTime: HrTime

View File

@ -20,9 +20,13 @@ import {
Aggregator,
AggregatorKind,
} from './types';
import { DataPointType, HistogramMetricData } from '../export/MetricData';
import {
DataPointType,
HistogramMetricData,
MetricDescriptor,
} from '../export/MetricData';
import { HrTime } from '@opentelemetry/api';
import { InstrumentDescriptor, InstrumentType } from '../InstrumentDescriptor';
import { InstrumentType } from '../InstrumentDescriptor';
import { binarySearchLB, Maybe } from '../utils';
import { AggregationTemporality } from '../export/AggregationTemporality';
@ -207,7 +211,7 @@ export class HistogramAggregator implements Aggregator<HistogramAccumulation> {
}
toMetricData(
descriptor: InstrumentDescriptor,
descriptor: MetricDescriptor,
aggregationTemporality: AggregationTemporality,
accumulationByAttributes: AccumulationRecord<HistogramAccumulation>[],
endTime: HrTime

View File

@ -23,8 +23,11 @@ import {
} from './types';
import { HrTime } from '@opentelemetry/api';
import { millisToHrTime, hrTimeToMicroseconds } from '@opentelemetry/core';
import { DataPointType, GaugeMetricData } from '../export/MetricData';
import { InstrumentDescriptor } from '../InstrumentDescriptor';
import {
DataPointType,
GaugeMetricData,
MetricDescriptor,
} from '../export/MetricData';
import { Maybe } from '../utils';
import { AggregationTemporality } from '../export/AggregationTemporality';
@ -103,7 +106,7 @@ export class LastValueAggregator implements Aggregator<LastValueAccumulation> {
}
toMetricData(
descriptor: InstrumentDescriptor,
descriptor: MetricDescriptor,
aggregationTemporality: AggregationTemporality,
accumulationByAttributes: AccumulationRecord<LastValueAccumulation>[],
endTime: HrTime

View File

@ -22,8 +22,11 @@ import {
AccumulationRecord,
} from './types';
import { HrTime } from '@opentelemetry/api';
import { DataPointType, SumMetricData } from '../export/MetricData';
import { InstrumentDescriptor } from '../InstrumentDescriptor';
import {
DataPointType,
MetricDescriptor,
SumMetricData,
} from '../export/MetricData';
import { Maybe } from '../utils';
import { AggregationTemporality } from '../export/AggregationTemporality';
@ -109,7 +112,7 @@ export class SumAggregator implements Aggregator<SumAccumulation> {
}
toMetricData(
descriptor: InstrumentDescriptor,
descriptor: MetricDescriptor,
aggregationTemporality: AggregationTemporality,
accumulationByAttributes: AccumulationRecord<SumAccumulation>[],
endTime: HrTime

View File

@ -16,8 +16,7 @@
import { HrTime, MetricAttributes } from '@opentelemetry/api';
import { AggregationTemporality } from '../export/AggregationTemporality';
import { MetricData } from '../export/MetricData';
import { InstrumentDescriptor } from '../InstrumentDescriptor';
import { MetricData, MetricDescriptor } from '../export/MetricData';
import { Maybe } from '../utils';
/** The kind of aggregator. */
@ -128,14 +127,14 @@ export interface Aggregator<T> {
/**
* Returns the {@link MetricData} that this {@link Aggregator} will produce.
*
* @param descriptor the metric instrument descriptor.
* @param descriptor the metric descriptor.
* @param aggregationTemporality the temporality of the resulting {@link MetricData}
* @param accumulationByAttributes the array of attributes and accumulation pairs.
* @param endTime the end time of the metric data.
* @return the {@link MetricData} that this {@link Aggregator} will produce.
*/
toMetricData(
descriptor: InstrumentDescriptor,
descriptor: MetricDescriptor,
aggregationTemporality: AggregationTemporality,
accumulationByAttributes: AccumulationRecord<T>[],
endTime: HrTime

View File

@ -14,18 +14,30 @@
* limitations under the License.
*/
import { HrTime, MetricAttributes } from '@opentelemetry/api';
import { HrTime, MetricAttributes, ValueType } from '@opentelemetry/api';
import { InstrumentationScope } from '@opentelemetry/core';
import { IResource } from '@opentelemetry/resources';
import { InstrumentDescriptor } from '../InstrumentDescriptor';
import { InstrumentType } from '../InstrumentDescriptor';
import { AggregationTemporality } from './AggregationTemporality';
import { Histogram, ExponentialHistogram } from '../aggregator/types';
export interface MetricDescriptor {
readonly name: string;
readonly description: string;
readonly unit: string;
/**
* @deprecated exporter should avoid depending on the type of the instrument
* as their resulting aggregator can be re-mapped with views.
*/
readonly type: InstrumentType;
readonly valueType: ValueType;
}
/**
* Basic metric data fields.
*/
interface BaseMetricData {
readonly descriptor: InstrumentDescriptor;
readonly descriptor: MetricDescriptor;
readonly aggregationTemporality: AggregationTemporality;
/**
* DataPointType of the metric instrument.

View File

@ -14,6 +14,8 @@
* limitations under the License.
*/
import { MetricDescriptor } from './export/MetricData';
export {
Sum,
LastValue,
@ -38,6 +40,7 @@ export {
ResourceMetrics,
ScopeMetrics,
MetricData,
MetricDescriptor,
CollectionResult,
} from './export/MetricData';
@ -56,7 +59,11 @@ export { ConsoleMetricExporter } from './export/ConsoleMetricExporter';
export { MetricCollectOptions, MetricProducer } from './export/MetricProducer';
export { InstrumentDescriptor, InstrumentType } from './InstrumentDescriptor';
export { InstrumentType } from './InstrumentDescriptor';
/**
* @deprecated Use {@link MetricDescriptor} instead.
*/
export type InstrumentDescriptor = MetricDescriptor;
export { MeterProvider, MeterProviderOptions } from './MeterProvider';

View File

@ -54,6 +54,7 @@ export abstract class MetricStorage {
description: description,
valueType: this._instrumentDescriptor.valueType,
unit: this._instrumentDescriptor.unit,
advice: this._instrumentDescriptor.advice,
}
);
}

View File

@ -144,7 +144,10 @@ export class ObservableRegistry {
private _observeCallbacks(observationTime: HrTime, timeoutMillis?: number) {
return this._callbacks.map(async ({ callback, instrument }) => {
const observableResult = new ObservableResultImpl(instrument._descriptor);
const observableResult = new ObservableResultImpl(
instrument._descriptor.name,
instrument._descriptor.valueType
);
let callPromise: Promise<void> = Promise.resolve(
callback(observableResult)
);

View File

@ -184,6 +184,11 @@ export class DefaultAggregation extends Aggregation {
return LAST_VALUE_AGGREGATION;
}
case InstrumentType.HISTOGRAM: {
if (instrument.advice.explicitBucketBoundaries) {
return new ExplicitBucketHistogramAggregation(
instrument.advice.explicitBucketBoundaries
);
}
return HISTOGRAM_AGGREGATION;
}
}

View File

@ -57,6 +57,7 @@ describe('InstrumentDescriptor', () => {
unit: 'kB',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {},
},
{
name: 'foo',
@ -64,6 +65,7 @@ describe('InstrumentDescriptor', () => {
unit: 'kB',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {},
},
],
[
@ -75,6 +77,7 @@ describe('InstrumentDescriptor', () => {
unit: '',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {},
},
{
name: 'FoO',
@ -82,6 +85,53 @@ describe('InstrumentDescriptor', () => {
unit: '',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {},
},
],
[
'Compatible with different advice options',
true,
{
name: 'foo',
description: '',
unit: '',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {
explicitBucketBoundaries: [4, 5, 6],
},
},
{
name: 'FoO',
description: '',
unit: '',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {
explicitBucketBoundaries: [1, 2, 3],
},
},
],
[
'Compatible with empty advice options',
true,
{
name: 'foo',
description: '',
unit: '',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {},
},
{
name: 'FoO',
description: '',
unit: '',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {
explicitBucketBoundaries: [1, 2, 3],
},
},
],
[
@ -93,6 +143,7 @@ describe('InstrumentDescriptor', () => {
unit: '',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {},
},
{
name: 'foobar',
@ -100,6 +151,7 @@ describe('InstrumentDescriptor', () => {
unit: '',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {},
},
],
[
@ -111,6 +163,7 @@ describe('InstrumentDescriptor', () => {
unit: 'kB',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {},
},
{
name: 'foo',
@ -118,6 +171,7 @@ describe('InstrumentDescriptor', () => {
unit: 'kb',
type: InstrumentType.COUNTER,
valueType: ValueType.DOUBLE,
advice: {},
},
],
];

View File

@ -19,13 +19,13 @@ import * as sinon from 'sinon';
import { InstrumentationScope } from '@opentelemetry/core';
import { Resource } from '@opentelemetry/resources';
import {
InstrumentDescriptor,
InstrumentType,
MeterProvider,
MetricReader,
DataPoint,
DataPointType,
Histogram,
MetricDescriptor,
} from '../src';
import {
TestDeltaMetricReader,
@ -352,6 +352,60 @@ describe('Instruments', () => {
});
});
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,
},
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, 0, 1],
},
count: 2,
sum: 100,
max: 100,
min: 0,
},
},
],
});
});
it('should collect min and max', async () => {
const { meter, deltaReader, cumulativeReader } = setup();
const histogram = meter.createHistogram('test', {
@ -721,7 +775,7 @@ function setup() {
interface ValidateMetricData {
resource?: Resource;
instrumentationScope?: InstrumentationScope;
descriptor?: InstrumentDescriptor;
descriptor?: MetricDescriptor;
dataPointType?: DataPointType;
dataPoints?: Partial<DataPoint<number | Partial<Histogram>>>[];
isMonotonic?: boolean;

View File

@ -33,7 +33,8 @@ describe('ObservableResultImpl', () => {
describe('observe', () => {
it('should observe common values', () => {
const observableResult = new ObservableResultImpl(
defaultInstrumentDescriptor
'instrument_name',
ValueType.DOUBLE
);
for (const value of commonValues) {
for (const attributes of commonAttributes) {
@ -44,7 +45,8 @@ describe('ObservableResultImpl', () => {
it('should deduplicate observations', () => {
const observableResult = new ObservableResultImpl(
defaultInstrumentDescriptor
'instrument_name',
ValueType.DOUBLE
);
observableResult.observe(1, {});
observableResult.observe(2, {});
@ -55,13 +57,10 @@ describe('ObservableResultImpl', () => {
});
it('should trunc value if ValueType is INT', () => {
const observableResult = new ObservableResultImpl({
name: 'test',
description: '',
type: InstrumentType.COUNTER,
unit: '',
valueType: ValueType.INT,
});
const observableResult = new ObservableResultImpl(
'instrument_name',
ValueType.INT
);
observableResult.observe(1.1, {});
// should ignore non-finite/non-number values.
observableResult.observe(Infinity, {});
@ -72,14 +71,7 @@ describe('ObservableResultImpl', () => {
});
it('should ignore non-number values', () => {
const observableResult = new ObservableResultImpl({
name: 'test',
description: '',
type: InstrumentType.COUNTER,
unit: '',
valueType: ValueType.INT,
});
const observableResult = new ObservableResultImpl('test', ValueType.INT);
observableResult.observe('1' as any, {});
assert.strictEqual(observableResult._buffer.get({}), undefined);
@ -139,6 +131,7 @@ describe('BatchObservableResultImpl', () => {
type: InstrumentType.COUNTER,
unit: '',
valueType: ValueType.INT,
advice: {},
},
[],
new ObservableRegistry()
@ -161,6 +154,7 @@ describe('BatchObservableResultImpl', () => {
type: InstrumentType.COUNTER,
unit: '',
valueType: ValueType.INT,
advice: {},
},
[],
new ObservableRegistry()

View File

@ -19,7 +19,7 @@ import { diag, ValueType } from '@opentelemetry/api';
import { MetricStorage } from '../../src/state/MetricStorage';
import { HrTime } from '@opentelemetry/api';
import { MetricCollectorHandle } from '../../src/state/MetricCollector';
import { MetricData, InstrumentDescriptor, InstrumentType } from '../../src';
import { MetricData, InstrumentType } from '../../src';
import { Maybe } from '../../src/utils';
import * as assert from 'assert';
import * as sinon from 'sinon';
@ -29,6 +29,7 @@ import {
getUnitConflictResolutionRecipe,
getValueTypeConflictResolutionRecipe,
} from '../../src/view/RegistrationConflicts';
import { InstrumentDescriptor } from '../../src/InstrumentDescriptor';
class TestMetricStorage extends MetricStorage {
collect(
@ -73,6 +74,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
});
registry.register(storage);
@ -92,6 +94,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
});
const storage2 = new TestMetricStorage({
name: 'instrument2',
@ -99,6 +102,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
});
registry.registerForCollector(collectorHandle, storage);
@ -152,6 +156,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
const otherDescriptor = {
@ -160,6 +165,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
testConflictingRegistration(
@ -176,6 +182,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
const otherDescriptor = {
@ -184,6 +191,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.INT,
advice: {},
};
testConflictingRegistration(
@ -203,6 +211,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
const otherDescriptor = {
@ -211,6 +220,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: 'ms',
valueType: ValueType.DOUBLE,
advice: {},
};
testConflictingRegistration(
@ -227,6 +237,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
const otherDescriptor = {
@ -235,6 +246,7 @@ describe('MetricStorageRegistry', () => {
description: 'longer description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
const registry = new MetricStorageRegistry();
@ -275,6 +287,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
const storage = new TestMetricStorage(descriptor);
@ -294,6 +307,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
const storage = new TestMetricStorage(descriptor);
@ -329,6 +343,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
const otherDescriptor = {
@ -337,6 +352,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
const registry = new MetricStorageRegistry();
@ -375,6 +391,7 @@ describe('MetricStorageRegistry', () => {
description: 'description',
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
const registry = new MetricStorageRegistry();

View File

@ -33,6 +33,7 @@ import {
DataPoint,
DataPointType,
ScopeMetrics,
MetricDescriptor,
} from '../src/export/MetricData';
import { isNotNullish } from '../src/utils';
import { HrTime } from '@opentelemetry/api';
@ -58,6 +59,7 @@ export const defaultInstrumentDescriptor: InstrumentDescriptor = {
type: InstrumentType.COUNTER,
unit: '1',
valueType: ValueType.DOUBLE,
advice: {},
};
export const defaultInstrumentationScope: InstrumentationScope = {
@ -104,12 +106,12 @@ export function assertScopeMetrics(
export function assertMetricData(
actual: unknown,
dataPointType?: DataPointType,
instrumentDescriptor: Partial<InstrumentDescriptor> | null = defaultInstrumentDescriptor,
metricDescriptor: Partial<MetricDescriptor> | null = defaultInstrumentDescriptor,
aggregationTemporality?: AggregationTemporality
): asserts actual is MetricData {
const it = actual as MetricData;
if (instrumentDescriptor != null) {
assertPartialDeepStrictEqual(it.descriptor, instrumentDescriptor);
if (metricDescriptor != null) {
assertPartialDeepStrictEqual(it.descriptor, metricDescriptor);
}
if (isNotNullish(dataPointType)) {
assert.strictEqual(it.dataPointType, dataPointType);