Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sdk-metrics-base): per metric-reader aggregation #3153

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,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: support latest `@opentelemetry/api` [#3177](https://github.com/open-telemetry/opentelemetry-js/pull/3177) @dyladan
* 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 @@ -214,13 +214,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
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
Expand Up @@ -99,6 +99,7 @@ describe('OTLPMetricExporter - web', () => {
temporalityPreference: AggregationTemporality.CUMULATIVE
});
});

it('should successfully send metrics using sendBeacon', done => {
collectorExporter.export(metrics, () => {
});
Expand All @@ -109,16 +110,22 @@ describe('OTLPMetricExporter - web', () => {
const blob: Blob = args[1];
const body = await blob.text();
const json = JSON.parse(body) as IExportMetricsServiceRequest;
const metric1 = json.resourceMetrics[0].scopeMetrics[0].metrics[0];
const metric2 = json.resourceMetrics[0].scopeMetrics[0].metrics[1];
const metric3 = json.resourceMetrics[0].scopeMetrics[0].metrics[2];

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

const metric1 = json.resourceMetrics[0].scopeMetrics[0].metrics[counterIndex];
const metric2 = json.resourceMetrics[0].scopeMetrics[0].metrics[observableIndex];
const metric3 = json.resourceMetrics[0].scopeMetrics[0].metrics[histogramIndex];

assert.ok(typeof metric1 !== 'undefined', "metric doesn't exist");

ensureCounterIsCorrect(
metric1,
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[0].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[0].dataPoints[0].startTime)
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0].startTime)
);


Expand All @@ -128,8 +135,8 @@ describe('OTLPMetricExporter - web', () => {
);
ensureObservableGaugeIsCorrect(
metric2,
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[1].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[1].dataPoints[0].startTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0].startTime),
6,
'double-observable-gauge2'
);
Expand All @@ -140,8 +147,8 @@ describe('OTLPMetricExporter - web', () => {
);
ensureHistogramIsCorrect(
metric3,
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[2].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[2].dataPoints[0].startTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0].startTime),
[0, 100],
[0, 2, 0]
);
Expand Down Expand Up @@ -216,15 +223,20 @@ describe('OTLPMetricExporter - web', () => {

const body = request.requestBody;
const json = JSON.parse(body) as IExportMetricsServiceRequest;
const metric1 = json.resourceMetrics[0].scopeMetrics[0].metrics[0];
const metric2 = json.resourceMetrics[0].scopeMetrics[0].metrics[1];
const metric3 = json.resourceMetrics[0].scopeMetrics[0].metrics[2];
// The order of the metrics is not guaranteed.
const counterIndex = metrics.scopeMetrics[0].metrics.findIndex(it => it.descriptor.name === 'int-counter');
const observableIndex = metrics.scopeMetrics[0].metrics.findIndex(it => it.descriptor.name === 'double-observable-gauge2');
const histogramIndex = metrics.scopeMetrics[0].metrics.findIndex(it => it.descriptor.name === 'int-histogram');

const metric1 = json.resourceMetrics[0].scopeMetrics[0].metrics[counterIndex];
const metric2 = json.resourceMetrics[0].scopeMetrics[0].metrics[observableIndex];
const metric3 = json.resourceMetrics[0].scopeMetrics[0].metrics[histogramIndex];

assert.ok(typeof metric1 !== 'undefined', "metric doesn't exist");
ensureCounterIsCorrect(
metric1,
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[0].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[0].dataPoints[0].startTime)
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0].startTime)
);

assert.ok(
Expand All @@ -233,8 +245,8 @@ describe('OTLPMetricExporter - web', () => {
);
ensureObservableGaugeIsCorrect(
metric2,
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[1].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[1].dataPoints[0].startTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0].startTime),
6,
'double-observable-gauge2'
);
Expand All @@ -245,8 +257,8 @@ describe('OTLPMetricExporter - web', () => {
);
ensureHistogramIsCorrect(
metric3,
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[2].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[2].dataPoints[0].startTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0].endTime),
hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0].startTime),
[0, 100],
[0, 2, 0]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { Resource } from '@opentelemetry/resources';
import * as assert from 'assert';
import { InstrumentationScope, VERSION } from '@opentelemetry/core';
import {
Aggregation,
AggregationTemporality,
ExplicitBucketHistogramAggregation,
MeterProvider,
Expand Down Expand Up @@ -57,6 +58,10 @@ class TestMetricReader extends MetricReader {
return Promise.resolve(undefined);
}

selectAggregation() {
return Aggregation.Default();
}

selectAggregationTemporality() {
return AggregationTemporality.CUMULATIVE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,29 +288,34 @@ describe('OTLPMetricExporter - node with json over http', () => {
const responseBody = buff.toString();

const json = JSON.parse(responseBody) as IExportMetricsServiceRequest;
const metric1 = json.resourceMetrics[0].scopeMetrics[0].metrics[0];
const metric2 = json.resourceMetrics[0].scopeMetrics[0].metrics[1];
const metric3 = json.resourceMetrics[0].scopeMetrics[0].metrics[2];
// The order of the metrics is not guaranteed.
const counterIndex = metrics.scopeMetrics[0].metrics.findIndex(it => it.descriptor.name === 'int-counter');
const observableIndex = metrics.scopeMetrics[0].metrics.findIndex(it => it.descriptor.name === 'double-observable-gauge2');
const histogramIndex = metrics.scopeMetrics[0].metrics.findIndex(it => it.descriptor.name === 'int-histogram');

const metric1 = json.resourceMetrics[0].scopeMetrics[0].metrics[counterIndex];
const metric2 = json.resourceMetrics[0].scopeMetrics[0].metrics[observableIndex];
const metric3 = json.resourceMetrics[0].scopeMetrics[0].metrics[histogramIndex];

assert.ok(typeof metric1 !== 'undefined', "counter doesn't exist");
ensureCounterIsCorrect(
metric1,
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[0].dataPoints[0].endTime),
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[0].dataPoints[0].startTime)
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0].endTime),
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0].startTime)
);
assert.ok(typeof metric2 !== 'undefined', "observable gauge doesn't exist");
ensureObservableGaugeIsCorrect(
metric2,
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[1].dataPoints[0].endTime),
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[1].dataPoints[0].startTime),
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0].endTime),
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0].startTime),
6,
'double-observable-gauge2'
);
assert.ok(typeof metric3 !== 'undefined', "histogram doesn't exist");
ensureHistogramIsCorrect(
metric3,
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[2].dataPoints[0].endTime),
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[2].dataPoints[0].startTime),
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0].endTime),
core.hrTimeToNanoseconds(metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0].startTime),
[0, 100],
[0, 2, 0]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,14 @@ describe('OTLPMetricExporter - node with proto over http', () => {
const data = ExportTraceServiceRequestProto.decode(buff);
const json = data?.toJSON() as IExportMetricsServiceRequest;

const metric1 = json.resourceMetrics[0].scopeMetrics[0].metrics[0];
const metric2 = json.resourceMetrics[0].scopeMetrics[0].metrics[1];
const metric3 = json.resourceMetrics[0].scopeMetrics[0].metrics[2];
// The order of the metrics is not guaranteed.
const counterIndex = metrics.scopeMetrics[0].metrics.findIndex(it => it.descriptor.name === 'int-counter');
const observableIndex = metrics.scopeMetrics[0].metrics.findIndex(it => it.descriptor.name === 'double-observable-gauge');
const histogramIndex = metrics.scopeMetrics[0].metrics.findIndex(it => it.descriptor.name === 'int-histogram');

const metric1 = json.resourceMetrics[0].scopeMetrics[0].metrics[counterIndex];
const metric2 = json.resourceMetrics[0].scopeMetrics[0].metrics[observableIndex];
const metric3 = json.resourceMetrics[0].scopeMetrics[0].metrics[histogramIndex];

assert.ok(typeof metric1 !== 'undefined', "counter doesn't exist");
ensureExportedCounterIsCorrect(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
import { Resource } from '@opentelemetry/resources';
import * as assert from 'assert';
import {
Aggregation,
AggregationTemporality,
ExplicitBucketHistogramAggregation,
MeterProvider,
Expand All @@ -34,6 +35,10 @@ import { IExportMetricsServiceRequest, IKeyValue, IMetric } from '@opentelemetry
import { Stream } from 'stream';

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

selectAggregationTemporality() {
return AggregationTemporality.CUMULATIVE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { diag } from '@opentelemetry/api';
import {
globalErrorHandler,
} from '@opentelemetry/core';
import { AggregationTemporality, MetricReader } from '@opentelemetry/sdk-metrics';
import { Aggregation, AggregationTemporality, MetricReader } from '@opentelemetry/sdk-metrics';
import { createServer, IncomingMessage, Server, ServerResponse } from 'http';
import { ExporterConfig } from './export/types';
import { PrometheusSerializer } from './PrometheusSerializer';
Expand Down Expand Up @@ -90,6 +90,10 @@ export class PrometheusExporter extends MetricReader {
}
}

selectAggregation(): Aggregation {
return Aggregation.Default();
}

selectAggregationTemporality(): AggregationTemporality {
return AggregationTemporality.CUMULATIVE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
*/

import { Meter, ObservableResult } from '@opentelemetry/api-metrics';
import {
MeterProvider,
} from '@opentelemetry/sdk-metrics';
import { MeterProvider } from '@opentelemetry/sdk-metrics';
import * as assert from 'assert';
import * as sinon from 'sinon';
import * as http from 'http';
Expand Down Expand Up @@ -480,22 +478,19 @@ describe('PrometheusExporter', () => {
let meter: Meter;
let meterProvider: MeterProvider;
let counter: Counter;
let exporter: PrometheusExporter | undefined;
let exporter: PrometheusExporter;

beforeEach(() => {
function setup(reader: PrometheusExporter) {
meterProvider = new MeterProvider();
meterProvider.addMetricReader(reader);

meter = meterProvider.getMeter('test-prometheus');
counter = meter.createCounter('counter');
counter.add(10, { key1: 'attributeValue1' });
});
}

afterEach(done => {
if (exporter) {
exporter.shutdown().then(done);
exporter = undefined;
} else {
done();
}
afterEach(async () => {
await exporter.shutdown();
});

it('should use a configured name prefix', done => {
Expand All @@ -504,7 +499,7 @@ describe('PrometheusExporter', () => {
prefix: 'test_prefix',
},
async () => {
meterProvider.addMetricReader(exporter!);
setup(exporter);
http
.get('http://localhost:9464/metrics', res => {
res.on('data', chunk => {
Expand Down Expand Up @@ -532,7 +527,7 @@ describe('PrometheusExporter', () => {
port: 8080,
},
async () => {
meterProvider.addMetricReader(exporter!);
setup(exporter);
http
.get('http://localhost:8080/metrics', res => {
res.on('data', chunk => {
Expand Down Expand Up @@ -560,7 +555,7 @@ describe('PrometheusExporter', () => {
endpoint: '/test',
},
async () => {
meterProvider.addMetricReader(exporter!);
setup(exporter);
http
.get('http://localhost:9464/test', res => {
res.on('data', chunk => {
Expand Down Expand Up @@ -588,7 +583,7 @@ describe('PrometheusExporter', () => {
appendTimestamp: false,
},
async () => {
meterProvider.addMetricReader(exporter!);
setup(exporter);
http
.get('http://localhost:9464/metrics', res => {
res.on('data', chunk => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import * as assert from 'assert';
import { MetricAttributes, UpDownCounter } from '@opentelemetry/api-metrics';
import {
Aggregation,
AggregationTemporality,
DataPoint,
DataPointType,
Expand Down Expand Up @@ -46,6 +47,10 @@ class TestMetricReader extends MetricReader {
return AggregationTemporality.CUMULATIVE;
}

selectAggregation() {
return Aggregation.Default();
}

async onForceFlush() {}

async onShutdown() {}
Expand Down
Loading