Skip to content

Commit

Permalink
feat(sdk-metrics-base): per metric-reader aggregation
Browse files Browse the repository at this point in the history
  • Loading branch information
legendecas committed Aug 15, 2022
1 parent 3cca2ce commit df29111
Show file tree
Hide file tree
Showing 44 changed files with 771 additions and 399 deletions.
1 change: 1 addition & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ All notable changes to experimental packages in this project will be documented

* feature(add-console-metrics-exporter): add ConsoleMetricExporter [#3120](https://github.com/open-telemetry/opentelemetry-js/pull/3120) @weyert
* feature(prometheus-serialiser): export the unit block when unit is set in metric descriptor [#3066](https://github.com/open-telemetry/opentelemetry-js/pull/3041) @weyert
* feat(sdk-metrics-base): add per metric-reader aggregation support [#3153](https://github.com/open-telemetry/opentelemetry-js/pull/3153) @legendecas

### :bug: (Bug Fix)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
*/

import {
defaultOptions,
OTLPMetricExporterBase,
OTLPMetricExporterOptions
} from '@opentelemetry/exporter-metrics-otlp-http';
import { ResourceMetrics } from '@opentelemetry/sdk-metrics-base';
import {
Expand All @@ -33,7 +31,7 @@ import { createExportMetricsServiceRequest, IExportMetricsServiceRequest } from

class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase<ResourceMetrics, IExportMetricsServiceRequest> {

constructor(config: OTLPGRPCExporterConfigNode & OTLPMetricExporterOptions= defaultOptions) {
constructor(config: OTLPGRPCExporterConfigNode = {}) {
super(config);
const headers = baggageUtils.parseKeyPairsIntoRecord(getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS);
this.metadata ||= new Metadata();
Expand Down Expand Up @@ -73,7 +71,7 @@ class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase<ResourceMetrics,
* OTLP-gRPC metric exporter
*/
export class OTLPMetricExporter extends OTLPMetricExporterBase<OTLPMetricExporterProxy>{
constructor(config: OTLPGRPCExporterConfigNode & OTLPMetricExporterOptions = defaultOptions) {
super(new OTLPMetricExporterProxy(config), config);
constructor(config: OTLPGRPCExporterConfigNode = {}) {
super(new OTLPMetricExporterProxy(config));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
mockHistogram,
mockObservableGauge, setUp, shutdown,
} from './metricsHelper';
import { AggregationTemporality, ResourceMetrics } from '@opentelemetry/sdk-metrics-base';
import { ResourceMetrics } from '@opentelemetry/sdk-metrics-base';
import { IExportMetricsServiceRequest, IResourceMetrics } from '@opentelemetry/otlp-transformer';

const metricsServiceProtoPath =
Expand Down Expand Up @@ -128,7 +128,6 @@ const testOTLPMetricExporter = (params: TestParams) =>
url: 'https://' + address,
credentials,
metadata: params.metadata,
temporalityPreference: AggregationTemporality.CUMULATIVE
});

setUp();
Expand Down Expand Up @@ -184,15 +183,13 @@ const testOTLPMetricExporter = (params: TestParams) =>
headers: {
foo: 'bar',
},
temporalityPreference: AggregationTemporality.CUMULATIVE
});
const args = warnStub.args[0];
assert.strictEqual(args[0], 'Headers cannot be set when using grpc');
});
it('should warn about path in url', () => {
collectorExporter = new OTLPMetricExporter({
url: `http://${address}/v1/metrics`,
temporalityPreference: AggregationTemporality.CUMULATIVE
});
const args = warnStub.args[0];
assert.strictEqual(
Expand All @@ -214,13 +211,18 @@ const testOTLPMetricExporter = (params: TestParams) =>

assert.ok(exportedData, 'exportedData does not exist');

// The order of the metrics is not guaranteed.
const counterIndex = exportedData[0].scopeMetrics[0].metrics.findIndex(it => it.name === 'int-counter');
const observableIndex = exportedData[0].scopeMetrics[0].metrics.findIndex(it => it.name === 'double-observable-gauge');
const histogramIndex = exportedData[0].scopeMetrics[0].metrics.findIndex(it => it.name === 'int-histogram');

const resource = exportedData[0].resource;
const counter =
exportedData[0].scopeMetrics[0].metrics[0];
exportedData[0].scopeMetrics[0].metrics[counterIndex];
const observableGauge =
exportedData[0].scopeMetrics[0].metrics[1];
exportedData[0].scopeMetrics[0].metrics[observableIndex];
const histogram =
exportedData[0].scopeMetrics[0].metrics[2];
exportedData[0].scopeMetrics[0].metrics[histogramIndex];
ensureExportedCounterIsCorrect(
counter,
counter.sum?.dataPoints[0].timeUnixNano,
Expand Down Expand Up @@ -264,7 +266,6 @@ describe('OTLPMetricExporter - node (getDefaultUrl)', () => {
const url = 'http://foo.bar.com';
const collectorExporter = new OTLPMetricExporter({
url,
temporalityPreference: AggregationTemporality.CUMULATIVE
});
setTimeout(() => {
assert.strictEqual(collectorExporter._otlpExporter.url, 'foo.bar.com');
Expand Down Expand Up @@ -309,7 +310,6 @@ describe('when configuring via environment', () => {
envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo';
const collectorExporter = new OTLPMetricExporter({
metadata,
temporalityPreference: AggregationTemporality.CUMULATIVE
});
assert.deepStrictEqual(collectorExporter._otlpExporter.metadata?.get('foo'), ['boo']);
assert.deepStrictEqual(collectorExporter._otlpExporter.metadata?.get('bar'), ['foo']);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as assert from 'assert';
import * as grpc from '@grpc/grpc-js';
import { VERSION } from '@opentelemetry/core';
import {
Aggregation,
AggregationTemporality,
ExplicitBucketHistogramAggregation,
MeterProvider,
Expand All @@ -29,6 +30,10 @@ import {
import { IKeyValue, IMetric, IResource } from '@opentelemetry/otlp-transformer';

class TestMetricReader extends MetricReader {
selectAggregation() {
return Aggregation.Default();
}

selectAggregationTemporality() {
return AggregationTemporality.CUMULATIVE;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* 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 { getEnv } from '@opentelemetry/core';
import { Aggregation, AggregationSelector, AggregationTemporality, AggregationTemporalitySelector, InstrumentType } from '@opentelemetry/sdk-metrics-base';

/**
* Default {@link AggregationTemporalitySelector} when the OTLP Metrics Exporter is configured with environ `OTEL_METRICS_EXPORTER`.
*/
const CumulativeTemporalitySelector: AggregationTemporalitySelector = () => AggregationTemporality.CUMULATIVE;

/**
* Default {@link AggregationSelector} when the OTLP Metrics Exporter is configured with environ `OTEL_METRICS_EXPORTER`.
*/
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;
}

/**
* Get the default {@link AggregationTemporalitySelector} based on the environ `OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE`.
*/
export function getDefaultAggregationTemporalitySelector(): AggregationTemporalitySelector {
const env = getEnv();
const temporalityPreference = env.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE !== 'cumulative' ? AggregationTemporality.DELTA : AggregationTemporality.CUMULATIVE;
return chooseTemporalitySelector(temporalityPreference);
}

/**
* Get the default {@link AggregationSelector} based on the environ `OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION`.
*/
export function getDefaultAggregationSelector(): AggregationSelector {
// TODO(legendecas): exponential bucket histogram support.
return Aggregation.Default;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,50 +16,20 @@

import { ExportResult } from '@opentelemetry/core';
import {
AggregationTemporality,
AggregationTemporalitySelector,
InstrumentType,
PushMetricExporter,
ResourceMetrics
} from '@opentelemetry/sdk-metrics-base';
import { defaultOptions, OTLPMetricExporterOptions } from './OTLPMetricExporterOptions';
import { OTLPExporterBase } from '@opentelemetry/otlp-exporter-base';
import { OTLPExporterBase, OTLPExporterConfigBase } 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<T extends OTLPExporterBase<OTLPMetricExporterOptions,
export class OTLPMetricExporterBase<T extends OTLPExporterBase<OTLPExporterConfigBase,
ResourceMetrics,
IExportMetricsServiceRequest>>
implements PushMetricExporter {
public _otlpExporter: T;
protected _aggregationTemporalitySelector: AggregationTemporalitySelector;

constructor(exporter: T,
config: OTLPMetricExporterOptions = defaultOptions) {
constructor(exporter: T) {
this._otlpExporter = exporter;
this._aggregationTemporalitySelector = chooseTemporalitySelector(config.temporalityPreference);
}

export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void {
Expand All @@ -73,8 +43,4 @@ implements PushMetricExporter {
forceFlush(): Promise<void> {
return Promise.resolve();
}

selectAggregationTemporality(instrumentType: InstrumentType): AggregationTemporality {
return this._aggregationTemporalitySelector(instrumentType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@
*/

export * from './platform';
export * from './OTLPMetricExporterOptions';
export * from './OTLPMetricExporterBase';
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import { ResourceMetrics } from '@opentelemetry/sdk-metrics-base';
import { baggageUtils, getEnv } from '@opentelemetry/core';
import { defaultOptions, OTLPMetricExporterOptions } from '../../OTLPMetricExporterOptions';
import { OTLPMetricExporterBase } from '../../OTLPMetricExporterBase';
import {
OTLPExporterBrowserBase,
Expand All @@ -31,7 +30,7 @@ const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURC

class OTLPExporterBrowserProxy extends OTLPExporterBrowserBase<ResourceMetrics, IExportMetricsServiceRequest> {

constructor(config: OTLPMetricExporterOptions & OTLPExporterConfigBase = defaultOptions) {
constructor(config: OTLPExporterConfigBase) {
super(config);
this._headers = Object.assign(
this._headers,
Expand Down Expand Up @@ -60,7 +59,7 @@ class OTLPExporterBrowserProxy extends OTLPExporterBrowserBase<ResourceMetrics,
* Collector Metric Exporter for Web
*/
export class OTLPMetricExporter extends OTLPMetricExporterBase<OTLPExporterBrowserProxy> {
constructor(config: OTLPExporterConfigBase & OTLPMetricExporterOptions = defaultOptions) {
super(new OTLPExporterBrowserProxy(config), config);
constructor(config: OTLPExporterConfigBase = {}) {
super(new OTLPExporterBrowserProxy(config));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import { ResourceMetrics } from '@opentelemetry/sdk-metrics-base';
import { getEnv, baggageUtils} from '@opentelemetry/core';
import { defaultOptions, OTLPMetricExporterOptions } from '../../OTLPMetricExporterOptions';
import { OTLPMetricExporterBase } from '../../OTLPMetricExporterBase';
import {
OTLPExporterNodeBase,
Expand All @@ -31,7 +30,7 @@ const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURC

class OTLPExporterNodeProxy extends OTLPExporterNodeBase<ResourceMetrics, IExportMetricsServiceRequest> {

constructor(config: OTLPExporterNodeConfigBase & OTLPMetricExporterOptions = defaultOptions) {
constructor(config: OTLPExporterNodeConfigBase) {
super(config);
this.headers = Object.assign(
this.headers,
Expand Down Expand Up @@ -60,7 +59,7 @@ class OTLPExporterNodeProxy extends OTLPExporterNodeBase<ResourceMetrics, IExpor
* Collector Metric Exporter for Node
*/
export class OTLPMetricExporter extends OTLPMetricExporterBase<OTLPExporterNodeProxy> {
constructor(config: OTLPExporterNodeConfigBase & OTLPMetricExporterOptions = defaultOptions) {
super(new OTLPExporterNodeProxy(config), config);
constructor(config: OTLPExporterNodeConfigBase = {}) {
super(new OTLPExporterNodeProxy(config));
}
}
Loading

0 comments on commit df29111

Please sign in to comment.