Skip to content

Commit 1ee1b28

Browse files
authored
feat: metric aggregation temporality controls (#2902)
* feat: aggregation temporality controls * chore: update CHANGELOG * refactor: move named otlp temporality selectors to OTLPMetricExporterBase * fix: revert accidental protos change * refactor: rename preferredAggregationTemporality to temporalityPreference * doc: better changelog wording * fix: remove unnecessary files
1 parent 858f6ce commit 1ee1b28

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+221
-133
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
66

77
### :boom: Breaking Change
88

9+
* 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
910
* chore: remove unused InstrumentationConfig#path [#2944](https://github.com/open-telemetry/opentelemetry-js/pull/2944) @flarna
1011

1112
### :rocket: (Enhancement)

experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts

+3-7
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@
1515
*/
1616

1717
import {
18-
defaultExporterTemporality,
1918
defaultOptions,
2019
OTLPMetricExporterBase,
2120
OTLPMetricExporterOptions
2221
} from '@opentelemetry/exporter-metrics-otlp-http';
23-
import { AggregationTemporality, ResourceMetrics } from '@opentelemetry/sdk-metrics-base';
22+
import { ResourceMetrics } from '@opentelemetry/sdk-metrics-base';
2423
import {
2524
OTLPGRPCExporterConfigNode,
2625
OTLPGRPCExporterNodeBase,
@@ -34,9 +33,7 @@ import { createExportMetricsServiceRequest, IExportMetricsServiceRequest } from
3433
const DEFAULT_COLLECTOR_URL = 'localhost:4317';
3534

3635

37-
class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase<ResourceMetrics,
38-
IExportMetricsServiceRequest> {
39-
protected readonly _aggregationTemporality: AggregationTemporality;
36+
class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase<ResourceMetrics, IExportMetricsServiceRequest> {
4037

4138
constructor(config: OTLPGRPCExporterConfigNode & OTLPMetricExporterOptions= defaultOptions) {
4239
super(config);
@@ -45,7 +42,6 @@ class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase<ResourceMetrics,
4542
for (const [k, v] of Object.entries(headers)) {
4643
this.metadata.set(k, v);
4744
}
48-
this._aggregationTemporality = config.aggregationTemporality ?? defaultExporterTemporality;
4945
}
5046

5147
getServiceProtoPath(): string {
@@ -67,7 +63,7 @@ class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase<ResourceMetrics,
6763
}
6864

6965
convert(metrics: ResourceMetrics[]): IExportMetricsServiceRequest {
70-
return createExportMetricsServiceRequest(metrics, this._aggregationTemporality);
66+
return createExportMetricsServiceRequest(metrics);
7167
}
7268
}
7369

experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ const testOTLPMetricExporter = (params: TestParams) =>
128128
url: 'grpcs://' + address,
129129
credentials,
130130
metadata: params.metadata,
131-
aggregationTemporality: AggregationTemporality.CUMULATIVE
131+
temporalityPreference: AggregationTemporality.CUMULATIVE
132132
});
133133

134134
setUp();
@@ -182,15 +182,15 @@ const testOTLPMetricExporter = (params: TestParams) =>
182182
headers: {
183183
foo: 'bar',
184184
},
185-
aggregationTemporality: AggregationTemporality.CUMULATIVE
185+
temporalityPreference: AggregationTemporality.CUMULATIVE
186186
});
187187
const args = warnStub.args[0];
188188
assert.strictEqual(args[0], 'Headers cannot be set when using grpc');
189189
});
190190
it('should warn about path in url', () => {
191191
collectorExporter = new OTLPMetricExporter({
192192
url: `http://${address}/v1/metrics`,
193-
aggregationTemporality: AggregationTemporality.CUMULATIVE
193+
temporalityPreference: AggregationTemporality.CUMULATIVE
194194
});
195195
const args = warnStub.args[0];
196196
assert.strictEqual(
@@ -262,7 +262,7 @@ describe('OTLPMetricExporter - node (getDefaultUrl)', () => {
262262
const url = 'http://foo.bar.com';
263263
const collectorExporter = new OTLPMetricExporter({
264264
url,
265-
aggregationTemporality: AggregationTemporality.CUMULATIVE
265+
temporalityPreference: AggregationTemporality.CUMULATIVE
266266
});
267267
setTimeout(() => {
268268
assert.strictEqual(collectorExporter._otlpExporter.url, 'foo.bar.com');
@@ -307,7 +307,7 @@ describe('when configuring via environment', () => {
307307
envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo';
308308
const collectorExporter = new OTLPMetricExporter({
309309
metadata,
310-
aggregationTemporality: AggregationTemporality.CUMULATIVE
310+
temporalityPreference: AggregationTemporality.CUMULATIVE
311311
});
312312
assert.deepStrictEqual(collectorExporter._otlpExporter.metadata?.get('foo'), ['boo']);
313313
assert.deepStrictEqual(collectorExporter._otlpExporter.metadata?.get('bar'), ['foo']);

experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/metricsHelper.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,19 @@ import { Resource } from '@opentelemetry/resources';
1919
import * as assert from 'assert';
2020
import * as grpc from '@grpc/grpc-js';
2121
import { VERSION } from '@opentelemetry/core';
22-
import { ExplicitBucketHistogramAggregation, MeterProvider, MetricReader } from '@opentelemetry/sdk-metrics-base';
22+
import {
23+
AggregationTemporality,
24+
ExplicitBucketHistogramAggregation,
25+
MeterProvider,
26+
MetricReader,
27+
} from '@opentelemetry/sdk-metrics-base';
2328
import { IKeyValue, IMetric, IResource } from '@opentelemetry/otlp-transformer';
2429

25-
export class TestMetricReader extends MetricReader {
30+
class TestMetricReader extends MetricReader {
31+
selectAggregationTemporality() {
32+
return AggregationTemporality.CUMULATIVE;
33+
}
34+
2635
protected onForceFlush(): Promise<void> {
2736
return Promise.resolve(undefined);
2837
}

experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterBase.ts

+34-5
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,51 @@
1515
*/
1616

1717
import { ExportResult } from '@opentelemetry/core';
18-
import { AggregationTemporality, PushMetricExporter, ResourceMetrics } from '@opentelemetry/sdk-metrics-base';
18+
import {
19+
AggregationTemporality,
20+
AggregationTemporalitySelector,
21+
InstrumentType,
22+
PushMetricExporter,
23+
ResourceMetrics
24+
} from '@opentelemetry/sdk-metrics-base';
1925
import { defaultOptions, OTLPMetricExporterOptions } from './OTLPMetricExporterOptions';
2026
import { OTLPExporterBase } from '@opentelemetry/otlp-exporter-base';
2127
import { IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer';
2228

29+
export const CumulativeTemporalitySelector: AggregationTemporalitySelector = () => AggregationTemporality.CUMULATIVE;
30+
31+
export const DeltaTemporalitySelector: AggregationTemporalitySelector = (instrumentType: InstrumentType) => {
32+
switch (instrumentType) {
33+
case InstrumentType.COUNTER:
34+
case InstrumentType.OBSERVABLE_COUNTER:
35+
case InstrumentType.HISTOGRAM:
36+
case InstrumentType.OBSERVABLE_GAUGE:
37+
return AggregationTemporality.DELTA;
38+
case InstrumentType.UP_DOWN_COUNTER:
39+
case InstrumentType.OBSERVABLE_UP_DOWN_COUNTER:
40+
return AggregationTemporality.CUMULATIVE;
41+
}
42+
};
43+
44+
function chooseTemporalitySelector(temporalityPreference?: AggregationTemporality): AggregationTemporalitySelector {
45+
if (temporalityPreference === AggregationTemporality.DELTA) {
46+
return DeltaTemporalitySelector;
47+
}
48+
49+
return CumulativeTemporalitySelector;
50+
}
51+
2352
export class OTLPMetricExporterBase<T extends OTLPExporterBase<OTLPMetricExporterOptions,
2453
ResourceMetrics,
2554
IExportMetricsServiceRequest>>
2655
implements PushMetricExporter {
2756
public _otlpExporter: T;
28-
protected _preferredAggregationTemporality: AggregationTemporality;
57+
protected _aggregationTemporalitySelector: AggregationTemporalitySelector;
2958

3059
constructor(exporter: T,
3160
config: OTLPMetricExporterOptions = defaultOptions) {
3261
this._otlpExporter = exporter;
33-
this._preferredAggregationTemporality = config.aggregationTemporality ?? AggregationTemporality.CUMULATIVE;
62+
this._aggregationTemporalitySelector = chooseTemporalitySelector(config.temporalityPreference);
3463
}
3564

3665
export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void {
@@ -45,7 +74,7 @@ implements PushMetricExporter {
4574
return Promise.resolve();
4675
}
4776

48-
getPreferredAggregationTemporality(): AggregationTemporality {
49-
return this._preferredAggregationTemporality;
77+
selectAggregationTemporality(instrumentType: InstrumentType): AggregationTemporality {
78+
return this._aggregationTemporalitySelector(instrumentType);
5079
}
5180
}

experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterOptions.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { AggregationTemporality } from '@opentelemetry/sdk-metrics-base';
1818
import { OTLPExporterConfigBase } from '@opentelemetry/otlp-exporter-base';
1919

2020
export interface OTLPMetricExporterOptions extends OTLPExporterConfigBase {
21-
aggregationTemporality?: AggregationTemporality
21+
temporalityPreference?: AggregationTemporality
2222
}
2323
export const defaultExporterTemporality = AggregationTemporality.CUMULATIVE;
24-
export const defaultOptions = {aggregationTemporality: defaultExporterTemporality};
24+
export const defaultOptions = {temporalityPreference: defaultExporterTemporality};

experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/browser/OTLPMetricExporter.ts

+4-10
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { AggregationTemporality, ResourceMetrics } from '@opentelemetry/sdk-metrics-base';
17+
import { ResourceMetrics } from '@opentelemetry/sdk-metrics-base';
1818
import { baggageUtils, getEnv } from '@opentelemetry/core';
19-
import { defaultExporterTemporality, defaultOptions, OTLPMetricExporterOptions } from '../../OTLPMetricExporterOptions';
19+
import { defaultOptions, OTLPMetricExporterOptions } from '../../OTLPMetricExporterOptions';
2020
import { OTLPMetricExporterBase } from '../../OTLPMetricExporterBase';
2121
import {
2222
appendResourcePathToUrlIfNotPresent,
@@ -28,9 +28,7 @@ import { createExportMetricsServiceRequest, IExportMetricsServiceRequest } from
2828
const DEFAULT_COLLECTOR_RESOURCE_PATH = '/v1/metrics';
2929
const DEFAULT_COLLECTOR_URL = `http://localhost:4318${DEFAULT_COLLECTOR_RESOURCE_PATH}`;
3030

31-
class OTLPExporterBrowserProxy extends OTLPExporterBrowserBase<ResourceMetrics,
32-
IExportMetricsServiceRequest> {
33-
protected readonly _aggregationTemporality: AggregationTemporality;
31+
class OTLPExporterBrowserProxy extends OTLPExporterBrowserBase<ResourceMetrics, IExportMetricsServiceRequest> {
3432

3533
constructor(config: OTLPMetricExporterOptions & OTLPExporterConfigBase = defaultOptions) {
3634
super(config);
@@ -40,7 +38,6 @@ class OTLPExporterBrowserProxy extends OTLPExporterBrowserBase<ResourceMetrics,
4038
getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS
4139
)
4240
);
43-
this._aggregationTemporality = config.aggregationTemporality ?? defaultExporterTemporality;
4441
}
4542

4643
getDefaultUrl(config: OTLPExporterConfigBase): string {
@@ -54,10 +51,7 @@ class OTLPExporterBrowserProxy extends OTLPExporterBrowserBase<ResourceMetrics,
5451
}
5552

5653
convert(metrics: ResourceMetrics[]): IExportMetricsServiceRequest {
57-
return createExportMetricsServiceRequest(
58-
metrics,
59-
this._aggregationTemporality
60-
);
54+
return createExportMetricsServiceRequest(metrics);
6155
}
6256
}
6357

experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts

+4-10
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { ResourceMetrics, AggregationTemporality } from '@opentelemetry/sdk-metrics-base';
17+
import { ResourceMetrics } from '@opentelemetry/sdk-metrics-base';
1818
import { getEnv, baggageUtils} from '@opentelemetry/core';
19-
import { defaultExporterTemporality, defaultOptions, OTLPMetricExporterOptions } from '../../OTLPMetricExporterOptions';
19+
import { defaultOptions, OTLPMetricExporterOptions } from '../../OTLPMetricExporterOptions';
2020
import { OTLPMetricExporterBase } from '../../OTLPMetricExporterBase';
2121
import {
2222
appendResourcePathToUrlIfNotPresent,
@@ -28,9 +28,7 @@ import { createExportMetricsServiceRequest, IExportMetricsServiceRequest } from
2828
const DEFAULT_COLLECTOR_RESOURCE_PATH = '/v1/metrics';
2929
const DEFAULT_COLLECTOR_URL = `http://localhost:4318${DEFAULT_COLLECTOR_RESOURCE_PATH}`;
3030

31-
class OTLPExporterNodeProxy extends OTLPExporterNodeBase<ResourceMetrics,
32-
IExportMetricsServiceRequest> {
33-
protected readonly _aggregationTemporality: AggregationTemporality;
31+
class OTLPExporterNodeProxy extends OTLPExporterNodeBase<ResourceMetrics, IExportMetricsServiceRequest> {
3432

3533
constructor(config: OTLPExporterNodeConfigBase & OTLPMetricExporterOptions = defaultOptions) {
3634
super(config);
@@ -40,14 +38,10 @@ class OTLPExporterNodeProxy extends OTLPExporterNodeBase<ResourceMetrics,
4038
getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS
4139
)
4240
);
43-
this._aggregationTemporality = config.aggregationTemporality ?? defaultExporterTemporality;
4441
}
4542

4643
convert(metrics: ResourceMetrics[]): IExportMetricsServiceRequest {
47-
return createExportMetricsServiceRequest(
48-
metrics,
49-
this._aggregationTemporality
50-
);
44+
return createExportMetricsServiceRequest(metrics);
5145
}
5246

5347
getDefaultUrl(config: OTLPExporterNodeConfigBase): string {

experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ describe('OTLPMetricExporter - web', () => {
9494
beforeEach(() => {
9595
collectorExporter = new OTLPMetricExporter({
9696
url: 'http://foo.bar.com',
97-
aggregationTemporality: AggregationTemporality.CUMULATIVE
97+
temporalityPreference: AggregationTemporality.CUMULATIVE
9898
});
9999
});
100100
it('should successfully send metrics using sendBeacon', done => {
@@ -191,7 +191,7 @@ describe('OTLPMetricExporter - web', () => {
191191
(window.navigator as any).sendBeacon = false;
192192
collectorExporter = new OTLPMetricExporter({
193193
url: 'http://foo.bar.com',
194-
aggregationTemporality: AggregationTemporality.CUMULATIVE
194+
temporalityPreference: AggregationTemporality.CUMULATIVE
195195
});
196196
// Overwrites the start time to make tests consistent
197197
Object.defineProperty(collectorExporter, '_startTime', {
@@ -316,7 +316,7 @@ describe('OTLPMetricExporter - web', () => {
316316
beforeEach(() => {
317317
collectorExporterConfig = {
318318
headers: customHeaders,
319-
aggregationTemporality: AggregationTemporality.CUMULATIVE
319+
temporalityPreference: AggregationTemporality.CUMULATIVE
320320
};
321321
server = sinon.fakeServer.create();
322322
});
@@ -408,7 +408,7 @@ describe('when configuring via environment', () => {
408408
envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar';
409409
const collectorExporter = new OTLPMetricExporter({
410410
headers: {},
411-
aggregationTemporality: AggregationTemporality.CUMULATIVE
411+
temporalityPreference: AggregationTemporality.CUMULATIVE
412412
});
413413
assert.strictEqual(collectorExporter['_otlpExporter']['_headers'].foo, 'bar');
414414
envSource.OTEL_EXPORTER_OTLP_HEADERS = '';
@@ -418,7 +418,7 @@ describe('when configuring via environment', () => {
418418
envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo';
419419
const collectorExporter = new OTLPMetricExporter({
420420
headers: {},
421-
aggregationTemporality: AggregationTemporality.CUMULATIVE
421+
temporalityPreference: AggregationTemporality.CUMULATIVE
422422
});
423423
assert.strictEqual(collectorExporter['_otlpExporter']['_headers'].foo, 'boo');
424424
assert.strictEqual(collectorExporter['_otlpExporter']['_headers'].bar, 'foo');

experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/metricsHelper.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { Resource } from '@opentelemetry/resources';
2424
import * as assert from 'assert';
2525
import { InstrumentationLibrary, VERSION } from '@opentelemetry/core';
2626
import {
27+
AggregationTemporality,
2728
ExplicitBucketHistogramAggregation,
2829
MeterProvider,
2930
MetricReader
@@ -43,14 +44,18 @@ if (typeof Buffer === 'undefined') {
4344
};
4445
}
4546

46-
export class TestMetricReader extends MetricReader {
47+
class TestMetricReader extends MetricReader {
4748
protected onForceFlush(): Promise<void> {
4849
return Promise.resolve(undefined);
4950
}
5051

5152
protected onShutdown(): Promise<void> {
5253
return Promise.resolve(undefined);
5354
}
55+
56+
selectAggregationTemporality() {
57+
return AggregationTemporality.CUMULATIVE;
58+
}
5459
}
5560

5661
const defaultResource = Resource.default().merge(new Resource({

experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ describe('OTLPMetricExporter - node with json over http', () => {
163163
url: 'http://foo.bar.com',
164164
keepAlive: true,
165165
httpAgentOptions: { keepAliveMsecs: 2000 },
166-
aggregationTemporality: AggregationTemporality.CUMULATIVE
166+
temporalityPreference: AggregationTemporality.CUMULATIVE
167167
};
168168

169169
collectorExporter = new OTLPMetricExporter(collectorExporterConfig);
@@ -329,7 +329,7 @@ describe('OTLPMetricExporter - node with json over http', () => {
329329
const url = 'http://foo.bar.com';
330330
const collectorExporter = new OTLPMetricExporter({
331331
url,
332-
aggregationTemporality: AggregationTemporality.CUMULATIVE
332+
temporalityPreference: AggregationTemporality.CUMULATIVE
333333
});
334334
setTimeout(() => {
335335
assert.strictEqual(collectorExporter._otlpExporter.url, url);

0 commit comments

Comments
 (0)