diff --git a/packages/opentelemetry-exporter-collector/src/transformMetrics.ts b/packages/opentelemetry-exporter-collector/src/transformMetrics.ts index 96263c2d8a..f192d117bf 100644 --- a/packages/opentelemetry-exporter-collector/src/transformMetrics.ts +++ b/packages/opentelemetry-exporter-collector/src/transformMetrics.ts @@ -28,6 +28,7 @@ import * as core from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; import { toCollectorResource } from './transform'; import { CollectorExporterBase } from './CollectorExporterBase'; +import { HrTime } from '@opentelemetry/api'; /** * Converts labels @@ -60,6 +61,9 @@ export function toCollectorType( if (metric.aggregator instanceof HistogramAggregator) { return opentelemetryProto.metrics.v1.MetricDescriptorType.HISTOGRAM; } + if (metric.aggregator instanceof MinMaxLastSumCountAggregator) { + return opentelemetryProto.metrics.v1.MetricDescriptorType.SUMMARY; + } if (metric.descriptor.valueType == api.ValueType.INT) { return opentelemetryProto.metrics.v1.MetricDescriptorType.INT64; } @@ -67,7 +71,6 @@ export function toCollectorType( return opentelemetryProto.metrics.v1.MetricDescriptorType.DOUBLE; } - // @TODO #1294: Add Summary once implemented return opentelemetryProto.metrics.v1.MetricDescriptorType.INVALID_TYPE; } @@ -132,14 +135,9 @@ export function toSingularPoint( timeUnixNano: number; value: number; } { - const pointValue = - metric.aggregator instanceof MinMaxLastSumCountAggregator - ? (metric.aggregator.toPoint().value as Distribution).last - : (metric.aggregator.toPoint().value as number); - return { labels: toCollectorLabels(metric.labels), - value: pointValue, + value: metric.aggregator.toPoint().value as number, startTimeUnixNano: startTime, timeUnixNano: core.hrTimeToNanoseconds( metric.aggregator.toPoint().timestamp @@ -156,19 +154,47 @@ export function toHistogramPoint( metric: MetricRecord, startTime: number ): opentelemetryProto.metrics.v1.HistogramDataPoint { - const histValue = metric.aggregator.toPoint().value as Histogram; + const { value, timestamp } = metric.aggregator.toPoint() as { + value: Histogram; + timestamp: HrTime; + }; return { labels: toCollectorLabels(metric.labels), - sum: histValue.sum, - count: histValue.count, + sum: value.sum, + count: value.count, startTimeUnixNano: startTime, - timeUnixNano: core.hrTimeToNanoseconds( - metric.aggregator.toPoint().timestamp - ), - buckets: histValue.buckets.counts.map(count => { + timeUnixNano: core.hrTimeToNanoseconds(timestamp), + buckets: value.buckets.counts.map(count => { return { count }; }), - explicitBounds: histValue.buckets.boundaries, + explicitBounds: value.buckets.boundaries, + }; +} + +/** + * Returns a SummaryPoint to the collector + * @param metric + * @param startTime + */ +export function toSummaryPoint( + metric: MetricRecord, + startTime: number +): opentelemetryProto.metrics.v1.SummaryDataPoint { + const { value, timestamp } = metric.aggregator.toPoint() as { + value: Distribution; + timestamp: HrTime; + }; + + return { + labels: toCollectorLabels(metric.labels), + sum: value.sum, + count: value.count, + startTimeUnixNano: startTime, + timeUnixNano: core.hrTimeToNanoseconds(timestamp), + percentileValues: [ + { percentile: 0, value: value.min }, + { percentile: 100, value: value.max }, + ], }; } @@ -190,6 +216,15 @@ export function toCollectorMetric( histogramDataPoints: [toHistogramPoint(metric, startTime)], }; } + if ( + toCollectorType(metric) === + opentelemetryProto.metrics.v1.MetricDescriptorType.SUMMARY + ) { + return { + metricDescriptor: toCollectorMetricDescriptor(metric), + summaryDataPoints: [toSummaryPoint(metric, startTime)], + }; + } if (metric.descriptor.valueType == api.ValueType.INT) { return { metricDescriptor: toCollectorMetricDescriptor(metric), @@ -201,7 +236,7 @@ export function toCollectorMetric( metricDescriptor: toCollectorMetricDescriptor(metric), doubleDataPoints: [toSingularPoint(metric, startTime)], }; - } // TODO: Add support for summary points once implemented + } return { metricDescriptor: toCollectorMetricDescriptor(metric), diff --git a/packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts b/packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts index 086a8ea82f..e7ed4baca0 100644 --- a/packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts @@ -63,8 +63,8 @@ describe('CollectorMetricExporter - common', () => { }; collectorExporter = new CollectorMetricExporter(collectorExporterConfig); metrics = []; - metrics.push(Object.assign({}, mockCounter)); - metrics.push(Object.assign({}, mockObserver)); + metrics.push(mockCounter()); + metrics.push(mockObserver()); }); afterEach(() => { diff --git a/packages/opentelemetry-exporter-collector/test/common/transformMetrics.test.ts b/packages/opentelemetry-exporter-collector/test/common/transformMetrics.test.ts index 8cae6cc2cc..e5a42194b2 100644 --- a/packages/opentelemetry-exporter-collector/test/common/transformMetrics.test.ts +++ b/packages/opentelemetry-exporter-collector/test/common/transformMetrics.test.ts @@ -17,57 +17,90 @@ import * as assert from 'assert'; import * as transform from '../../src/transformMetrics'; import { mockCounter, + mockDoubleCounter, mockObserver, mockedResources, mockedInstrumentationLibraries, multiResourceMetrics, multiInstrumentationLibraryMetrics, ensureCounterIsCorrect, + ensureDoubleCounterIsCorrect, ensureObserverIsCorrect, mockHistogram, ensureHistogramIsCorrect, ensureValueRecorderIsCorrect, mockValueRecorder, } from '../helper'; +import { MetricRecord, SumAggregator } from '@opentelemetry/metrics'; import { hrTimeToNanoseconds } from '@opentelemetry/core'; +import { Resource } from '@opentelemetry/resources'; describe('transformMetrics', () => { describe('toCollectorMetric', () => { + const counter: MetricRecord = mockCounter(); + const doubleCounter: MetricRecord = mockDoubleCounter(); + const observer: MetricRecord = mockObserver(); + const histogram: MetricRecord = mockHistogram(); + const recorder: MetricRecord = mockValueRecorder(); + const invalidMetric: MetricRecord = { + descriptor: { + name: 'name', + description: 'description', + unit: 'unit', + metricKind: 8, // Not a valid metricKind + valueType: 2, // Not double or int + }, + labels: {}, + aggregator: new SumAggregator(), + resource: new Resource({}), + instrumentationLibrary: { name: 'x', version: 'y' }, + }; beforeEach(() => { // Counter - mockCounter.aggregator.update(1); + counter.aggregator.update(1); + + // Double Counter + doubleCounter.aggregator.update(8); // Observer - mockObserver.aggregator.update(10); + observer.aggregator.update(3); + observer.aggregator.update(6); // Histogram - mockHistogram.aggregator.update(7); - mockHistogram.aggregator.update(14); + histogram.aggregator.update(7); + histogram.aggregator.update(14); // ValueRecorder - mockValueRecorder.aggregator.update(5); - }); - - afterEach(() => { - mockCounter.aggregator.update(-1); // Reset counter + recorder.aggregator.update(5); }); it('should convert metric', () => { ensureCounterIsCorrect( - transform.toCollectorMetric(mockCounter, 1592602232694000000), - hrTimeToNanoseconds(mockCounter.aggregator.toPoint().timestamp) + transform.toCollectorMetric(counter, 1592602232694000000), + hrTimeToNanoseconds(counter.aggregator.toPoint().timestamp) ); ensureObserverIsCorrect( - transform.toCollectorMetric(mockObserver, 1592602232694000000), - hrTimeToNanoseconds(mockObserver.aggregator.toPoint().timestamp) + transform.toCollectorMetric(observer, 1592602232694000000), + hrTimeToNanoseconds(observer.aggregator.toPoint().timestamp) ); ensureHistogramIsCorrect( - transform.toCollectorMetric(mockHistogram, 1592602232694000000), - hrTimeToNanoseconds(mockHistogram.aggregator.toPoint().timestamp) + transform.toCollectorMetric(histogram, 1592602232694000000), + hrTimeToNanoseconds(histogram.aggregator.toPoint().timestamp) ); ensureValueRecorderIsCorrect( - transform.toCollectorMetric(mockValueRecorder, 1592602232694000000), - hrTimeToNanoseconds(mockValueRecorder.aggregator.toPoint().timestamp) + transform.toCollectorMetric(recorder, 1592602232694000000), + hrTimeToNanoseconds(recorder.aggregator.toPoint().timestamp) + ); + + ensureDoubleCounterIsCorrect( + transform.toCollectorMetric(doubleCounter, 1592602232694000000), + hrTimeToNanoseconds(doubleCounter.aggregator.toPoint().timestamp) + ); + + const emptyMetric = transform.toCollectorMetric( + invalidMetric, + 1592602232694000000 ); + assert.deepStrictEqual(emptyMetric.int64DataPoints, []); }); }); describe('toCollectorMetricDescriptor', () => { diff --git a/packages/opentelemetry-exporter-collector/test/helper.ts b/packages/opentelemetry-exporter-collector/test/helper.ts index 58d70d28eb..697fa7ee90 100644 --- a/packages/opentelemetry-exporter-collector/test/helper.ts +++ b/packages/opentelemetry-exporter-collector/test/helper.ts @@ -38,10 +38,6 @@ if (typeof Buffer === 'undefined') { }; } -type Mutable = { - -readonly [P in keyof T]: T[P]; -}; - const traceIdArr = [ 31, 16, @@ -63,77 +59,105 @@ const traceIdArr = [ const spanIdArr = [94, 16, 114, 97, 246, 79, 165, 62]; const parentIdArr = [120, 168, 145, 80, 152, 134, 67, 136]; -export const mockCounter: MetricRecord = { - descriptor: { - name: 'test-counter', - description: 'sample counter description', - unit: '1', - metricKind: MetricKind.COUNTER, - valueType: ValueType.INT, - }, - labels: {}, - aggregator: new SumAggregator(), - resource: new Resource({ - service: 'ui', - version: 1, - cost: 112.12, - }), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, -}; +export function mockCounter(): MetricRecord { + return { + descriptor: { + name: 'test-counter', + description: 'sample counter description', + unit: '1', + metricKind: MetricKind.COUNTER, + valueType: ValueType.INT, + }, + labels: {}, + aggregator: new SumAggregator(), + resource: new Resource({ + service: 'ui', + version: 1, + cost: 112.12, + }), + instrumentationLibrary: { name: 'default', version: '0.0.1' }, + }; +} -export const mockObserver: MetricRecord = { - descriptor: { - name: 'test-observer', - description: 'sample observer description', - unit: '2', - metricKind: MetricKind.VALUE_OBSERVER, - valueType: ValueType.DOUBLE, - }, - labels: {}, - aggregator: new MinMaxLastSumCountAggregator(), - resource: new Resource({ - service: 'ui', - version: 1, - cost: 112.12, - }), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, -}; +export function mockDoubleCounter(): MetricRecord { + return { + descriptor: { + name: 'test-counter', + description: 'sample counter description', + unit: '1', + metricKind: MetricKind.COUNTER, + valueType: ValueType.DOUBLE, + }, + labels: {}, + aggregator: new SumAggregator(), + resource: new Resource({ + service: 'ui', + version: 1, + cost: 112.12, + }), + instrumentationLibrary: { name: 'default', version: '0.0.1' }, + }; +} -export const mockValueRecorder: MetricRecord = { - descriptor: { - name: 'test-recorder', - description: 'sample recorder description', - unit: '3', - metricKind: MetricKind.VALUE_RECORDER, - valueType: ValueType.INT, - }, - labels: {}, - aggregator: new MinMaxLastSumCountAggregator(), - resource: new Resource({ - service: 'ui', - version: 1, - cost: 112.12, - }), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, -}; +export function mockObserver(): MetricRecord { + return { + descriptor: { + name: 'test-observer', + description: 'sample observer description', + unit: '2', + metricKind: MetricKind.VALUE_OBSERVER, + valueType: ValueType.DOUBLE, + }, + labels: {}, + aggregator: new MinMaxLastSumCountAggregator(), + resource: new Resource({ + service: 'ui', + version: 1, + cost: 112.12, + }), + instrumentationLibrary: { name: 'default', version: '0.0.1' }, + }; +} -export const mockHistogram: Mutable = { - descriptor: { - name: 'test-hist', - description: 'sample observer description', - unit: '2', - metricKind: MetricKind.VALUE_OBSERVER, - valueType: ValueType.DOUBLE, - }, - labels: {}, - aggregator: new HistogramAggregator([10, 20]), - resource: new Resource({ - service: 'ui', - version: 1, - cost: 112.12, - }), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, -}; +export function mockValueRecorder(): MetricRecord { + return { + descriptor: { + name: 'test-recorder', + description: 'sample recorder description', + unit: '3', + metricKind: MetricKind.VALUE_RECORDER, + valueType: ValueType.INT, + }, + labels: {}, + aggregator: new MinMaxLastSumCountAggregator(), + resource: new Resource({ + service: 'ui', + version: 1, + cost: 112.12, + }), + instrumentationLibrary: { name: 'default', version: '0.0.1' }, + }; +} + +export function mockHistogram(): MetricRecord { + return { + descriptor: { + name: 'test-hist', + description: 'sample observer description', + unit: '2', + metricKind: MetricKind.VALUE_OBSERVER, + valueType: ValueType.DOUBLE, + }, + labels: {}, + aggregator: new HistogramAggregator([10, 20]), + resource: new Resource({ + service: 'ui', + version: 1, + cost: 112.12, + }), + instrumentationLibrary: { name: 'default', version: '0.0.1' }, + }; +} const traceIdBase64 = 'HxAI3I4nDoXECg18OTmyeA=='; const spanIdBase64 = 'XhByYfZPpT4='; @@ -289,17 +313,17 @@ export const multiResourceTrace: ReadableSpan[] = [ export const multiResourceMetrics: MetricRecord[] = [ { - ...mockCounter, + ...mockCounter(), resource: mockedResources[0], instrumentationLibrary: mockedInstrumentationLibraries[0], }, { - ...mockObserver, + ...mockObserver(), resource: mockedResources[1], instrumentationLibrary: mockedInstrumentationLibraries[0], }, { - ...mockCounter, + ...mockCounter(), resource: mockedResources[0], instrumentationLibrary: mockedInstrumentationLibraries[0], }, @@ -307,17 +331,17 @@ export const multiResourceMetrics: MetricRecord[] = [ export const multiInstrumentationLibraryMetrics: MetricRecord[] = [ { - ...mockCounter, + ...mockCounter(), resource: mockedResources[0], instrumentationLibrary: mockedInstrumentationLibraries[0], }, { - ...mockObserver, + ...mockObserver(), resource: mockedResources[0], instrumentationLibrary: mockedInstrumentationLibraries[1], }, { - ...mockCounter, + ...mockCounter(), resource: mockedResources[0], instrumentationLibrary: mockedInstrumentationLibraries[0], }, @@ -857,8 +881,12 @@ export function ensureCounterIsCorrect( name: 'test-counter', description: 'sample counter description', unit: '1', - type: 2, - temporality: 3, + type: + collectorTypes.opentelemetryProto.metrics.v1.MetricDescriptorType + .MONOTONIC_INT64, + temporality: + collectorTypes.opentelemetryProto.metrics.v1.MetricDescriptorTemporality + .CUMULATIVE, }, int64DataPoints: [ { @@ -871,6 +899,33 @@ export function ensureCounterIsCorrect( }); } +export function ensureDoubleCounterIsCorrect( + metric: collectorTypes.opentelemetryProto.metrics.v1.Metric, + time: number +) { + assert.deepStrictEqual(metric, { + metricDescriptor: { + name: 'test-counter', + description: 'sample counter description', + unit: '1', + type: + collectorTypes.opentelemetryProto.metrics.v1.MetricDescriptorType + .MONOTONIC_DOUBLE, + temporality: + collectorTypes.opentelemetryProto.metrics.v1.MetricDescriptorTemporality + .CUMULATIVE, + }, + doubleDataPoints: [ + { + labels: [], + value: 8, + startTimeUnixNano: 1592602232694000000, + timeUnixNano: time, + }, + ], + }); +} + export function ensureObserverIsCorrect( metric: collectorTypes.opentelemetryProto.metrics.v1.Metric, time: number @@ -880,15 +935,27 @@ export function ensureObserverIsCorrect( name: 'test-observer', description: 'sample observer description', unit: '2', - type: 3, - temporality: 2, + type: + collectorTypes.opentelemetryProto.metrics.v1.MetricDescriptorType + .SUMMARY, + temporality: + collectorTypes.opentelemetryProto.metrics.v1.MetricDescriptorTemporality + .DELTA, }, - doubleDataPoints: [ + summaryDataPoints: [ { - labels: [], - value: 10, startTimeUnixNano: 1592602232694000000, timeUnixNano: time, + count: 2, + sum: 9, + labels: [], + percentileValues: [ + { + percentile: 0, + value: 3, + }, + { percentile: 100, value: 6 }, + ], }, ], }); @@ -903,13 +970,22 @@ export function ensureValueRecorderIsCorrect( name: 'test-recorder', description: 'sample recorder description', unit: '3', - type: 1, - temporality: 2, + type: + collectorTypes.opentelemetryProto.metrics.v1.MetricDescriptorType + .SUMMARY, + temporality: + collectorTypes.opentelemetryProto.metrics.v1.MetricDescriptorTemporality + .DELTA, }, - int64DataPoints: [ + summaryDataPoints: [ { + count: 1, + sum: 5, labels: [], - value: 5, + percentileValues: [ + { percentile: 0, value: 5 }, + { percentile: 100, value: 5 }, + ], startTimeUnixNano: 1592602232694000000, timeUnixNano: time, }, @@ -926,8 +1002,12 @@ export function ensureHistogramIsCorrect( name: 'test-hist', description: 'sample observer description', unit: '2', - type: 5, - temporality: 2, + type: + collectorTypes.opentelemetryProto.metrics.v1.MetricDescriptorType + .HISTOGRAM, + temporality: + collectorTypes.opentelemetryProto.metrics.v1.MetricDescriptorTemporality + .DELTA, }, histogramDataPoints: [ { @@ -972,20 +1052,25 @@ export function ensureExportedObserverIsCorrect( name: 'test-observer', description: 'sample observer description', unit: '2', - type: 'DOUBLE', + type: 'SUMMARY', temporality: 'DELTA', }); assert.deepStrictEqual(metric.int64DataPoints, []); - assert.deepStrictEqual(metric.summaryDataPoints, []); + assert.deepStrictEqual(metric.doubleDataPoints, []); assert.deepStrictEqual(metric.histogramDataPoints, []); - assert.ok(metric.doubleDataPoints); - assert.deepStrictEqual(metric.doubleDataPoints[0].labels, []); - assert.deepStrictEqual(metric.doubleDataPoints[0].value, 10); + assert.ok(metric.summaryDataPoints); + assert.deepStrictEqual(metric.summaryDataPoints[0].labels, []); + assert.deepStrictEqual(metric.summaryDataPoints[0].sum, 9); + assert.deepStrictEqual(metric.summaryDataPoints[0].count, '2'); assert.deepStrictEqual( - metric.doubleDataPoints[0].startTimeUnixNano, + metric.summaryDataPoints[0].startTimeUnixNano, '1592602232694000128' ); + assert.deepStrictEqual(metric.summaryDataPoints[0].percentileValues, [ + { percentile: 0, value: 3 }, + { percentile: 100, value: 6 }, + ]); } export function ensureExportedHistogramIsCorrect( @@ -1027,18 +1112,24 @@ export function ensureExportedValueRecorderIsCorrect( name: 'test-recorder', description: 'sample recorder description', unit: '3', - type: 'INT64', + type: 'SUMMARY', temporality: 'DELTA', }); assert.deepStrictEqual(metric.histogramDataPoints, []); - assert.deepStrictEqual(metric.summaryDataPoints, []); + assert.deepStrictEqual(metric.int64DataPoints, []); assert.deepStrictEqual(metric.doubleDataPoints, []); - assert.ok(metric.int64DataPoints); - assert.deepStrictEqual(metric.int64DataPoints[0].labels, []); + assert.ok(metric.summaryDataPoints); + assert.deepStrictEqual(metric.summaryDataPoints[0].labels, []); assert.deepStrictEqual( - metric.int64DataPoints[0].startTimeUnixNano, + metric.summaryDataPoints[0].startTimeUnixNano, '1592602232694000128' ); + assert.deepStrictEqual(metric.summaryDataPoints[0].percentileValues, [ + { percentile: 0, value: 5 }, + { percentile: 100, value: 5 }, + ]); + assert.deepStrictEqual(metric.summaryDataPoints[0].count, '1'); + assert.deepStrictEqual(metric.summaryDataPoints[0].sum, 5); } export function ensureResourceIsCorrect( diff --git a/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporter.test.ts b/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporter.test.ts index ee659923d4..18f3b7a444 100644 --- a/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporter.test.ts @@ -23,7 +23,7 @@ import * as assert from 'assert'; import * as sinon from 'sinon'; import { CollectorMetricExporter } from '../../src/platform/node'; import * as collectorTypes from '../../src/types'; -import { MetricRecord, HistogramAggregator } from '@opentelemetry/metrics'; +import { MetricRecord } from '@opentelemetry/metrics'; import { mockCounter, mockObserver, @@ -137,13 +137,16 @@ const testCollectorMetricExporter = (params: TestParams) => value: 1592602232694000000, }); metrics = []; - metrics.push(Object.assign({}, mockCounter)); - metrics.push(Object.assign({}, mockObserver)); - metrics.push(Object.assign({}, mockHistogram)); - metrics.push(Object.assign({}, mockValueRecorder)); + metrics.push(mockCounter()); + metrics.push(mockObserver()); + metrics.push(mockHistogram()); + metrics.push(mockValueRecorder()); metrics[0].aggregator.update(1); - metrics[1].aggregator.update(10); + + metrics[1].aggregator.update(3); + metrics[1].aggregator.update(6); + metrics[2].aggregator.update(7); metrics[2].aggregator.update(14); metrics[3].aggregator.update(5); @@ -151,9 +154,6 @@ const testCollectorMetricExporter = (params: TestParams) => }); afterEach(() => { - // Aggregator is not deep-copied - metrics[0].aggregator.update(-1); - mockHistogram.aggregator = new HistogramAggregator([10, 20]); exportedData = undefined; reqMetadata = undefined; }); diff --git a/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporterWithJson.test.ts b/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporterWithJson.test.ts index c8f767c82b..433b9d867a 100644 --- a/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporterWithJson.test.ts +++ b/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporterWithJson.test.ts @@ -34,7 +34,7 @@ import { ensureHistogramIsCorrect, ensureObserverIsCorrect, } from '../helper'; -import { MetricRecord, HistogramAggregator } from '@opentelemetry/metrics'; +import { MetricRecord } from '@opentelemetry/metrics'; const fakeRequest = { end: function () {}, @@ -77,20 +77,18 @@ describe('CollectorMetricExporter - node with json over http', () => { value: 1592602232694000000, }); metrics = []; - metrics.push(Object.assign({}, mockCounter)); - metrics.push(Object.assign({}, mockObserver)); - metrics.push(Object.assign({}, mockHistogram)); - metrics.push(Object.assign({}, mockValueRecorder)); + metrics.push(mockCounter()); + metrics.push(mockObserver()); + metrics.push(mockHistogram()); + metrics.push(mockValueRecorder()); metrics[0].aggregator.update(1); - metrics[1].aggregator.update(10); + metrics[1].aggregator.update(3); + metrics[1].aggregator.update(6); metrics[2].aggregator.update(7); metrics[2].aggregator.update(14); metrics[3].aggregator.update(5); }); afterEach(() => { - // Aggregator is not deep-copied - metrics[0].aggregator.update(-1); - mockHistogram.aggregator = new HistogramAggregator([10, 20]); spyRequest.restore(); spyWrite.restore(); });