From 1f208a1f4e06918bb923d06fb77b94ba936221ce Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 16 Jun 2022 00:31:15 +0100 Subject: [PATCH 01/16] feat: add InMemoryMetricExporter Introduces the `InMemoryMetricExporter`-class which collects metrics and stores it in memory --- .../src/export/InMemoryMetricExporter.ts | 78 +++++++++++++++++++ .../src/index.ts | 1 + .../export/InMemoryMetricExporter.test.ts | 25 ++++++ 3 files changed, 104 insertions(+) create mode 100644 experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts create mode 100644 experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts new file mode 100644 index 00000000000..f6beecc0e3b --- /dev/null +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts @@ -0,0 +1,78 @@ +/* + * 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 { ExportResultCode } from "@opentelemetry/core" +import { ExportResult } from "@opentelemetry/core" +import { InstrumentType } from "../InstrumentDescriptor" +import { AggregationTemporality } from "./AggregationTemporality" +import { ResourceMetrics } from "./MetricData" +import { PushMetricExporter } from "./MetricExporter" + +/** + * TODO + */ +export class InMemoryMetricExporter implements PushMetricExporter { + protected _shutdown = false + protected _aggregationTemporality: AggregationTemporality + private _metrics: ResourceMetrics[] = [] + + constructor(aggregationTemporality: AggregationTemporality) { + this._aggregationTemporality = aggregationTemporality + } + + /** + * @inheritedDoc + */ + export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void { + // Avoid storing metrics when exporter is shutdown + if (this. _shutdown) { + process.nextTick(() => resultCallback({ code: ExportResultCode.FAILED })); + return + } + + this._metrics.push(metrics) + process.nextTick(() => resultCallback({ code: ExportResultCode.SUCCESS })); + } + + /** + * Returns all the collected scope metrics + * @returns ScopeMetric[] + */ + public getMetrics(): ResourceMetrics[] { + return this._metrics + } + + /** + * Clear the collected metrics + */ + public clear(): void { + this._metrics = [] + } + + async forceFlush() { + this._metrics = [] + return Promise.resolve() + } + + selectAggregationTemporality(_instrumentType: InstrumentType): AggregationTemporality { + return this._aggregationTemporality + } + + shutdown(): Promise { + this._shutdown = true + return Promise.resolve() + } +} diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/index.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/index.ts index a43ec3bcbca..439f76571ab 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/index.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/index.ts @@ -21,6 +21,7 @@ export * from './export/MetricExporter'; export * from './export/MetricProducer'; export * from './export/MetricReader'; export * from './export/PeriodicExportingMetricReader'; +export * from './export/InMemoryMetricExporter'; export { InstrumentDescriptor, InstrumentType } from './InstrumentDescriptor'; export * from './Meter'; export * from './MeterProvider'; diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts new file mode 100644 index 00000000000..79f74f39c3e --- /dev/null +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.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 * as assert from 'assert'; +import { AggregationTemporality } from "../../src/export/AggregationTemporality" +import { InMemoryMetricExporter } from "../../src/export/InMemoryMetricExporter" + +describe('InMemoryMetricExporter', () => { + describe('clear metrics on request', () => { + const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE) + assert.ok(exporter, 'exporter exists') + }) +}) From b00b26f5d2b653a3b90ff1c17328e519aaf1a16b Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 16 Jun 2022 00:37:50 +0100 Subject: [PATCH 02/16] style: improve comments --- .../src/export/InMemoryMetricExporter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts index f6beecc0e3b..47de232f768 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts @@ -48,8 +48,8 @@ export class InMemoryMetricExporter implements PushMetricExporter { } /** - * Returns all the collected scope metrics - * @returns ScopeMetric[] + * Returns all the collected resource metrics + * @returns ResourceMetrics[] */ public getMetrics(): ResourceMetrics[] { return this._metrics From be26afa17477f00ae74aeb198a5cac1583563e23 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Thu, 16 Jun 2022 00:39:13 +0100 Subject: [PATCH 03/16] style: improve comments --- .../src/export/InMemoryMetricExporter.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts index 47de232f768..805ae394c53 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts @@ -22,7 +22,9 @@ import { ResourceMetrics } from "./MetricData" import { PushMetricExporter } from "./MetricExporter" /** - * TODO + * In-memory Metrics Exporter is a Push Metric Exporter + * which accumulates metrics data in the local memory and + * allows to inspect it (useful for e.g. unit tests). */ export class InMemoryMetricExporter implements PushMetricExporter { protected _shutdown = false From e256c3a5f590999cccbf7ade8e7798bfcc1e6ed3 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 21 Jun 2022 22:59:01 +0100 Subject: [PATCH 04/16] test: created test for the `InMemoryMetricExporter`-class --- .../export/InMemoryMetricExporter.test.ts | 86 +++++++++++++++++-- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts index 79f74f39c3e..fad1255aa07 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts @@ -13,13 +13,87 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as assert from 'assert'; -import { AggregationTemporality } from "../../src/export/AggregationTemporality" +import assert = require('assert'); +import { AggregationTemporality } from '../../src/export/AggregationTemporality'; import { InMemoryMetricExporter } from "../../src/export/InMemoryMetricExporter" +import { PeriodicExportingMetricReader } from '../../src/export/PeriodicExportingMetricReader'; +import { MeterProvider } from '../../src/MeterProvider'; +import { defaultResource } from '../util'; -describe('InMemoryMetricExporter', () => { - describe('clear metrics on request', () => { - const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE) - assert.ok(exporter, 'exporter exists') +function setup() { + const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE) + const meterProvider = new MeterProvider({ resource: defaultResource }); + const meter = meterProvider.getMeter('InMemoryMetricExporter', '1.0.0'); + const meterReader = new PeriodicExportingMetricReader({ + exporter: exporter, + exportIntervalMillis: 100, + exportTimeoutMillis: 100 + }) + meterProvider.addMetricReader(meterReader); + + return { + meterProvider, + meter, + meterReader, + exporter, + }; +} +async function waitForNumberOfExports(exporter: InMemoryMetricExporter , numberOfExports: number): Promise { + if (numberOfExports <= 0) { + throw new Error('numberOfExports must be greater than or equal to 0'); + } + + let totalExports = 0 + while (totalExports < numberOfExports) { + await new Promise(resolve => setTimeout(resolve, 20)); + const exportedMetrics = exporter.getMetrics() + totalExports = exportedMetrics.length + } + + return exporter.getMetrics() +} + +describe.only('InMemoryMetricExporter', () => { + + it('should be able to access metric', async () => { + const { + meter, + meterReader, + exporter, + } = setup() + + const counter = meter.createCounter('counter_total', { + description: 'a test description', + }); + const counterAttribute = { key1: 'attributeValue1' } + counter.add(10, counterAttribute); + counter.add(10, counterAttribute); + + const histogram = meter.createHistogram('histogram', { description: 'a histogram' }) + histogram.record(10) + histogram.record(100) + histogram.record(1000) + + const exportedMetrics = await waitForNumberOfExports(exporter, 1) + assert.ok(exportedMetrics.length > 0); + + const resourceMetrics = exportedMetrics.shift() + assert.ok(resourceMetrics) + const firstScopeMetric = resourceMetrics?.scopeMetrics.shift() + assert.ok(firstScopeMetric) + assert.ok(firstScopeMetric.metrics.length > 0) + const [counterMetric, histogramMetric] = firstScopeMetric.metrics + assert.ok(counterMetric.descriptor.name, 'counter_total') + assert.ok(counterMetric.dataPoints.length > 0) + const counterDataPoint = counterMetric.dataPoints.shift() + assert.ok(counterDataPoint) + assert.strictEqual(counterDataPoint.attributes, counterAttribute) + + assert.ok(histogramMetric.descriptor.name, 'histogram') + assert.ok(histogramMetric.dataPoints.length > 0) + const histogramDataPoint = histogramMetric.dataPoints.shift() + assert.ok(histogramDataPoint) + + await meterReader.shutdown() }) }) From 02a71f97c21fdd2c8d91dc63c20c830b57d2ba45 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 21 Jun 2022 23:00:56 +0100 Subject: [PATCH 05/16] fix: remove the `clear`-method from `InMemoryMetricExporter`-class --- .../src/export/InMemoryMetricExporter.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts index 805ae394c53..9d04575c4a7 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts @@ -57,13 +57,6 @@ export class InMemoryMetricExporter implements PushMetricExporter { return this._metrics } - /** - * Clear the collected metrics - */ - public clear(): void { - this._metrics = [] - } - async forceFlush() { this._metrics = [] return Promise.resolve() From ed8f681264476a7560f74271ba2998162e0ffa8c Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 21 Jun 2022 23:04:41 +0100 Subject: [PATCH 06/16] fix: add missing `ResourceMetrics` import --- .../test/export/InMemoryMetricExporter.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts index fad1255aa07..a3e86b195ed 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts @@ -16,6 +16,7 @@ import assert = require('assert'); import { AggregationTemporality } from '../../src/export/AggregationTemporality'; import { InMemoryMetricExporter } from "../../src/export/InMemoryMetricExporter" +import { ResourceMetrics } from '../../src/export/MetricData'; import { PeriodicExportingMetricReader } from '../../src/export/PeriodicExportingMetricReader'; import { MeterProvider } from '../../src/MeterProvider'; import { defaultResource } from '../util'; From 7fe960926be9fe8cbaba2860c5e52c80ee6de508 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 21 Jun 2022 23:05:02 +0100 Subject: [PATCH 07/16] style: ran `lint:fix` command on the code base --- .../src/export/InMemoryMetricExporter.ts | 36 +++++------ .../export/InMemoryMetricExporter.test.ts | 64 +++++++++---------- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts index 9d04575c4a7..7834dbe425c 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts @@ -14,12 +14,12 @@ * limitations under the License. */ -import { ExportResultCode } from "@opentelemetry/core" -import { ExportResult } from "@opentelemetry/core" -import { InstrumentType } from "../InstrumentDescriptor" -import { AggregationTemporality } from "./AggregationTemporality" -import { ResourceMetrics } from "./MetricData" -import { PushMetricExporter } from "./MetricExporter" +import { ExportResultCode } from '@opentelemetry/core'; +import { ExportResult } from '@opentelemetry/core'; +import { InstrumentType } from '../InstrumentDescriptor'; +import { AggregationTemporality } from './AggregationTemporality'; +import { ResourceMetrics } from './MetricData'; +import { PushMetricExporter } from './MetricExporter'; /** * In-memory Metrics Exporter is a Push Metric Exporter @@ -27,12 +27,12 @@ import { PushMetricExporter } from "./MetricExporter" * allows to inspect it (useful for e.g. unit tests). */ export class InMemoryMetricExporter implements PushMetricExporter { - protected _shutdown = false - protected _aggregationTemporality: AggregationTemporality - private _metrics: ResourceMetrics[] = [] + protected _shutdown = false; + protected _aggregationTemporality: AggregationTemporality; + private _metrics: ResourceMetrics[] = []; constructor(aggregationTemporality: AggregationTemporality) { - this._aggregationTemporality = aggregationTemporality + this._aggregationTemporality = aggregationTemporality; } /** @@ -42,10 +42,10 @@ export class InMemoryMetricExporter implements PushMetricExporter { // Avoid storing metrics when exporter is shutdown if (this. _shutdown) { process.nextTick(() => resultCallback({ code: ExportResultCode.FAILED })); - return + return; } - this._metrics.push(metrics) + this._metrics.push(metrics); process.nextTick(() => resultCallback({ code: ExportResultCode.SUCCESS })); } @@ -54,20 +54,20 @@ export class InMemoryMetricExporter implements PushMetricExporter { * @returns ResourceMetrics[] */ public getMetrics(): ResourceMetrics[] { - return this._metrics + return this._metrics; } async forceFlush() { - this._metrics = [] - return Promise.resolve() + this._metrics = []; + return Promise.resolve(); } selectAggregationTemporality(_instrumentType: InstrumentType): AggregationTemporality { - return this._aggregationTemporality + return this._aggregationTemporality; } shutdown(): Promise { - this._shutdown = true - return Promise.resolve() + this._shutdown = true; + return Promise.resolve(); } } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts index a3e86b195ed..f8cead6f51f 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts @@ -15,21 +15,21 @@ */ import assert = require('assert'); import { AggregationTemporality } from '../../src/export/AggregationTemporality'; -import { InMemoryMetricExporter } from "../../src/export/InMemoryMetricExporter" +import { InMemoryMetricExporter } from '../../src/export/InMemoryMetricExporter'; import { ResourceMetrics } from '../../src/export/MetricData'; import { PeriodicExportingMetricReader } from '../../src/export/PeriodicExportingMetricReader'; import { MeterProvider } from '../../src/MeterProvider'; import { defaultResource } from '../util'; function setup() { - const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE) + const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE); const meterProvider = new MeterProvider({ resource: defaultResource }); const meter = meterProvider.getMeter('InMemoryMetricExporter', '1.0.0'); const meterReader = new PeriodicExportingMetricReader({ exporter: exporter, exportIntervalMillis: 100, exportTimeoutMillis: 100 - }) + }); meterProvider.addMetricReader(meterReader); return { @@ -44,14 +44,14 @@ async function waitForNumberOfExports(exporter: InMemoryMetricExporter , numberO throw new Error('numberOfExports must be greater than or equal to 0'); } - let totalExports = 0 + let totalExports = 0; while (totalExports < numberOfExports) { await new Promise(resolve => setTimeout(resolve, 20)); - const exportedMetrics = exporter.getMetrics() - totalExports = exportedMetrics.length + const exportedMetrics = exporter.getMetrics(); + totalExports = exportedMetrics.length; } - return exporter.getMetrics() + return exporter.getMetrics(); } describe.only('InMemoryMetricExporter', () => { @@ -61,40 +61,40 @@ describe.only('InMemoryMetricExporter', () => { meter, meterReader, exporter, - } = setup() + } = setup(); const counter = meter.createCounter('counter_total', { description: 'a test description', }); - const counterAttribute = { key1: 'attributeValue1' } + const counterAttribute = { key1: 'attributeValue1' }; counter.add(10, counterAttribute); counter.add(10, counterAttribute); - const histogram = meter.createHistogram('histogram', { description: 'a histogram' }) - histogram.record(10) - histogram.record(100) - histogram.record(1000) + const histogram = meter.createHistogram('histogram', { description: 'a histogram' }); + histogram.record(10); + histogram.record(100); + histogram.record(1000); - const exportedMetrics = await waitForNumberOfExports(exporter, 1) + const exportedMetrics = await waitForNumberOfExports(exporter, 1); assert.ok(exportedMetrics.length > 0); - const resourceMetrics = exportedMetrics.shift() - assert.ok(resourceMetrics) - const firstScopeMetric = resourceMetrics?.scopeMetrics.shift() - assert.ok(firstScopeMetric) - assert.ok(firstScopeMetric.metrics.length > 0) - const [counterMetric, histogramMetric] = firstScopeMetric.metrics - assert.ok(counterMetric.descriptor.name, 'counter_total') - assert.ok(counterMetric.dataPoints.length > 0) - const counterDataPoint = counterMetric.dataPoints.shift() - assert.ok(counterDataPoint) - assert.strictEqual(counterDataPoint.attributes, counterAttribute) + const resourceMetrics = exportedMetrics.shift(); + assert.ok(resourceMetrics); + const firstScopeMetric = resourceMetrics?.scopeMetrics.shift(); + assert.ok(firstScopeMetric); + assert.ok(firstScopeMetric.metrics.length > 0); + const [counterMetric, histogramMetric] = firstScopeMetric.metrics; + assert.ok(counterMetric.descriptor.name, 'counter_total'); + assert.ok(counterMetric.dataPoints.length > 0); + const counterDataPoint = counterMetric.dataPoints.shift(); + assert.ok(counterDataPoint); + assert.strictEqual(counterDataPoint.attributes, counterAttribute); - assert.ok(histogramMetric.descriptor.name, 'histogram') - assert.ok(histogramMetric.dataPoints.length > 0) - const histogramDataPoint = histogramMetric.dataPoints.shift() - assert.ok(histogramDataPoint) + assert.ok(histogramMetric.descriptor.name, 'histogram'); + assert.ok(histogramMetric.dataPoints.length > 0); + const histogramDataPoint = histogramMetric.dataPoints.shift(); + assert.ok(histogramDataPoint); - await meterReader.shutdown() - }) -}) + await meterReader.shutdown(); + }); +}); From 9eabdda0b4add6e474babf88ac88f709028b78ac Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 21 Jun 2022 23:11:58 +0100 Subject: [PATCH 08/16] docs: add CHANGELOG.md entry for the new `InMemoryMetricExporter`-class --- experimental/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index ac352ef3c39..8a39667f1a8 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to experimental packages in this project will be documented * feat(http-instrumentation): record exceptions in http instrumentation #3008 @luismiramirez * feat(node-sdk): add serviceName config option #2867 @naseemkullah * feat(opentelemetry-exporter-prometheus): export PrometheusSerializer #3034 @matschaffer +* feat(opentelemetry-sdk-metrics-base): added InMemoryMetricExporter #3039 @weyert ### :bug: (Bug Fix) From fffcee2a6c8ca630171e288de81b153459809ff7 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 21 Jun 2022 23:23:02 +0100 Subject: [PATCH 09/16] test: drop the `describe.only` --- .../test/export/InMemoryMetricExporter.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts index f8cead6f51f..398214745b4 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts @@ -54,7 +54,7 @@ async function waitForNumberOfExports(exporter: InMemoryMetricExporter , numberO return exporter.getMetrics(); } -describe.only('InMemoryMetricExporter', () => { +describe('InMemoryMetricExporter', () => { it('should be able to access metric', async () => { const { From 5ff683eeeac91f1c518419348fb3e3363e6c7a1e Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Tue, 21 Jun 2022 23:52:49 +0100 Subject: [PATCH 10/16] test: improve test coverage --- .../export/InMemoryMetricExporter.test.ts | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts index 398214745b4..fcb8c1f5546 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { ExportResultCode } from '@opentelemetry/core'; +import { Resource } from '@opentelemetry/resources'; import assert = require('assert'); import { AggregationTemporality } from '../../src/export/AggregationTemporality'; import { InMemoryMetricExporter } from '../../src/export/InMemoryMetricExporter'; @@ -56,6 +58,60 @@ async function waitForNumberOfExports(exporter: InMemoryMetricExporter , numberO describe('InMemoryMetricExporter', () => { + it('should return failed result code', done => { + const { exporter, meterReader } = setup(); + exporter.shutdown().then(() => { + const resource = new Resource({ + 'resource-attribute': 'resource attribute value', + }); + const resourceMetrics: ResourceMetrics = { + resource: resource, + scopeMetrics: + [ + { + scope: { + name: 'mylib', + version: '0.1.0', + schemaUrl: 'http://url.to.schema' + }, + metrics: [], + } + ] + }; + exporter.export(resourceMetrics, result => { + assert.ok(result.code === ExportResultCode.FAILED); + meterReader.shutdown().then(() => { + done(); + }); + }); + }); + }); + + it('should reset metrics when forceFlush is called', async () => { + const { + meter, + meterReader, + exporter, + } = setup(); + + const counter = meter.createCounter('counter_total', { + description: 'a test description', + }); + const counterAttribute = { key1: 'attributeValue1' }; + counter.add(10, counterAttribute); + + const exportedMetrics = await waitForNumberOfExports(exporter, 1); + assert.ok(exportedMetrics.length > 0); + + await exporter.forceFlush(); + + const otherMetrics = exporter.getMetrics(); + assert.ok(otherMetrics.length === 0); + + await exporter.shutdown(); + await meterReader.shutdown(); + }); + it('should be able to access metric', async () => { const { meter, @@ -97,4 +153,6 @@ describe('InMemoryMetricExporter', () => { await meterReader.shutdown(); }); + + }); From 06a72a8637fb9c3cc7c439a24840c72bced489eb Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Mon, 25 Jul 2022 15:26:38 -0400 Subject: [PATCH 11/16] Split reset and forceFlush --- .../src/export/InMemoryMetricExporter.ts | 5 +- .../export/InMemoryMetricExporter.test.ts | 46 ++++++++++--------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts index 7834dbe425c..7fb5e16dcf8 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts @@ -58,10 +58,13 @@ export class InMemoryMetricExporter implements PushMetricExporter { } async forceFlush() { - this._metrics = []; return Promise.resolve(); } + reset() { + this._metrics = []; + } + selectAggregationTemporality(_instrumentType: InstrumentType): AggregationTemporality { return this._aggregationTemporality; } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts index fcb8c1f5546..6d35b7ec0f7 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts @@ -20,27 +20,10 @@ import { AggregationTemporality } from '../../src/export/AggregationTemporality' import { InMemoryMetricExporter } from '../../src/export/InMemoryMetricExporter'; import { ResourceMetrics } from '../../src/export/MetricData'; import { PeriodicExportingMetricReader } from '../../src/export/PeriodicExportingMetricReader'; +import { Meter } from '../../src/Meter'; import { MeterProvider } from '../../src/MeterProvider'; import { defaultResource } from '../util'; -function setup() { - const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE); - const meterProvider = new MeterProvider({ resource: defaultResource }); - const meter = meterProvider.getMeter('InMemoryMetricExporter', '1.0.0'); - const meterReader = new PeriodicExportingMetricReader({ - exporter: exporter, - exportIntervalMillis: 100, - exportTimeoutMillis: 100 - }); - meterProvider.addMetricReader(meterReader); - - return { - meterProvider, - meter, - meterReader, - exporter, - }; -} async function waitForNumberOfExports(exporter: InMemoryMetricExporter , numberOfExports: number): Promise { if (numberOfExports <= 0) { throw new Error('numberOfExports must be greater than or equal to 0'); @@ -57,6 +40,27 @@ async function waitForNumberOfExports(exporter: InMemoryMetricExporter , numberO } describe('InMemoryMetricExporter', () => { + let exporter: InMemoryMetricExporter; + let meterProvider: MeterProvider; + let meterReader: PeriodicExportingMetricReader; + let meter: MeterProvider; + + beforeEach(() => { + exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE); + meterProvider = new MeterProvider({ resource: defaultResource }); + meter = meterProvider.getMeter('InMemoryMetricExporter', '1.0.0'); + meterReader = new PeriodicExportingMetricReader({ + exporter: exporter, + exportIntervalMillis: 100, + exportTimeoutMillis: 100 + }); + meterProvider.addMetricReader(meterReader); + }); + + afterEach(async () => { + await exporter.shutdown(); + await meterReader.shutdown(); + }); it('should return failed result code', done => { const { exporter, meterReader } = setup(); @@ -87,7 +91,7 @@ describe('InMemoryMetricExporter', () => { }); }); - it('should reset metrics when forceFlush is called', async () => { + it('should reset metrics when reset is called', async () => { const { meter, meterReader, @@ -103,7 +107,7 @@ describe('InMemoryMetricExporter', () => { const exportedMetrics = await waitForNumberOfExports(exporter, 1); assert.ok(exportedMetrics.length > 0); - await exporter.forceFlush(); + exporter.reset(); const otherMetrics = exporter.getMetrics(); assert.ok(otherMetrics.length === 0); @@ -153,6 +157,4 @@ describe('InMemoryMetricExporter', () => { await meterReader.shutdown(); }); - - }); From 4e72a8bd192aa51af73054c7141900b9100962f8 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Mon, 25 Jul 2022 15:30:56 -0400 Subject: [PATCH 12/16] fix: remove meterprovider typo --- .../test/export/InMemoryMetricExporter.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts index 6d35b7ec0f7..7fa9318a2be 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts @@ -43,7 +43,7 @@ describe('InMemoryMetricExporter', () => { let exporter: InMemoryMetricExporter; let meterProvider: MeterProvider; let meterReader: PeriodicExportingMetricReader; - let meter: MeterProvider; + let meter: Meter; beforeEach(() => { exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE); From da2355c5f3658726e11666e43bbef0390d1bce5b Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Mon, 25 Jul 2022 15:36:10 -0400 Subject: [PATCH 13/16] Remove calls to missing setup method --- .../test/export/InMemoryMetricExporter.test.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts index 7fa9318a2be..11aa6ebd780 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts @@ -63,7 +63,6 @@ describe('InMemoryMetricExporter', () => { }); it('should return failed result code', done => { - const { exporter, meterReader } = setup(); exporter.shutdown().then(() => { const resource = new Resource({ 'resource-attribute': 'resource attribute value', @@ -92,12 +91,6 @@ describe('InMemoryMetricExporter', () => { }); it('should reset metrics when reset is called', async () => { - const { - meter, - meterReader, - exporter, - } = setup(); - const counter = meter.createCounter('counter_total', { description: 'a test description', }); @@ -117,12 +110,6 @@ describe('InMemoryMetricExporter', () => { }); it('should be able to access metric', async () => { - const { - meter, - meterReader, - exporter, - } = setup(); - const counter = meter.createCounter('counter_total', { description: 'a test description', }); From b95cbef08a3574e4408e3b51669cc9db845de1cb Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Mon, 25 Jul 2022 15:50:34 -0400 Subject: [PATCH 14/16] Use api meter in test --- .../test/export/InMemoryMetricExporter.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts index 11aa6ebd780..7afb3299a46 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/InMemoryMetricExporter.test.ts @@ -15,12 +15,12 @@ */ import { ExportResultCode } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; +import * as metrics from '@opentelemetry/api-metrics'; import assert = require('assert'); import { AggregationTemporality } from '../../src/export/AggregationTemporality'; import { InMemoryMetricExporter } from '../../src/export/InMemoryMetricExporter'; import { ResourceMetrics } from '../../src/export/MetricData'; import { PeriodicExportingMetricReader } from '../../src/export/PeriodicExportingMetricReader'; -import { Meter } from '../../src/Meter'; import { MeterProvider } from '../../src/MeterProvider'; import { defaultResource } from '../util'; @@ -43,7 +43,7 @@ describe('InMemoryMetricExporter', () => { let exporter: InMemoryMetricExporter; let meterProvider: MeterProvider; let meterReader: PeriodicExportingMetricReader; - let meter: Meter; + let meter: metrics.Meter; beforeEach(() => { exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE); From c86c525ba60052a9b2539fad397ce65d5afba627 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Tue, 26 Jul 2022 07:58:50 -0400 Subject: [PATCH 15/16] Browser support --- .../src/export/InMemoryMetricExporter.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts index 7fb5e16dcf8..11a6330ec06 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts @@ -41,12 +41,16 @@ export class InMemoryMetricExporter implements PushMetricExporter { export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void { // Avoid storing metrics when exporter is shutdown if (this. _shutdown) { - process.nextTick(() => resultCallback({ code: ExportResultCode.FAILED })); + setTimeout(() => { + resultCallback({ code: ExportResultCode.FAILED }) + }, 0); return; } this._metrics.push(metrics); - process.nextTick(() => resultCallback({ code: ExportResultCode.SUCCESS })); + setTimeout(() => { + resultCallback({ code: ExportResultCode.SUCCESS }) + }, 0); } /** From b0657581f6b86f2c7b0b11676ebb5fdbee214850 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Tue, 26 Jul 2022 08:10:00 -0400 Subject: [PATCH 16/16] style: lint --- .../src/export/InMemoryMetricExporter.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts index 11a6330ec06..c0ec67e74ab 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/InMemoryMetricExporter.ts @@ -41,16 +41,12 @@ export class InMemoryMetricExporter implements PushMetricExporter { export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void { // Avoid storing metrics when exporter is shutdown if (this. _shutdown) { - setTimeout(() => { - resultCallback({ code: ExportResultCode.FAILED }) - }, 0); + setTimeout(() => resultCallback({ code: ExportResultCode.FAILED }), 0); return; } this._metrics.push(metrics); - setTimeout(() => { - resultCallback({ code: ExportResultCode.SUCCESS }) - }, 0); + setTimeout(() => resultCallback({ code: ExportResultCode.SUCCESS }), 0); } /** @@ -61,7 +57,7 @@ export class InMemoryMetricExporter implements PushMetricExporter { return this._metrics; } - async forceFlush() { + forceFlush(): Promise { return Promise.resolve(); }