From a310e376bb55d46bd94744364462d5e7aea5f0cb Mon Sep 17 00:00:00 2001 From: "marc.pichler" Date: Wed, 29 Jun 2022 16:58:06 +0200 Subject: [PATCH] feature(views): move views registration to MeterProvider constructor --- .../test/metricsHelper.ts | 19 +- .../browser/CollectorMetricExporter.test.ts | 4 +- .../test/metricsHelper.ts | 30 +- .../test/node/CollectorMetricExporter.test.ts | 4 +- .../test/metricsHelper.ts | 15 +- .../test/PrometheusSerializer.test.ts | 107 +++---- .../src/MeterProvider.ts | 30 +- .../test/MeterProvider.test.ts | 266 +++++++++++------- .../test/state/MeterSharedState.test.ts | 50 ++-- 9 files changed, 312 insertions(+), 213 deletions(-) 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 c2511d17c5..428eaf5f7a 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/metricsHelper.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/metricsHelper.ts @@ -59,7 +59,19 @@ export async function collect() { } export function setUp() { - meterProvider = new MeterProvider({ resource: testResource }); + meterProvider = new MeterProvider({ + resource: testResource, + views: [{ + view: { + aggregation: new ExplicitBucketHistogramAggregation([0, 100]) + }, + selector: { + instrument: { + name: 'int-histogram' + } + } + }] + }); reader = new TestMetricReader(); meterProvider.addMetricReader( reader @@ -96,10 +108,7 @@ export function mockObservableGauge( } export function mockHistogram(): Histogram { - const name = 'int-histogram'; - meterProvider.addView({ aggregation: new ExplicitBucketHistogramAggregation([0, 100]) }); - - return meter.createHistogram(name, { + return meter.createHistogram('int-histogram', { description: 'sample histogram description', valueType: ValueType.INT, }); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts index f1e00dce99..c76ca3ebdc 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts @@ -27,7 +27,7 @@ import { ensureExportMetricsServiceRequestIsSet, ensureHeadersContain, ensureHistogramIsCorrect, ensureObservableGaugeIsCorrect, - ensureWebResourceIsCorrect, + ensureWebResourceIsCorrect, HISTOGRAM_AGGREGATION_VIEW, mockCounter, mockHistogram, mockObservableGauge, @@ -47,7 +47,7 @@ describe('OTLPMetricExporter - web', () => { let errorStub: sinon.SinonStub; beforeEach(async () => { - setUp(); + setUp([HISTOGRAM_AGGREGATION_VIEW]); stubOpen = sinon.stub(XMLHttpRequest.prototype, 'open'); sinon.stub(XMLHttpRequest.prototype, 'send'); stubBeacon = sinon.stub(navigator, 'sendBeacon'); 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 3725a52f70..6e63a335ea 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/metricsHelper.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/metricsHelper.ts @@ -30,7 +30,7 @@ import { AggregationTemporality, ExplicitBucketHistogramAggregation, MeterProvider, - MetricReader + MetricReader, ViewRegistrationOptions } from '@opentelemetry/sdk-metrics-base'; import { IExportMetricsServiceRequest, @@ -61,6 +61,17 @@ class TestMetricReader extends MetricReader { } } +export const HISTOGRAM_AGGREGATION_VIEW = { + view: { + aggregation: new ExplicitBucketHistogramAggregation([0, 100]) + }, + selector: { + instrument: { + name: 'int-histogram' + } + } +}; + const defaultResource = Resource.default().merge(new Resource({ service: 'ui', version: 1, @@ -78,8 +89,8 @@ export async function collect() { return (await reader.collect())!; } -export function setUp() { - meterProvider = new MeterProvider({ resource: defaultResource }); +export function setUp(views?: ViewRegistrationOptions[]) { + meterProvider = new MeterProvider({ resource: defaultResource, views }); reader = new TestMetricReader(); meterProvider.addMetricReader( reader @@ -158,18 +169,7 @@ export function mockObservableUpDownCounter( } export function mockHistogram(): Histogram { - const name = 'int-histogram'; - - meterProvider.addView({ - aggregation: new ExplicitBucketHistogramAggregation([0, 100]) - }, - { - instrument: { - name: name - } - }); - - return meter.createHistogram(name, { + return meter.createHistogram('int-histogram', { description: 'sample histogram description', valueType: ValueType.INT, }); 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 c1b16cd278..4bec7327c3 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 @@ -35,7 +35,7 @@ import { mockCounter, mockObservableGauge, mockHistogram, - collect, shutdown, setUp, + collect, shutdown, setUp, HISTOGRAM_AGGREGATION_VIEW, } from '../metricsHelper'; import { MockedResponse } from './nodeHelpers'; import { AggregationTemporality, ResourceMetrics } from '@opentelemetry/sdk-metrics-base'; @@ -54,7 +54,7 @@ describe('OTLPMetricExporter - node with json over http', () => { let metrics: ResourceMetrics; beforeEach(async () => { - setUp(); + setUp([HISTOGRAM_AGGREGATION_VIEW]); }); afterEach(async () => { 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 bb78daf397..354ad60a46 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/metricsHelper.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/metricsHelper.ts @@ -64,7 +64,19 @@ export async function collect() { } export function setUp() { - meterProvider = new MeterProvider({ resource: testResource }); + meterProvider = new MeterProvider({ + resource: testResource, + views: [{ + view: { + aggregation: new ExplicitBucketHistogramAggregation([0, 100]) + }, + selector: { + instrument: { + name: 'int-histogram' + } + } + }] + }); reader = new TestMetricReader(); meterProvider.addMetricReader( reader @@ -102,7 +114,6 @@ export function mockObservableGauge( export function mockHistogram(): Histogram { const name = 'int-histogram'; - meterProvider.addView({ aggregation: new ExplicitBucketHistogramAggregation([0, 100]) }); return meter.createHistogram(name, { description: 'sample histogram description', diff --git a/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts b/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts index f0dc004e25..8876594a79 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts +++ b/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts @@ -45,6 +45,7 @@ class TestMetricReader extends MetricReader { } async onForceFlush() {} + async onShutdown() {} } @@ -67,11 +68,12 @@ describe('PrometheusSerializer', () => { describe('Singular', () => { async function testSerializer(serializer: PrometheusSerializer) { const reader = new TestMetricReader(); - const meterProvider = new MeterProvider(); + const meterProvider = new MeterProvider( + { + views: [{ view: { aggregation: new SumAggregation() } }] + } + ); meterProvider.addMetricReader(reader); - meterProvider.addView({ - aggregation: new SumAggregation(), - }); const meter = meterProvider.getMeter('test'); const counter = meter.createCounter('test_total'); @@ -112,9 +114,10 @@ describe('PrometheusSerializer', () => { describe('Histogram', () => { async function testSerializer(serializer: PrometheusSerializer) { const reader = new TestMetricReader(); - const meterProvider = new MeterProvider(); + const meterProvider = new MeterProvider({ + views: [{ view: { aggregation: new ExplicitBucketHistogramAggregation([1, 10, 100]) } }] + }); meterProvider.addMetricReader(reader); - meterProvider.addView({ aggregation: new ExplicitBucketHistogramAggregation([1, 10, 100]) }); const meter = meterProvider.getMeter('test'); const histogram = meter.createHistogram('test'); @@ -139,11 +142,11 @@ describe('PrometheusSerializer', () => { assert.strictEqual( result, `test_count{foo1="bar1",foo2="bar2"} 1 ${mockedHrTimeMs}\n` + - `test_sum{foo1="bar1",foo2="bar2"} 5 ${mockedHrTimeMs}\n` + - `test_bucket{foo1="bar1",foo2="bar2",le="1"} 0 ${mockedHrTimeMs}\n` + - `test_bucket{foo1="bar1",foo2="bar2",le="10"} 1 ${mockedHrTimeMs}\n` + - `test_bucket{foo1="bar1",foo2="bar2",le="100"} 1 ${mockedHrTimeMs}\n` + - `test_bucket{foo1="bar1",foo2="bar2",le="+Inf"} 1 ${mockedHrTimeMs}\n` + `test_sum{foo1="bar1",foo2="bar2"} 5 ${mockedHrTimeMs}\n` + + `test_bucket{foo1="bar1",foo2="bar2",le="1"} 0 ${mockedHrTimeMs}\n` + + `test_bucket{foo1="bar1",foo2="bar2",le="10"} 1 ${mockedHrTimeMs}\n` + + `test_bucket{foo1="bar1",foo2="bar2",le="100"} 1 ${mockedHrTimeMs}\n` + + `test_bucket{foo1="bar1",foo2="bar2",le="+Inf"} 1 ${mockedHrTimeMs}\n` ); }); @@ -153,11 +156,11 @@ describe('PrometheusSerializer', () => { assert.strictEqual( result, 'test_count{foo1="bar1",foo2="bar2"} 1\n' + - 'test_sum{foo1="bar1",foo2="bar2"} 5\n' + - 'test_bucket{foo1="bar1",foo2="bar2",le="1"} 0\n' + - 'test_bucket{foo1="bar1",foo2="bar2",le="10"} 1\n' + - 'test_bucket{foo1="bar1",foo2="bar2",le="100"} 1\n' + - 'test_bucket{foo1="bar1",foo2="bar2",le="+Inf"} 1\n' + 'test_sum{foo1="bar1",foo2="bar2"} 5\n' + + 'test_bucket{foo1="bar1",foo2="bar2",le="1"} 0\n' + + 'test_bucket{foo1="bar1",foo2="bar2",le="10"} 1\n' + + 'test_bucket{foo1="bar1",foo2="bar2",le="100"} 1\n' + + 'test_bucket{foo1="bar1",foo2="bar2",le="+Inf"} 1\n' ); }); }); @@ -167,9 +170,10 @@ describe('PrometheusSerializer', () => { describe('Singular', () => { async function testSerializer(serializer: PrometheusSerializer) { const reader = new TestMetricReader(); - const meterProvider = new MeterProvider(); + const meterProvider = new MeterProvider({ + views: [{ view: { aggregation: new SumAggregation() } }] + }); meterProvider.addMetricReader(reader); - meterProvider.addView({ aggregation: new SumAggregation() }); const meter = meterProvider.getMeter('test'); const counter = meter.createCounter('test_total', { @@ -194,9 +198,9 @@ describe('PrometheusSerializer', () => { assert.strictEqual( result, '# HELP test_total foobar\n' + - '# TYPE test_total counter\n' + - `test_total{val="1"} 1 ${mockedHrTimeMs}\n` + - `test_total{val="2"} 1 ${mockedHrTimeMs}\n` + '# TYPE test_total counter\n' + + `test_total{val="1"} 1 ${mockedHrTimeMs}\n` + + `test_total{val="2"} 1 ${mockedHrTimeMs}\n` ); }); @@ -206,9 +210,9 @@ describe('PrometheusSerializer', () => { assert.strictEqual( result, '# HELP test_total foobar\n' + - '# TYPE test_total counter\n' + - 'test_total{val="1"} 1\n' + - 'test_total{val="2"} 1\n' + '# TYPE test_total counter\n' + + 'test_total{val="1"} 1\n' + + 'test_total{val="2"} 1\n' ); }); }); @@ -216,9 +220,10 @@ describe('PrometheusSerializer', () => { describe('with ExplicitBucketHistogramAggregation', () => { async function testSerializer(serializer: PrometheusSerializer) { const reader = new TestMetricReader(); - const meterProvider = new MeterProvider(); + const meterProvider = new MeterProvider({ + views: [{ view: { aggregation: new ExplicitBucketHistogramAggregation([1, 10, 100]) } }] + }); meterProvider.addMetricReader(reader); - meterProvider.addView({ aggregation: new ExplicitBucketHistogramAggregation([1, 10, 100]) }); const meter = meterProvider.getMeter('test'); const histogram = meter.createHistogram('test', { @@ -246,19 +251,19 @@ describe('PrometheusSerializer', () => { assert.strictEqual( result, '# HELP test foobar\n' + - '# TYPE test histogram\n' + - `test_count{val="1"} 3 ${mockedHrTimeMs}\n` + - `test_sum{val="1"} 175 ${mockedHrTimeMs}\n` + - `test_bucket{val="1",le="1"} 0 ${mockedHrTimeMs}\n` + - `test_bucket{val="1",le="10"} 1 ${mockedHrTimeMs}\n` + - `test_bucket{val="1",le="100"} 2 ${mockedHrTimeMs}\n` + - `test_bucket{val="1",le="+Inf"} 3 ${mockedHrTimeMs}\n` + - `test_count{val="2"} 1 ${mockedHrTimeMs}\n` + - `test_sum{val="2"} 5 ${mockedHrTimeMs}\n` + - `test_bucket{val="2",le="1"} 0 ${mockedHrTimeMs}\n` + - `test_bucket{val="2",le="10"} 1 ${mockedHrTimeMs}\n` + - `test_bucket{val="2",le="100"} 1 ${mockedHrTimeMs}\n` + - `test_bucket{val="2",le="+Inf"} 1 ${mockedHrTimeMs}\n` + '# TYPE test histogram\n' + + `test_count{val="1"} 3 ${mockedHrTimeMs}\n` + + `test_sum{val="1"} 175 ${mockedHrTimeMs}\n` + + `test_bucket{val="1",le="1"} 0 ${mockedHrTimeMs}\n` + + `test_bucket{val="1",le="10"} 1 ${mockedHrTimeMs}\n` + + `test_bucket{val="1",le="100"} 2 ${mockedHrTimeMs}\n` + + `test_bucket{val="1",le="+Inf"} 3 ${mockedHrTimeMs}\n` + + `test_count{val="2"} 1 ${mockedHrTimeMs}\n` + + `test_sum{val="2"} 5 ${mockedHrTimeMs}\n` + + `test_bucket{val="2",le="1"} 0 ${mockedHrTimeMs}\n` + + `test_bucket{val="2",le="10"} 1 ${mockedHrTimeMs}\n` + + `test_bucket{val="2",le="100"} 1 ${mockedHrTimeMs}\n` + + `test_bucket{val="2",le="+Inf"} 1 ${mockedHrTimeMs}\n` ); }); }); @@ -267,9 +272,10 @@ describe('PrometheusSerializer', () => { describe('validate against metric conventions', () => { async function getCounterResult(name: string, serializer: PrometheusSerializer) { const reader = new TestMetricReader(); - const meterProvider = new MeterProvider(); + const meterProvider = new MeterProvider({ + views: [{ view: { aggregation: new SumAggregation() } }] + }); meterProvider.addMetricReader(reader); - meterProvider.addView({ aggregation: new SumAggregation() }); const meter = meterProvider.getMeter('test'); const counter = meter.createCounter(name); @@ -306,9 +312,10 @@ describe('PrometheusSerializer', () => { describe('serialize non-normalized values', () => { async function testSerializer(serializer: PrometheusSerializer, name: string, fn: (counter: UpDownCounter) => void) { const reader = new TestMetricReader(); - const meterProvider = new MeterProvider(); + const meterProvider = new MeterProvider({ + views: [{ view: { aggregation: new SumAggregation() } }] + }); meterProvider.addMetricReader(reader); - meterProvider.addView({ aggregation: new SumAggregation() }); const meter = meterProvider.getMeter('test'); const counter = meter.createUpDownCounter(name); @@ -392,13 +399,13 @@ describe('PrometheusSerializer', () => { assert.strictEqual( result, 'test_total{' + - 'backslash="\u005c\u005c",' + - 'doubleQuote="\u005c\u0022",' + - 'lineFeed="\u005c\u006e",' + - 'backslashN="\u005c\u005c\u006e",' + - 'backslashDoubleQuote="\u005c\u005c\u005c\u0022",' + - 'backslashLineFeed="\u005c\u005c\u005c\u006e"' + - `} 1 ${mockedHrTimeMs}\n` + 'backslash="\u005c\u005c",' + + 'doubleQuote="\u005c\u0022",' + + 'lineFeed="\u005c\u006e",' + + 'backslashN="\u005c\u005c\u006e",' + + 'backslashDoubleQuote="\u005c\u005c\u005c\u0022",' + + 'backslashLineFeed="\u005c\u005c\u005c\u006e"' + + `} 1 ${mockedHrTimeMs}\n` ); }); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/MeterProvider.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/MeterProvider.ts index 5c0e2b6e1d..50d51e48cd 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/MeterProvider.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/MeterProvider.ts @@ -35,6 +35,12 @@ import { ForceFlushOptions, ShutdownOptions } from './types'; export interface MeterProviderOptions { /** Resource associated with metric telemetry */ resource?: Resource; + views?: ViewRegistrationOptions[]; +} + +export interface ViewRegistrationOptions { + view: ViewOptions; + selector?: SelectorOptions; } export type ViewOptions = { @@ -102,6 +108,11 @@ export class MeterProvider implements metrics.MeterProvider { constructor(options?: MeterProviderOptions) { this._sharedState = new MeterProviderSharedState(options?.resource ?? Resource.empty()); + if(options?.views != null && options.views.length > 0){ + for(const view of options.views){ + this.addView(view); + } + } } /** @@ -131,14 +142,17 @@ export class MeterProvider implements metrics.MeterProvider { this._sharedState.metricCollectors.push(collector); } - addView(options: ViewOptions, selectorOptions?: SelectorOptions) { - if (isViewOptionsEmpty(options)) { + private addView(registrationOptions: ViewRegistrationOptions) { + const viewOptions = registrationOptions.view; + const selectorOptions = registrationOptions.selector; + + if (isViewOptionsEmpty(viewOptions)) { throw new Error('Cannot create view with no view arguments supplied'); } // the SDK SHOULD NOT allow Views with a specified name to be declared with instrument selectors that // may select more than one instrument (e.g. wild card instrument name) in the same Meter. - if (options.name != null && + if (viewOptions.name != null && (selectorOptions?.instrument?.name == null || PatternPredicate.hasWildcard(selectorOptions.instrument.name))) { throw new Error('Views with a specified name must be declared with an instrument selector that selects at most one instrument per meter.'); @@ -146,14 +160,14 @@ export class MeterProvider implements metrics.MeterProvider { // Create AttributesProcessor if attributeKeys are defined set. let attributesProcessor = undefined; - if (options.attributeKeys != null) { - attributesProcessor = new FilteringAttributesProcessor(options.attributeKeys); + if (viewOptions.attributeKeys != null) { + attributesProcessor = new FilteringAttributesProcessor(viewOptions.attributeKeys); } const view = new View({ - name: options.name, - description: options.description, - aggregation: options.aggregation, + name: viewOptions.name, + description: viewOptions.description, + aggregation: viewOptions.aggregation, attributesProcessor: attributesProcessor }); const instrument = new InstrumentSelector(selectorOptions?.instrument); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/MeterProvider.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/MeterProvider.test.ts index 0d4e5d80db..999f3d83dd 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/MeterProvider.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/MeterProvider.test.ts @@ -113,77 +113,101 @@ describe('MeterProvider', () => { describe('addView', () => { it('with named view and instrument wildcard should throw', () => { - const meterProvider = new MeterProvider({ resource: defaultResource }); - // Throws with wildcard character only. - assert.throws(() => meterProvider.addView({ - name: 'renamed-instrument' - }, - { - instrument: { - name: '*' - } + assert.throws(() => new MeterProvider({ + resource: defaultResource, + views: [{ + view: { + name: 'renamed-instrument' + }, + selector: { + instrument: { + name: '*' + } + } + }] })); // Throws with wildcard character in instrument name. - assert.throws(() => meterProvider.addView({ - name: 'renamed-instrument' - }, { - instrument: { - name: 'other.instrument.*' - } + assert.throws(() => new MeterProvider({ + resource: defaultResource, + views: [ + { + view: { + name: 'renamed-instrument' + }, + selector: { + instrument: { + name: '*' + } + } + } + ] })); }); it('with named view and instrument type selector should throw', () => { - const meterProvider = new MeterProvider({ resource: defaultResource }); - - assert.throws(() => meterProvider.addView({ - name: 'renamed-instrument' - }, - { - instrument: { - type: InstrumentType.COUNTER - } + assert.throws(() => new MeterProvider({ + resource: defaultResource, + views: [ + { + view: { + name: 'renamed-instrument' + }, + selector: { + instrument: { + type: InstrumentType.COUNTER + } + } + } + ] })); }); it('with named view and no instrument selector should throw', () => { - const meterProvider = new MeterProvider({ resource: defaultResource }); - - assert.throws(() => meterProvider.addView({ - name: 'renamed-instrument' + assert.throws(() => new MeterProvider({ + resource: defaultResource, views: [ + { + view: { + name: 'renamed-instrument' + } + } + ] })); - - assert.throws(() => meterProvider.addView({ - name: 'renamed-instrument' - }, - {})); }); it('with no view parameters should throw', () => { - const meterProvider = new MeterProvider({ resource: defaultResource }); - - assert.throws(() => meterProvider.addView({})); + assert.throws(() => new MeterProvider({ + resource: defaultResource, views: [ + { + view: {} + } + ] + })); }); it('with existing instrument should rename', async () => { - const meterProvider = new MeterProvider({ resource: defaultResource }); + const meterProvider = new MeterProvider({ + resource: defaultResource, + // Add view to rename 'non-renamed-instrument' to 'renamed-instrument' + views: [ + { + view: { + name: 'renamed-instrument', + description: 'my renamed instrument' + }, + selector: { + instrument: { + name: 'non-renamed-instrument', + }, + } + } + ] + }); const reader = new TestMetricReader(); meterProvider.addMetricReader(reader); - // Add view to rename 'non-renamed-instrument' to 'renamed-instrument' - meterProvider.addView({ - name: 'renamed-instrument', - description: 'my renamed instrument' - }, - { - instrument: { - name: 'non-renamed-instrument', - }, - }); - // Create meter and instrument. const myMeter = meterProvider.getMeter('meter1', 'v1.0.0'); const counter = myMeter.createCounter('non-renamed-instrument'); @@ -228,21 +252,27 @@ describe('MeterProvider', () => { }); it('with attributeKeys should drop non-listed attributes', async () => { - const meterProvider = new MeterProvider({ resource: defaultResource }); - - const reader = new TestMetricReader(); - meterProvider.addMetricReader(reader); // Add view to drop all attributes except 'attrib1' - meterProvider.addView({ - attributeKeys: ['attrib1'] - }, - { - instrument: { - name: 'non-renamed-instrument', - } + const meterProvider = new MeterProvider({ + resource: defaultResource, + views: [ + { + view: { + attributeKeys: ['attrib1'] + }, + selector: { + instrument: { + name: 'non-renamed-instrument', + } + } + } + ] }); + const reader = new TestMetricReader(); + meterProvider.addMetricReader(reader); + // Create meter and instrument. const myMeter = meterProvider.getMeter('meter1', 'v1.0.0'); const counter = myMeter.createCounter('non-renamed-instrument'); @@ -285,21 +315,26 @@ describe('MeterProvider', () => { }); it('with no meter name should apply view to instruments of all meters', async () => { - const meterProvider = new MeterProvider({ resource: defaultResource }); + // Add view that renames 'test-counter' to 'renamed-instrument' + const meterProvider = new MeterProvider({ + resource: defaultResource, + views: [ + { + view: { + name: 'renamed-instrument' + }, + selector: { + instrument: { + name: 'test-counter' + } + } + } + ] + }); const reader = new TestMetricReader(); meterProvider.addMetricReader(reader); - // Add view that renames 'test-counter' to 'renamed-instrument' - meterProvider.addView({ - name: 'renamed-instrument' - }, - { - instrument: { - name: 'test-counter' - } - }); - // Create two meters. const meter1 = meterProvider.getMeter('meter1', 'v1.0.0'); const meter2 = meterProvider.getMeter('meter2', 'v1.0.0'); @@ -351,23 +386,30 @@ describe('MeterProvider', () => { }); it('with meter name should apply view to only the selected meter', async () => { - const meterProvider = new MeterProvider({ resource: defaultResource }); + const meterProvider = new MeterProvider({ + resource: defaultResource, + views: [ + // Add view that renames 'test-counter' to 'renamed-instrument' on 'meter1' + { + view: { + name: 'renamed-instrument' + }, + selector: + { + instrument: { + name: 'test-counter' + }, + meter: { + name: 'meter1' + } + } + } + ] + }); const reader = new TestMetricReader(); meterProvider.addMetricReader(reader); - // Add view that renames 'test-counter' to 'renamed-instrument' on 'meter1' - meterProvider.addView({ - name: 'renamed-instrument' - }, - { - instrument: { - name: 'test-counter' - }, - meter: { - name: 'meter1' - } - }); // Create two meters. const meter1 = meterProvider.getMeter('meter1', 'v1.0.0'); @@ -420,35 +462,41 @@ describe('MeterProvider', () => { }); it('with different instrument types does not throw', async () => { - const meterProvider = new MeterProvider({ resource: defaultResource }); + const meterProvider = new MeterProvider({ + resource: defaultResource, + // Add Views to rename both instruments (of different types) to the same name. + views: [ + { + view: { + name: 'renamed-instrument' + }, + selector: { + instrument: { + name: 'test-counter', + }, + meter: { + name: 'meter1' + } + } + }, + { + view: { + name: 'renamed-instrument' + }, + selector: { + instrument: { + name: 'test-histogram', + }, + meter: { + name: 'meter1' + } + } + } + ] + }); const reader = new TestMetricReader(); meterProvider.addMetricReader(reader); - // Add Views to rename both instruments (of different types) to the same name. - meterProvider.addView({ - name: 'renamed-instrument' - }, - { - instrument: { - name: 'test-counter' - }, - meter: { - name: 'meter1' - } - }); - - meterProvider.addView({ - name: 'renamed-instrument' - }, - { - instrument: { - name: 'test-histogram' - }, - meter: { - name: 'meter1' - } - }); - // Create meter and instruments. const meter = meterProvider.getMeter('meter1', 'v1.0.0'); const counter = meter.createCounter('test-counter', { unit: 'ms' }); 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 1ecc5732c1..c9e844086b 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 @@ -21,7 +21,7 @@ import { Meter, MeterProvider, DataPointType, - CollectionResult + CollectionResult, ViewRegistrationOptions } from '../../src'; import { assertMetricData, defaultInstrumentationScope, defaultResource, sleep } from '../util'; import { TestMetricReader } from '../export/TestMetricReader'; @@ -33,8 +33,8 @@ describe('MeterSharedState', () => { }); describe('collect', () => { - function setupInstruments() { - const meterProvider = new MeterProvider({ resource: defaultResource }); + function setupInstruments(views?: ViewRegistrationOptions[]) { + const meterProvider = new MeterProvider({ resource: defaultResource, views: views }); const cumulativeReader = new TestMetricReader(() => AggregationTemporality.CUMULATIVE); meterProvider.addMetricReader(cumulativeReader); @@ -51,7 +51,7 @@ describe('MeterSharedState', () => { }) as Meter; const meterSharedState = meter['_meterSharedState'] as MeterSharedState; - return { metricCollectors, cumulativeCollector, deltaCollector, meter, meterSharedState, meterProvider }; + return { metricCollectors, cumulativeCollector, deltaCollector, meter, meterSharedState }; } it('should collect sync metrics', async () => { @@ -76,12 +76,12 @@ describe('MeterSharedState', () => { it('should collect sync metrics with views', async () => { /** preparing test instrumentations */ - const { metricCollectors, meter, meterProvider } = setupInstruments(); + const { metricCollectors, meter } = setupInstruments([ + { view: { name: 'foo' }, selector: { instrument: { name: 'test' } } }, + { view: { name: 'bar' }, selector: { instrument: { name: 'test' } } } + ]); /** creating metric events */ - meterProvider.addView({ name: 'foo' }, { instrument: { name: 'test' } }); - meterProvider.addView({ name: 'bar' }, { instrument: { name: 'test' } }); - const counter = meter.createCounter('test'); /** collect metrics */ @@ -135,20 +135,30 @@ describe('MeterSharedState', () => { it('should call observable callback once with view-ed async instruments', async () => { /** preparing test instrumentations */ - const { metricCollectors, meter, meterProvider } = setupInstruments(); - - /** creating metric events */ - meterProvider.addView({ name: 'foo' }, { - instrument: { - name: 'test', + const { metricCollectors, meter } = setupInstruments([ + { + view: { + name: 'foo' + }, + selector: { + instrument: { + name: 'test' + } + } }, - }); - meterProvider.addView({ name: 'bar' }, { - instrument: { - name: 'test', - }, - }); + { + view: { + name: 'bar' + }, + selector: { + instrument: { + name: 'test' + } + } + } + ]); + /** creating metric events */ let observableCalledCount = 0; const observableCounter = meter.createObservableCounter('test'); observableCounter.addCallback(observableResult => {