diff --git a/CHANGELOG.md b/CHANGELOG.md index dcff93ca76..8b8c5fac1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### :boom: Breaking Change +* feat(metrics): metric readers and exporters now select aggregation temporality based on instrument type [#2902](https://github.com/open-telemetry/opentelemetry-js/pull/2902) @seemk * chore: remove unused InstrumentationConfig#path [#2944](https://github.com/open-telemetry/opentelemetry-js/pull/2944) @flarna ### :rocket: (Enhancement) diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts index 3d7b178352..f7f45114be 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts @@ -15,12 +15,11 @@ */ import { - defaultExporterTemporality, defaultOptions, OTLPMetricExporterBase, OTLPMetricExporterOptions } from '@opentelemetry/exporter-metrics-otlp-http'; -import { AggregationTemporality, ResourceMetrics } from '@opentelemetry/sdk-metrics-base'; +import { ResourceMetrics } from '@opentelemetry/sdk-metrics-base'; import { OTLPGRPCExporterConfigNode, OTLPGRPCExporterNodeBase, @@ -34,9 +33,7 @@ import { createExportMetricsServiceRequest, IExportMetricsServiceRequest } from const DEFAULT_COLLECTOR_URL = 'localhost:4317'; -class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase { - protected readonly _aggregationTemporality: AggregationTemporality; +class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase { constructor(config: OTLPGRPCExporterConfigNode & OTLPMetricExporterOptions= defaultOptions) { super(config); @@ -45,7 +42,6 @@ class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase url: 'grpcs://' + address, credentials, metadata: params.metadata, - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }); setUp(); @@ -182,7 +182,7 @@ const testOTLPMetricExporter = (params: TestParams) => headers: { foo: 'bar', }, - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }); const args = warnStub.args[0]; assert.strictEqual(args[0], 'Headers cannot be set when using grpc'); @@ -190,7 +190,7 @@ const testOTLPMetricExporter = (params: TestParams) => it('should warn about path in url', () => { collectorExporter = new OTLPMetricExporter({ url: `http://${address}/v1/metrics`, - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }); const args = warnStub.args[0]; assert.strictEqual( @@ -262,7 +262,7 @@ describe('OTLPMetricExporter - node (getDefaultUrl)', () => { const url = 'http://foo.bar.com'; const collectorExporter = new OTLPMetricExporter({ url, - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }); setTimeout(() => { assert.strictEqual(collectorExporter._otlpExporter.url, 'foo.bar.com'); @@ -307,7 +307,7 @@ describe('when configuring via environment', () => { envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo'; const collectorExporter = new OTLPMetricExporter({ metadata, - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }); assert.deepStrictEqual(collectorExporter._otlpExporter.metadata?.get('foo'), ['boo']); assert.deepStrictEqual(collectorExporter._otlpExporter.metadata?.get('bar'), ['foo']); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/metricsHelper.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/metricsHelper.ts index 7f33ceb9ef..54bd6ee553 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/metricsHelper.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/metricsHelper.ts @@ -19,10 +19,19 @@ import { Resource } from '@opentelemetry/resources'; import * as assert from 'assert'; import * as grpc from '@grpc/grpc-js'; import { VERSION } from '@opentelemetry/core'; -import { ExplicitBucketHistogramAggregation, MeterProvider, MetricReader } from '@opentelemetry/sdk-metrics-base'; +import { + AggregationTemporality, + ExplicitBucketHistogramAggregation, + MeterProvider, + MetricReader, +} from '@opentelemetry/sdk-metrics-base'; import { IKeyValue, IMetric, IResource } from '@opentelemetry/otlp-transformer'; -export class TestMetricReader extends MetricReader { +class TestMetricReader extends MetricReader { + selectAggregationTemporality() { + return AggregationTemporality.CUMULATIVE; + } + protected onForceFlush(): Promise { return Promise.resolve(undefined); } diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterBase.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterBase.ts index 5d06cd60bd..059d44eeca 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterBase.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterBase.ts @@ -15,22 +15,51 @@ */ import { ExportResult } from '@opentelemetry/core'; -import { AggregationTemporality, PushMetricExporter, ResourceMetrics } from '@opentelemetry/sdk-metrics-base'; +import { + AggregationTemporality, + AggregationTemporalitySelector, + InstrumentType, + PushMetricExporter, + ResourceMetrics +} from '@opentelemetry/sdk-metrics-base'; import { defaultOptions, OTLPMetricExporterOptions } from './OTLPMetricExporterOptions'; import { OTLPExporterBase } from '@opentelemetry/otlp-exporter-base'; import { IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer'; +export const CumulativeTemporalitySelector: AggregationTemporalitySelector = () => AggregationTemporality.CUMULATIVE; + +export const DeltaTemporalitySelector: AggregationTemporalitySelector = (instrumentType: InstrumentType) => { + switch (instrumentType) { + case InstrumentType.COUNTER: + case InstrumentType.OBSERVABLE_COUNTER: + case InstrumentType.HISTOGRAM: + case InstrumentType.OBSERVABLE_GAUGE: + return AggregationTemporality.DELTA; + case InstrumentType.UP_DOWN_COUNTER: + case InstrumentType.OBSERVABLE_UP_DOWN_COUNTER: + return AggregationTemporality.CUMULATIVE; + } +}; + +function chooseTemporalitySelector(temporalityPreference?: AggregationTemporality): AggregationTemporalitySelector { + if (temporalityPreference === AggregationTemporality.DELTA) { + return DeltaTemporalitySelector; + } + + return CumulativeTemporalitySelector; +} + export class OTLPMetricExporterBase> implements PushMetricExporter { public _otlpExporter: T; - protected _preferredAggregationTemporality: AggregationTemporality; + protected _aggregationTemporalitySelector: AggregationTemporalitySelector; constructor(exporter: T, config: OTLPMetricExporterOptions = defaultOptions) { this._otlpExporter = exporter; - this._preferredAggregationTemporality = config.aggregationTemporality ?? AggregationTemporality.CUMULATIVE; + this._aggregationTemporalitySelector = chooseTemporalitySelector(config.temporalityPreference); } export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void { @@ -45,7 +74,7 @@ implements PushMetricExporter { return Promise.resolve(); } - getPreferredAggregationTemporality(): AggregationTemporality { - return this._preferredAggregationTemporality; + selectAggregationTemporality(instrumentType: InstrumentType): AggregationTemporality { + return this._aggregationTemporalitySelector(instrumentType); } } diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterOptions.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterOptions.ts index 59cc20065e..a9f601992f 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterOptions.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterOptions.ts @@ -18,7 +18,7 @@ import { AggregationTemporality } from '@opentelemetry/sdk-metrics-base'; import { OTLPExporterConfigBase } from '@opentelemetry/otlp-exporter-base'; export interface OTLPMetricExporterOptions extends OTLPExporterConfigBase { - aggregationTemporality?: AggregationTemporality + temporalityPreference?: AggregationTemporality } export const defaultExporterTemporality = AggregationTemporality.CUMULATIVE; -export const defaultOptions = {aggregationTemporality: defaultExporterTemporality}; +export const defaultOptions = {temporalityPreference: defaultExporterTemporality}; diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/browser/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/browser/OTLPMetricExporter.ts index 0189b6d9b3..16dfd998bf 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/browser/OTLPMetricExporter.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/browser/OTLPMetricExporter.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { AggregationTemporality, ResourceMetrics } from '@opentelemetry/sdk-metrics-base'; +import { ResourceMetrics } from '@opentelemetry/sdk-metrics-base'; import { baggageUtils, getEnv } from '@opentelemetry/core'; -import { defaultExporterTemporality, defaultOptions, OTLPMetricExporterOptions } from '../../OTLPMetricExporterOptions'; +import { defaultOptions, OTLPMetricExporterOptions } from '../../OTLPMetricExporterOptions'; import { OTLPMetricExporterBase } from '../../OTLPMetricExporterBase'; import { appendResourcePathToUrlIfNotPresent, @@ -28,9 +28,7 @@ import { createExportMetricsServiceRequest, IExportMetricsServiceRequest } from const DEFAULT_COLLECTOR_RESOURCE_PATH = '/v1/metrics'; const DEFAULT_COLLECTOR_URL = `http://localhost:4318${DEFAULT_COLLECTOR_RESOURCE_PATH}`; -class OTLPExporterBrowserProxy extends OTLPExporterBrowserBase { - protected readonly _aggregationTemporality: AggregationTemporality; +class OTLPExporterBrowserProxy extends OTLPExporterBrowserBase { constructor(config: OTLPMetricExporterOptions & OTLPExporterConfigBase = defaultOptions) { super(config); @@ -40,7 +38,6 @@ class OTLPExporterBrowserProxy extends OTLPExporterBrowserBase { - protected readonly _aggregationTemporality: AggregationTemporality; +class OTLPExporterNodeProxy extends OTLPExporterNodeBase { constructor(config: OTLPExporterNodeConfigBase & OTLPMetricExporterOptions = defaultOptions) { super(config); @@ -40,14 +38,10 @@ class OTLPExporterNodeProxy extends OTLPExporterNodeBase { beforeEach(() => { collectorExporter = new OTLPMetricExporter({ url: 'http://foo.bar.com', - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }); }); it('should successfully send metrics using sendBeacon', done => { @@ -191,7 +191,7 @@ describe('OTLPMetricExporter - web', () => { (window.navigator as any).sendBeacon = false; collectorExporter = new OTLPMetricExporter({ url: 'http://foo.bar.com', - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }); // Overwrites the start time to make tests consistent Object.defineProperty(collectorExporter, '_startTime', { @@ -316,7 +316,7 @@ describe('OTLPMetricExporter - web', () => { beforeEach(() => { collectorExporterConfig = { headers: customHeaders, - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }; server = sinon.fakeServer.create(); }); @@ -408,7 +408,7 @@ describe('when configuring via environment', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPMetricExporter({ headers: {}, - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }); assert.strictEqual(collectorExporter['_otlpExporter']['_headers'].foo, 'bar'); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; @@ -418,7 +418,7 @@ describe('when configuring via environment', () => { envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo'; const collectorExporter = new OTLPMetricExporter({ headers: {}, - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }); assert.strictEqual(collectorExporter['_otlpExporter']['_headers'].foo, 'boo'); assert.strictEqual(collectorExporter['_otlpExporter']['_headers'].bar, 'foo'); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/metricsHelper.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/metricsHelper.ts index 457b525f19..66cd9b66bc 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/metricsHelper.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/metricsHelper.ts @@ -24,6 +24,7 @@ import { Resource } from '@opentelemetry/resources'; import * as assert from 'assert'; import { InstrumentationLibrary, VERSION } from '@opentelemetry/core'; import { + AggregationTemporality, ExplicitBucketHistogramAggregation, MeterProvider, MetricReader @@ -43,7 +44,7 @@ if (typeof Buffer === 'undefined') { }; } -export class TestMetricReader extends MetricReader { +class TestMetricReader extends MetricReader { protected onForceFlush(): Promise { return Promise.resolve(undefined); } @@ -51,6 +52,10 @@ export class TestMetricReader extends MetricReader { protected onShutdown(): Promise { return Promise.resolve(undefined); } + + selectAggregationTemporality() { + return AggregationTemporality.CUMULATIVE; + } } const defaultResource = Resource.default().merge(new Resource({ diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts index 93c9ba70e1..33f768207a 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts @@ -163,7 +163,7 @@ describe('OTLPMetricExporter - node with json over http', () => { url: 'http://foo.bar.com', keepAlive: true, httpAgentOptions: { keepAliveMsecs: 2000 }, - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }; collectorExporter = new OTLPMetricExporter(collectorExporterConfig); @@ -329,7 +329,7 @@ describe('OTLPMetricExporter - node with json over http', () => { const url = 'http://foo.bar.com'; const collectorExporter = new OTLPMetricExporter({ url, - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }); setTimeout(() => { assert.strictEqual(collectorExporter._otlpExporter.url, url); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts index eee22e33d9..ffcbede041 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts @@ -14,13 +14,12 @@ * limitations under the License. */ import { - defaultExporterTemporality, defaultOptions, OTLPMetricExporterOptions } from '@opentelemetry/exporter-metrics-otlp-http'; import { ServiceClientType, OTLPProtoExporterNodeBase } from '@opentelemetry/otlp-proto-exporter-base'; import { getEnv, baggageUtils} from '@opentelemetry/core'; -import { AggregationTemporality, ResourceMetrics} from '@opentelemetry/sdk-metrics-base'; +import { ResourceMetrics} from '@opentelemetry/sdk-metrics-base'; import { OTLPMetricExporterBase } from '@opentelemetry/exporter-metrics-otlp-http'; import { appendResourcePathToUrlIfNotPresent, OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base'; import { createExportMetricsServiceRequest, IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer'; @@ -29,9 +28,7 @@ const DEFAULT_COLLECTOR_RESOURCE_PATH = '/v1/metrics'; const DEFAULT_COLLECTOR_URL = `http://localhost:4318${DEFAULT_COLLECTOR_RESOURCE_PATH}`; -class OTLPMetricExporterNodeProxy extends OTLPProtoExporterNodeBase { - protected readonly _aggregationTemporality: AggregationTemporality; +class OTLPMetricExporterNodeProxy extends OTLPProtoExporterNodeBase { constructor(config: OTLPExporterNodeConfigBase & OTLPMetricExporterOptions = defaultOptions) { super(config); @@ -41,14 +38,10 @@ class OTLPMetricExporterNodeProxy extends OTLPProtoExporterNodeBase { url: 'http://foo.bar.com', keepAlive: true, httpAgentOptions: { keepAliveMsecs: 2000 }, - aggregationTemporality: AggregationTemporality.CUMULATIVE + temporalityPreference: AggregationTemporality.CUMULATIVE }; collectorExporter = new OTLPMetricExporter(collectorExporterConfig); setUp(); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/metricsHelper.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/metricsHelper.ts index 1006f34804..80d38bd164 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/metricsHelper.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/metricsHelper.ts @@ -23,6 +23,7 @@ import { import { Resource } from '@opentelemetry/resources'; import * as assert from 'assert'; import { + AggregationTemporality, ExplicitBucketHistogramAggregation, MeterProvider, MetricReader @@ -31,6 +32,10 @@ import { IExportMetricsServiceRequest, IKeyValue, IMetric } from '@opentelemetry import { Stream } from 'stream'; export class TestMetricReader extends MetricReader { + selectAggregationTemporality() { + return AggregationTemporality.CUMULATIVE; + } + protected onForceFlush(): Promise { return Promise.resolve(undefined); } diff --git a/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusExporter.ts b/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusExporter.ts index 0be01d6c75..aa7491bc77 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusExporter.ts +++ b/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusExporter.ts @@ -55,7 +55,7 @@ export class PrometheusExporter extends MetricReader { * @param callback Callback to be called after a server was started */ constructor(config: ExporterConfig = {}, callback?: () => void) { - super(AggregationTemporality.CUMULATIVE); + super(); this._host = config.host || process.env.OTEL_EXPORTER_PROMETHEUS_HOST || @@ -90,6 +90,10 @@ export class PrometheusExporter extends MetricReader { } } + selectAggregationTemporality(): AggregationTemporality { + return AggregationTemporality.CUMULATIVE; + } + override async onForceFlush(): Promise { /** do nothing */ } diff --git a/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts b/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts index c71c01310a..bd1a6b4602 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts +++ b/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts @@ -37,8 +37,13 @@ const attributes = { class TestMetricReader extends MetricReader { constructor() { - super(AggregationTemporality.CUMULATIVE); + super(); } + + selectAggregationTemporality() { + return AggregationTemporality.CUMULATIVE; + } + async onForceFlush() {} async onShutdown() {} } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Drop.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Drop.ts index 441ca6e8e4..56ef74e554 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Drop.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Drop.ts @@ -15,6 +15,7 @@ */ import { HrTime } from '@opentelemetry/api'; +import { AggregationTemporality } from '../export/AggregationTemporality'; import { MetricData } from '../export/MetricData'; import { InstrumentDescriptor } from '../InstrumentDescriptor'; import { Maybe } from '../utils'; @@ -42,6 +43,7 @@ export class DropAggregator implements Aggregator { toMetricData( _descriptor: InstrumentDescriptor, + _aggregationTemporality: AggregationTemporality, _accumulationByAttributes: AccumulationRecord[], _startTime: HrTime, _endTime: HrTime): Maybe { diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Histogram.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Histogram.ts index f3f1782d31..bcfa4f69eb 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Histogram.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Histogram.ts @@ -25,6 +25,7 @@ import { HistogramMetricData, DataPointType } from '../export/MetricData'; import { HrTime } from '@opentelemetry/api'; import { InstrumentDescriptor } from '../InstrumentDescriptor'; import { Maybe } from '../utils'; +import { AggregationTemporality } from '../export/AggregationTemporality'; function createNewEmptyCheckpoint(boundaries: number[]): Histogram { const counts = boundaries.map(() => 0); @@ -134,11 +135,13 @@ export class HistogramAggregator implements Aggregator { toMetricData( descriptor: InstrumentDescriptor, + aggregationTemporality: AggregationTemporality, accumulationByAttributes: AccumulationRecord[], startTime: HrTime, endTime: HrTime): Maybe { return { descriptor, + aggregationTemporality, dataPointType: DataPointType.HISTOGRAM, dataPoints: accumulationByAttributes.map(([attributes, accumulation]) => { return { diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/LastValue.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/LastValue.ts index f73891afe2..a6ec036564 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/LastValue.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/LastValue.ts @@ -20,6 +20,7 @@ import { hrTime, hrTimeToMicroseconds } from '@opentelemetry/core'; import { DataPointType, SingularMetricData } from '../export/MetricData'; import { InstrumentDescriptor } from '../InstrumentDescriptor'; import { Maybe } from '../utils'; +import { AggregationTemporality } from '../export/AggregationTemporality'; export class LastValueAccumulation implements Accumulation { constructor(private _current: number = 0, public sampleTime: HrTime = [0, 0]) {} @@ -67,11 +68,13 @@ export class LastValueAggregator implements Aggregator { toMetricData( descriptor: InstrumentDescriptor, + aggregationTemporality: AggregationTemporality, accumulationByAttributes: AccumulationRecord[], startTime: HrTime, endTime: HrTime): Maybe { return { descriptor, + aggregationTemporality, dataPointType: DataPointType.SINGULAR, dataPoints: accumulationByAttributes.map(([attributes, accumulation]) => { return { diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Sum.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Sum.ts index 0b21c7a417..3b8647d730 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Sum.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/Sum.ts @@ -19,6 +19,7 @@ import { HrTime } from '@opentelemetry/api'; import { DataPointType, SingularMetricData } from '../export/MetricData'; import { InstrumentDescriptor } from '../InstrumentDescriptor'; import { Maybe } from '../utils'; +import { AggregationTemporality } from '../export/AggregationTemporality'; export class SumAccumulation implements Accumulation { constructor(private _current: number = 0) {} @@ -56,11 +57,13 @@ export class SumAggregator implements Aggregator { toMetricData( descriptor: InstrumentDescriptor, + aggregationTemporality: AggregationTemporality, accumulationByAttributes: AccumulationRecord[], startTime: HrTime, endTime: HrTime): Maybe { return { descriptor, + aggregationTemporality, dataPointType: DataPointType.SINGULAR, dataPoints: accumulationByAttributes.map(([attributes, accumulation]) => { return { diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/types.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/types.ts index 7c972070ba..403eb65155 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/types.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/aggregator/types.ts @@ -16,6 +16,7 @@ import { HrTime } from '@opentelemetry/api'; import { MetricAttributes } from '@opentelemetry/api-metrics'; +import { AggregationTemporality } from '../export/AggregationTemporality'; import { MetricData } from '../export/MetricData'; import { InstrumentDescriptor } from '../InstrumentDescriptor'; import { Maybe } from '../utils'; @@ -113,6 +114,7 @@ export interface Aggregator { * @return the {@link MetricData} that this {@link Aggregator} will produce. */ toMetricData(descriptor: InstrumentDescriptor, + aggregationTemporality: AggregationTemporality, accumulationByAttributes: AccumulationRecord[], startTime: HrTime, endTime: HrTime): Maybe; diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/AggregationTemporality.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/AggregationTemporality.ts index 6cc6d1231b..0b93671472 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/AggregationTemporality.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/AggregationTemporality.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { InstrumentType } from '../InstrumentDescriptor'; + /** * AggregationTemporality indicates the way additive quantities are expressed. */ @@ -21,3 +23,5 @@ export enum AggregationTemporality { DELTA, CUMULATIVE, } + +export type AggregationTemporalitySelector = (instrumentType: InstrumentType) => AggregationTemporality; diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricData.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricData.ts index 620039cc23..85a5db05ec 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricData.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricData.ts @@ -20,12 +20,14 @@ import { InstrumentationLibrary } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; import { InstrumentDescriptor } from '../InstrumentDescriptor'; import { Histogram } from '../aggregator/types'; +import { AggregationTemporality } from './AggregationTemporality'; /** * Basic metric data fields. */ export interface BaseMetricData { readonly descriptor: InstrumentDescriptor; + readonly aggregationTemporality: AggregationTemporality; /** * DataPointType of the metric instrument. */ diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricExporter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricExporter.ts index 06375d4da5..2460a495ca 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricExporter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricExporter.ts @@ -20,6 +20,7 @@ import { ExportResult, ExportResultCode, } from '@opentelemetry/core'; +import { InstrumentType } from '../InstrumentDescriptor'; // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#metricexporter @@ -30,7 +31,7 @@ export interface PushMetricExporter { forceFlush(): Promise; - getPreferredAggregationTemporality(): AggregationTemporality; + selectAggregationTemporality(instrumentType: InstrumentType): AggregationTemporality; shutdown(): Promise; @@ -38,6 +39,11 @@ export interface PushMetricExporter { export class ConsoleMetricExporter implements PushMetricExporter { protected _shutdown = true; + private _aggregationTemporality: AggregationTemporality; + + constructor(aggregationTemporality?: AggregationTemporality) { + this._aggregationTemporality = aggregationTemporality ?? AggregationTemporality.CUMULATIVE; + } export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void) { return resultCallback({ @@ -46,8 +52,8 @@ export class ConsoleMetricExporter implements PushMetricExporter { }); } - getPreferredAggregationTemporality() { - return AggregationTemporality.CUMULATIVE; + selectAggregationTemporality(_instrumentType: InstrumentType) { + return this._aggregationTemporality; } // nothing to do diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricReader.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricReader.ts index 166819df92..44581649f0 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricReader.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricReader.ts @@ -19,6 +19,7 @@ import { AggregationTemporality } from './AggregationTemporality'; import { MetricProducer } from './MetricProducer'; import { ResourceMetrics } from './MetricData'; import { callWithTimeout, Maybe } from '../utils'; +import { InstrumentType } from '../InstrumentDescriptor'; import { CollectionOptions, ForceFlushOptions, ShutdownOptions } from '../types'; // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#metricreader @@ -34,9 +35,6 @@ export abstract class MetricReader { // MetricProducer used by this instance. private _metricProducer?: MetricProducer; - constructor(private readonly _preferredAggregationTemporality = AggregationTemporality.CUMULATIVE) { - } - /** * Set the {@link MetricProducer} used by this instance. * @@ -51,11 +49,9 @@ export abstract class MetricReader { } /** - * Get the {@link AggregationTemporality} preferred by this {@link MetricReader} + * Get the default {@link AggregationTemporality} for the given {@link InstrumentType} */ - getPreferredAggregationTemporality(): AggregationTemporality { - return this._preferredAggregationTemporality; - } + abstract selectAggregationTemporality(instrumentType: InstrumentType): AggregationTemporality; /** * Handle once the SDK has initialized this {@link MetricReader} diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/PeriodicExportingMetricReader.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/PeriodicExportingMetricReader.ts index bd647f4029..0db14825ff 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/PeriodicExportingMetricReader.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/PeriodicExportingMetricReader.ts @@ -17,6 +17,8 @@ import * as api from '@opentelemetry/api'; import { ExportResultCode, globalErrorHandler } from '@opentelemetry/core'; import { MetricReader } from './MetricReader'; +import { AggregationTemporality } from './AggregationTemporality'; +import { InstrumentType } from '../InstrumentDescriptor'; import { PushMetricExporter } from './MetricExporter'; import { callWithTimeout, TimeoutError } from '../utils'; @@ -40,7 +42,7 @@ export class PeriodicExportingMetricReader extends MetricReader { private readonly _exportTimeout: number; constructor(options: PeriodicExportingMetricReaderOptions) { - super(options.exporter.getPreferredAggregationTemporality()); + super(); if (options.exportIntervalMillis !== undefined && options.exportIntervalMillis <= 0) { throw Error('exportIntervalMillis must be greater than 0'); @@ -111,4 +113,8 @@ export class PeriodicExportingMetricReader extends MetricReader { await this._exporter.shutdown(); } + + selectAggregationTemporality(instrumentType: InstrumentType): AggregationTemporality { + return this._exporter.selectAggregationTemporality(instrumentType); + } } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/state/MetricCollector.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/state/MetricCollector.ts index 540a5e0917..fb1d7885a9 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/state/MetricCollector.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/state/MetricCollector.ts @@ -15,10 +15,11 @@ */ import { hrTime } from '@opentelemetry/core'; -import { AggregationTemporality } from '../export/AggregationTemporality'; +import { AggregationTemporalitySelector } from '../export/AggregationTemporality'; import { ResourceMetrics } from '../export/MetricData'; import { MetricProducer } from '../export/MetricProducer'; import { MetricReader } from '../export/MetricReader'; +import { InstrumentType } from '../InstrumentDescriptor'; import { ForceFlushOptions, ShutdownOptions } from '../types'; import { MeterProviderSharedState } from './MeterProviderSharedState'; @@ -28,9 +29,7 @@ import { MeterProviderSharedState } from './MeterProviderSharedState'; * state for each MetricReader. */ export class MetricCollector implements MetricProducer { - public readonly aggregatorTemporality: AggregationTemporality; constructor(private _sharedState: MeterProviderSharedState, private _metricReader: MetricReader) { - this.aggregatorTemporality = this._metricReader.getPreferredAggregationTemporality(); } async collect(): Promise { @@ -58,6 +57,10 @@ export class MetricCollector implements MetricProducer { async shutdown(options?: ShutdownOptions): Promise { await this._metricReader.shutdown(options); } + + selectAggregationTemporality(instrumentType: InstrumentType) { + return this._metricReader.selectAggregationTemporality(instrumentType); + } } /** @@ -65,5 +68,5 @@ export class MetricCollector implements MetricProducer { * information for metric collection. */ export interface MetricCollectorHandle { - aggregatorTemporality: AggregationTemporality; + selectAggregationTemporality: AggregationTemporalitySelector; } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/state/TemporalMetricProcessor.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/state/TemporalMetricProcessor.ts index c916523a6a..c9131e2252 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/state/TemporalMetricProcessor.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/state/TemporalMetricProcessor.ts @@ -69,7 +69,7 @@ export class TemporalMetricProcessor { sdkStartTime: HrTime, collectionTime: HrTime, ): Maybe { - const aggregationTemporality = collector.aggregatorTemporality; + const aggregationTemporality = collector.selectAggregationTemporality(instrumentDescriptor.type); // In case it's our first collection, default to start timestamp (see below for explanation). let lastCollectionTime = sdkStartTime; @@ -108,6 +108,7 @@ export class TemporalMetricProcessor { // 2. Delta Aggregation time span: (lastCollectionTime, collectionTime] return this._aggregator.toMetricData( instrumentDescriptor, + aggregationTemporality, AttributesMapToAccumulationRecords(result), /* startTime */ aggregationTemporality === AggregationTemporality.CUMULATIVE ? sdkStartTime : lastCollectionTime, /* endTime */ collectionTime); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/Instruments.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/Instruments.test.ts index 56c16dbac4..247773fe31 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/Instruments.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/Instruments.test.ts @@ -521,9 +521,9 @@ function setup() { const meter = meterProvider.getMeter(defaultInstrumentationLibrary.name, defaultInstrumentationLibrary.version, { schemaUrl: defaultInstrumentationLibrary.schemaUrl, }); - const deltaReader = new TestMetricReader(AggregationTemporality.DELTA); + const deltaReader = new TestMetricReader(() => AggregationTemporality.DELTA); meterProvider.addMetricReader(deltaReader); - const cumulativeReader = new TestMetricReader(AggregationTemporality.CUMULATIVE); + const cumulativeReader = new TestMetricReader(() => AggregationTemporality.CUMULATIVE); meterProvider.addMetricReader(cumulativeReader); return { diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Drop.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Drop.test.ts index 05242cc192..d378a165c9 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Drop.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Drop.test.ts @@ -16,6 +16,7 @@ import { HrTime } from '@opentelemetry/api'; import * as assert from 'assert'; +import { AggregationTemporality } from '../../src'; import { DropAggregator } from '../../src/aggregator'; import { defaultInstrumentDescriptor } from '../util'; @@ -55,6 +56,7 @@ describe('DropAggregator', () => { assert.strictEqual(aggregator.toMetricData( defaultInstrumentDescriptor, + AggregationTemporality.CUMULATIVE, [[{}, undefined]], startTime, endTime, diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Histogram.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Histogram.test.ts index 08bfca8889..2b4e685915 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Histogram.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Histogram.test.ts @@ -16,6 +16,7 @@ import { HrTime } from '@opentelemetry/api'; import * as assert from 'assert'; +import { AggregationTemporality } from '../../src'; import { HistogramAccumulation, HistogramAggregator } from '../../src/aggregator'; import { MetricData, DataPointType } from '../../src/export/MetricData'; import { commonValues, defaultInstrumentDescriptor } from '../util'; @@ -93,6 +94,7 @@ describe('HistogramAggregator', () => { const expected: MetricData = { descriptor: defaultInstrumentDescriptor, + aggregationTemporality: AggregationTemporality.CUMULATIVE, dataPointType: DataPointType.HISTOGRAM, dataPoints: [ { @@ -112,6 +114,7 @@ describe('HistogramAggregator', () => { }; assert.deepStrictEqual(aggregator.toMetricData( defaultInstrumentDescriptor, + AggregationTemporality.CUMULATIVE, [[{}, accumulation]], startTime, endTime, diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/LastValue.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/LastValue.test.ts index 03c75a7b2d..63df2357c8 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/LastValue.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/LastValue.test.ts @@ -16,6 +16,7 @@ import { HrTime } from '@opentelemetry/api'; import * as assert from 'assert'; +import { AggregationTemporality } from '../../src'; import { LastValueAccumulation, LastValueAggregator } from '../../src/aggregator'; import { MetricData, DataPointType } from '../../src/export/MetricData'; import { commonValues, defaultInstrumentDescriptor, sleep } from '../util'; @@ -101,6 +102,7 @@ describe('LastValueAggregator', () => { const expected: MetricData = { descriptor: defaultInstrumentDescriptor, + aggregationTemporality: AggregationTemporality.CUMULATIVE, dataPointType: DataPointType.SINGULAR, dataPoints: [ { @@ -113,6 +115,7 @@ describe('LastValueAggregator', () => { }; assert.deepStrictEqual(aggregator.toMetricData( defaultInstrumentDescriptor, + AggregationTemporality.CUMULATIVE, [[{}, accumulation]], startTime, endTime, diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Sum.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Sum.test.ts index 3c9e0a48b4..64db048d4e 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Sum.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/aggregator/Sum.test.ts @@ -16,6 +16,7 @@ import { HrTime } from '@opentelemetry/api'; import * as assert from 'assert'; +import { AggregationTemporality } from '../../src'; import { SumAccumulation, SumAggregator } from '../../src/aggregator'; import { MetricData, DataPointType } from '../../src/export/MetricData'; import { commonValues, defaultInstrumentDescriptor } from '../util'; @@ -79,6 +80,7 @@ describe('SumAggregator', () => { const expected: MetricData = { descriptor: defaultInstrumentDescriptor, + aggregationTemporality: AggregationTemporality.CUMULATIVE, dataPointType: DataPointType.SINGULAR, dataPoints: [ { @@ -91,6 +93,7 @@ describe('SumAggregator', () => { }; assert.deepStrictEqual(aggregator.toMetricData( defaultInstrumentDescriptor, + AggregationTemporality.CUMULATIVE, [[{}, accumulation]], startTime, endTime, diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/PeriodicExportingMetricReader.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/PeriodicExportingMetricReader.test.ts index f5f30e03ab..2ad97d875d 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/PeriodicExportingMetricReader.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/PeriodicExportingMetricReader.test.ts @@ -16,7 +16,7 @@ import { PeriodicExportingMetricReader } from '../../src/export/PeriodicExportingMetricReader'; import { AggregationTemporality } from '../../src/export/AggregationTemporality'; -import { PushMetricExporter } from '../../src'; +import { InstrumentType, PushMetricExporter } from '../../src'; import { ResourceMetrics } from '../../src/export/MetricData'; import * as assert from 'assert'; import * as sinon from 'sinon'; @@ -77,13 +77,13 @@ class TestMetricExporter implements PushMetricExporter { return this._batches.slice(0, numberOfExports); } - getPreferredAggregationTemporality(): AggregationTemporality { + selectAggregationTemporality(_instrumentType: InstrumentType): AggregationTemporality { return AggregationTemporality.CUMULATIVE; } } class TestDeltaMetricExporter extends TestMetricExporter { - override getPreferredAggregationTemporality(): AggregationTemporality { + override selectAggregationTemporality(_instrumentType: InstrumentType): AggregationTemporality { return AggregationTemporality.DELTA; } } @@ -107,13 +107,11 @@ describe('PeriodicExportingMetricReader', () => { describe('constructor', () => { it('should construct PeriodicExportingMetricReader without exceptions', () => { const exporter = new TestDeltaMetricExporter(); - const reader = new PeriodicExportingMetricReader({ - exporter: exporter, + assert.doesNotThrow(() => new PeriodicExportingMetricReader({ + exporter, exportIntervalMillis: 4000, exportTimeoutMillis: 3000 - } - ); - assert.strictEqual(reader.getPreferredAggregationTemporality(), exporter.getPreferredAggregationTemporality()); + })); }); it('should throw when interval less or equal to 0', () => { diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/TestMetricExporter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/TestMetricExporter.ts index 43df025473..67f33a898d 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/TestMetricExporter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/TestMetricExporter.ts @@ -27,13 +27,13 @@ export class TestMetricExporter implements PushMetricExporter { async forceFlush(): Promise {} async shutdown(): Promise {} - getPreferredAggregationTemporality(): AggregationTemporality { + selectAggregationTemporality(): AggregationTemporality { return AggregationTemporality.CUMULATIVE; } } export class TestDeltaMetricExporter extends TestMetricExporter { - override getPreferredAggregationTemporality(): AggregationTemporality { + override selectAggregationTemporality(): AggregationTemporality { return AggregationTemporality.DELTA; } } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/TestMetricReader.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/TestMetricReader.ts index 172301d958..4b02562c94 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/TestMetricReader.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/TestMetricReader.ts @@ -14,13 +14,25 @@ * limitations under the License. */ -import { MetricReader } from '../../src'; +import { + AggregationTemporality, + AggregationTemporalitySelector, + InstrumentType, + MetricReader, +} from '../../src'; import { MetricCollector } from '../../src/state/MetricCollector'; /** * A test metric reader that implements no-op onForceFlush() and onShutdown() handlers. */ export class TestMetricReader extends MetricReader { + private _aggregationTemporalitySelector: AggregationTemporalitySelector; + + constructor(aggregationTemporalitySelector?: AggregationTemporalitySelector) { + super(); + this._aggregationTemporalitySelector = aggregationTemporalitySelector ?? (() => AggregationTemporality.CUMULATIVE); + } + protected onForceFlush(): Promise { return Promise.resolve(undefined); } @@ -29,6 +41,10 @@ export class TestMetricReader extends MetricReader { return Promise.resolve(undefined); } + selectAggregationTemporality(instrumentType: InstrumentType) { + return this._aggregationTemporalitySelector(instrumentType); + } + getMetricCollector(): MetricCollector { return this['_metricProducer'] as MetricCollector; } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/AsyncMetricStorage.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/AsyncMetricStorage.test.ts index 9c0a881a6d..07a40d5c02 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/AsyncMetricStorage.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/AsyncMetricStorage.test.ts @@ -28,11 +28,11 @@ import { ObservableCallback } from '@opentelemetry/api-metrics'; import { ObservableRegistry } from '../../src/state/ObservableRegistry'; const deltaCollector: MetricCollectorHandle = { - aggregatorTemporality: AggregationTemporality.DELTA, + selectAggregationTemporality: () => AggregationTemporality.DELTA, }; const cumulativeCollector: MetricCollectorHandle = { - aggregatorTemporality: AggregationTemporality.CUMULATIVE, + selectAggregationTemporality: () => AggregationTemporality.CUMULATIVE, }; const sdkStartTime = hrTime(); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MeterSharedState.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MeterSharedState.test.ts index 9bd9dfa525..79e01f3c6b 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MeterSharedState.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MeterSharedState.test.ts @@ -16,10 +16,15 @@ import * as assert from 'assert'; import * as sinon from 'sinon'; -import { Meter, MeterProvider, DataPointType, ResourceMetrics } from '../../src'; +import { + AggregationTemporality, + Meter, + MeterProvider, + DataPointType, + ResourceMetrics +} from '../../src'; import { assertMetricData, defaultInstrumentationLibrary, defaultResource, sleep } from '../util'; import { TestMetricReader } from '../export/TestMetricReader'; -import { TestDeltaMetricExporter, TestMetricExporter } from '../export/TestMetricExporter'; import { MeterSharedState } from '../../src/state/MeterSharedState'; describe('MeterSharedState', () => { @@ -31,11 +36,11 @@ describe('MeterSharedState', () => { function setupInstruments() { const meterProvider = new MeterProvider({ resource: defaultResource }); - const cumulativeReader = new TestMetricReader(new TestMetricExporter().getPreferredAggregationTemporality()); + const cumulativeReader = new TestMetricReader(() => AggregationTemporality.CUMULATIVE); meterProvider.addMetricReader(cumulativeReader); const cumulativeCollector = cumulativeReader.getMetricCollector(); - const deltaReader = new TestMetricReader(new TestDeltaMetricExporter().getPreferredAggregationTemporality()); + const deltaReader = new TestMetricReader(() => AggregationTemporality.DELTA); meterProvider.addMetricReader(deltaReader); const deltaCollector = deltaReader.getMetricCollector(); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MetricCollector.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MetricCollector.test.ts index 79d29f8560..dd5fac5127 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MetricCollector.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MetricCollector.test.ts @@ -35,10 +35,8 @@ describe('MetricCollector', () => { const meterProviderSharedState = new MeterProviderSharedState(defaultResource); const exporters = [ new TestMetricExporter(), new TestDeltaMetricExporter() ]; for (const exporter of exporters) { - const reader = new TestMetricReader(exporter.getPreferredAggregationTemporality()); - const metricCollector = new MetricCollector(meterProviderSharedState, reader); - - assert.strictEqual(metricCollector.aggregatorTemporality, exporter.getPreferredAggregationTemporality()); + const reader = new TestMetricReader(exporter.selectAggregationTemporality); + assert.doesNotThrow(() => new MetricCollector(meterProviderSharedState, reader)); } }); }); @@ -48,7 +46,7 @@ describe('MetricCollector', () => { function setupInstruments(exporter: PushMetricExporter) { const meterProvider = new MeterProvider({ resource: defaultResource }); - const reader = new TestMetricReader(exporter.getPreferredAggregationTemporality()); + const reader = new TestMetricReader(exporter.selectAggregationTemporality); meterProvider.addMetricReader(reader); const metricCollector = reader.getMetricCollector(); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/SyncMetricStorage.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/SyncMetricStorage.test.ts index 93de724e3d..72d090b961 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/SyncMetricStorage.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/SyncMetricStorage.test.ts @@ -27,11 +27,11 @@ import { NoopAttributesProcessor } from '../../src/view/AttributesProcessor'; import { assertMetricData, assertDataPoint, commonAttributes, commonValues, defaultInstrumentDescriptor } from '../util'; const deltaCollector: MetricCollectorHandle = { - aggregatorTemporality: AggregationTemporality.DELTA, + selectAggregationTemporality: () => AggregationTemporality.DELTA, }; const cumulativeCollector: MetricCollectorHandle = { - aggregatorTemporality: AggregationTemporality.CUMULATIVE, + selectAggregationTemporality: () => AggregationTemporality.CUMULATIVE, }; const sdkStartTime = hrTime(); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/TemporalMetricProcessor.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/TemporalMetricProcessor.test.ts index db0b50e033..7a9710db15 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/TemporalMetricProcessor.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/TemporalMetricProcessor.test.ts @@ -26,15 +26,15 @@ import { TemporalMetricProcessor } from '../../src/state/TemporalMetricProcessor import { assertMetricData, assertDataPoint, defaultInstrumentDescriptor } from '../util'; const deltaCollector1: MetricCollectorHandle = { - aggregatorTemporality: AggregationTemporality.DELTA, + selectAggregationTemporality: () => AggregationTemporality.DELTA, }; const deltaCollector2: MetricCollectorHandle = { - aggregatorTemporality: AggregationTemporality.DELTA, + selectAggregationTemporality: () => AggregationTemporality.DELTA, }; const cumulativeCollector1: MetricCollectorHandle = { - aggregatorTemporality: AggregationTemporality.CUMULATIVE, + selectAggregationTemporality: () => AggregationTemporality.CUMULATIVE, }; const sdkStartTime = hrTime(); diff --git a/experimental/packages/otlp-transformer/src/metrics/index.ts b/experimental/packages/otlp-transformer/src/metrics/index.ts index 494d4b6c4a..28337c3cd4 100644 --- a/experimental/packages/otlp-transformer/src/metrics/index.ts +++ b/experimental/packages/otlp-transformer/src/metrics/index.ts @@ -15,12 +15,10 @@ */ import type { ResourceMetrics } from '@opentelemetry/sdk-metrics-base'; import type { IExportMetricsServiceRequest } from './types'; -import { AggregationTemporality } from '@opentelemetry/sdk-metrics-base'; import { toResourceMetrics } from './internal'; -export function createExportMetricsServiceRequest(resourceMetrics: ResourceMetrics[], - aggregationTemporality: AggregationTemporality): IExportMetricsServiceRequest { +export function createExportMetricsServiceRequest(resourceMetrics: ResourceMetrics[]): IExportMetricsServiceRequest { return { - resourceMetrics: resourceMetrics.map(metrics => toResourceMetrics(metrics, aggregationTemporality)) + resourceMetrics: resourceMetrics.map(metrics => toResourceMetrics(metrics)) }; } diff --git a/experimental/packages/otlp-transformer/src/metrics/internal.ts b/experimental/packages/otlp-transformer/src/metrics/internal.ts index 48e592a1a5..8c08b40b76 100644 --- a/experimental/packages/otlp-transformer/src/metrics/internal.ts +++ b/experimental/packages/otlp-transformer/src/metrics/internal.ts @@ -35,41 +35,39 @@ import { IScopeMetrics } from './types'; -export function toResourceMetrics(resourceMetrics: ResourceMetrics, - aggregationTemporality: AggregationTemporality): IResourceMetrics { +export function toResourceMetrics(resourceMetrics: ResourceMetrics): IResourceMetrics { return { resource: { attributes: toAttributes(resourceMetrics.resource.attributes), droppedAttributesCount: 0 }, schemaUrl: undefined, // TODO: Schema Url does not exist yet in the SDK. - scopeMetrics: toScopeMetrics(resourceMetrics.instrumentationLibraryMetrics, aggregationTemporality) + scopeMetrics: toScopeMetrics(resourceMetrics.instrumentationLibraryMetrics) }; } -export function toScopeMetrics(instrumentationLibraryMetrics: InstrumentationLibraryMetrics[], - aggregationTemporality: AggregationTemporality): IScopeMetrics[]{ +export function toScopeMetrics(instrumentationLibraryMetrics: InstrumentationLibraryMetrics[]): IScopeMetrics[]{ return Array.from(instrumentationLibraryMetrics.map(metrics => { const scopeMetrics : IScopeMetrics = { scope: { name: metrics.instrumentationLibrary.name, version: metrics.instrumentationLibrary.version, }, - metrics: metrics.metrics.map(metricData => toMetric(metricData, aggregationTemporality)), + metrics: metrics.metrics.map(metricData => toMetric(metricData)), schemaUrl: metrics.instrumentationLibrary.schemaUrl }; return scopeMetrics; })); } -export function toMetric(metricData: MetricData, metricTemporality: AggregationTemporality): IMetric { +export function toMetric(metricData: MetricData): IMetric { const out: IMetric = { name: metricData.descriptor.name, description: metricData.descriptor.description, unit: metricData.descriptor.unit, }; - const aggregationTemporality = toAggregationTemporality(metricTemporality); + const aggregationTemporality = toAggregationTemporality(metricData.aggregationTemporality); if (metricData.dataPointType === DataPointType.SINGULAR) { const dataPoints = toSingularDataPoints(metricData); diff --git a/experimental/packages/otlp-transformer/test/metrics.test.ts b/experimental/packages/otlp-transformer/test/metrics.test.ts index c1fa7586ed..48d8422ff9 100644 --- a/experimental/packages/otlp-transformer/test/metrics.test.ts +++ b/experimental/packages/otlp-transformer/test/metrics.test.ts @@ -32,7 +32,7 @@ const END_TIME = hrTime(); describe('Metrics', () => { describe('createExportMetricsServiceRequest', () => { - function createCounterData(value: number): MetricData { + function createCounterData(value: number, aggregationTemporality: AggregationTemporality): MetricData { return { descriptor: { description: 'this is a description', @@ -41,6 +41,7 @@ describe('Metrics', () => { unit: '1', valueType: ValueType.INT, }, + aggregationTemporality, dataPointType: DataPointType.SINGULAR, dataPoints: [ { @@ -53,7 +54,7 @@ describe('Metrics', () => { }; } - function createObservableCounterData(value: number): MetricData { + function createObservableCounterData(value: number, aggregationTemporality: AggregationTemporality): MetricData { return { descriptor: { description: 'this is a description', @@ -62,6 +63,7 @@ describe('Metrics', () => { unit: '1', valueType: ValueType.INT, }, + aggregationTemporality, dataPointType: DataPointType.SINGULAR, dataPoints: [ { @@ -83,6 +85,7 @@ describe('Metrics', () => { unit: '1', valueType: ValueType.DOUBLE, }, + aggregationTemporality: AggregationTemporality.CUMULATIVE, dataPointType: DataPointType.SINGULAR, dataPoints: [ { @@ -95,7 +98,7 @@ describe('Metrics', () => { }; } - function createHistogramMetrics(count: number, sum: number, boundaries: number[], counts: number[]): MetricData { + function createHistogramMetrics(count: number, sum: number, boundaries: number[], counts: number[], aggregationTemporality: AggregationTemporality): MetricData { return { descriptor: { description: 'this is a description', @@ -104,6 +107,7 @@ describe('Metrics', () => { unit: '1', valueType: ValueType.INT, }, + aggregationTemporality, dataPointType: DataPointType.HISTOGRAM, dataPoints: [ { @@ -144,11 +148,8 @@ describe('Metrics', () => { } it('serializes a sum metric record', () => { - const metrics = [createResourceMetrics([createCounterData(10)])]; - const exportRequest = createExportMetricsServiceRequest( - metrics, - AggregationTemporality.DELTA - ); + const metrics = createResourceMetrics([createCounterData(10, AggregationTemporality.DELTA)]); + const exportRequest = createExportMetricsServiceRequest([metrics]); assert.ok(exportRequest); assert.deepStrictEqual(exportRequest, { @@ -208,8 +209,7 @@ describe('Metrics', () => { it('serializes an observable sum metric record', () => { const exportRequest = createExportMetricsServiceRequest( - [createResourceMetrics([createObservableCounterData(10)])], - AggregationTemporality.DELTA + [createResourceMetrics([createObservableCounterData(10, AggregationTemporality.DELTA)])] ); assert.ok(exportRequest); @@ -270,8 +270,7 @@ describe('Metrics', () => { it('serializes a gauge metric record', () => { const exportRequest = createExportMetricsServiceRequest( - [createResourceMetrics([createObservableGaugeData(10.5)])], - AggregationTemporality.DELTA + [createResourceMetrics([createObservableGaugeData(10.5)])] ); assert.ok(exportRequest); @@ -330,8 +329,7 @@ describe('Metrics', () => { it('serializes a histogram metric record', () => { const exportRequest = createExportMetricsServiceRequest( - [createResourceMetrics([createHistogramMetrics(2, 9, [5], [1,1])])], - AggregationTemporality.CUMULATIVE + [createResourceMetrics([createHistogramMetrics(2, 9, [5], [1,1], AggregationTemporality.CUMULATIVE)])] ); assert.ok(exportRequest);