diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/state/MeterProviderSharedState.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/state/MeterProviderSharedState.ts index 6c35e650bf8..a4d909ddef7 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/state/MeterProviderSharedState.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/state/MeterProviderSharedState.ts @@ -30,15 +30,21 @@ export class MeterProviderSharedState { metricCollectors: MetricCollector[] = []; - meterSharedStates: MeterSharedState[] = []; + meterSharedStates: Map = new Map(); constructor(public resource: Resource) {} getMeterSharedState(instrumentationLibrary: InstrumentationLibrary) { - // TODO: meter identity - // https://github.com/open-telemetry/opentelemetry-js/issues/2593 - const meterSharedState = new MeterSharedState(this, instrumentationLibrary); - this.meterSharedStates.push(meterSharedState); + const id = this.instrumentationLibraryId(instrumentationLibrary); + let meterSharedState = this.meterSharedStates.get(id); + if (meterSharedState == null) { + meterSharedState = new MeterSharedState(this, instrumentationLibrary); + this.meterSharedStates.set(id, meterSharedState); + } return meterSharedState; } + + instrumentationLibraryId(instrumentationLibrary: InstrumentationLibrary) { + return `${instrumentationLibrary.name}:${instrumentationLibrary.version ?? ''}:${instrumentationLibrary.schemaUrl ?? ''}`; + } } 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 ac522a293a1..540a5e09179 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/state/MetricCollector.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/state/MetricCollector.ts @@ -35,8 +35,9 @@ export class MetricCollector implements MetricProducer { async collect(): Promise { const collectionTime = hrTime(); - const instrumentationLibraryMetrics = (await Promise.all(this._sharedState.meterSharedStates - .map(meterSharedState => meterSharedState.collect(this, collectionTime)))); + const meterCollectionPromises = Array.from(this._sharedState.meterSharedStates.values()) + .map(meterSharedState => meterSharedState.collect(this, collectionTime)); + const instrumentationLibraryMetrics = await Promise.all(meterCollectionPromises); return { resource: this._sharedState.resource, 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 bce870c6e63..b1e21fad598 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/MeterProvider.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/MeterProvider.test.ts @@ -56,6 +56,51 @@ describe('MeterProvider', () => { const meter = meterProvider.getMeter('meter1', '1.0.0'); assert.strictEqual(meter, NOOP_METER); }); + + it('get meter with same identity', async () => { + const meterProvider = new MeterProvider({ resource: defaultResource }); + const reader = new TestMetricReader(); + meterProvider.addMetricReader(reader); + + // Create meter and instrument. + // name+version pair 1 + meterProvider.getMeter('meter1', 'v1.0.0'); + meterProvider.getMeter('meter1', 'v1.0.0'); + // name+version pair 2 + meterProvider.getMeter('meter2', 'v1.0.0'); + meterProvider.getMeter('meter2', 'v1.0.0'); + // name+version pair 3 + meterProvider.getMeter('meter1', 'v1.0.1'); + meterProvider.getMeter('meter1', 'v1.0.1'); + // name+version+schemaUrl pair 4 + meterProvider.getMeter('meter1', 'v1.0.1', { schemaUrl: 'https://opentelemetry.io/schemas/1.4.0' }); + meterProvider.getMeter('meter1', 'v1.0.1', { schemaUrl: 'https://opentelemetry.io/schemas/1.4.0' }); + + // Perform collection. + const result = await reader.collect(); + + // Results came only from de-duplicated meters. + assert.strictEqual(result?.instrumentationLibraryMetrics.length, 4); + + // InstrumentationLibrary matches from de-duplicated meters. + assertInstrumentationLibraryMetrics(result?.instrumentationLibraryMetrics[0], { + name: 'meter1', + version: 'v1.0.0' + }); + assertInstrumentationLibraryMetrics(result?.instrumentationLibraryMetrics[1], { + name: 'meter2', + version: 'v1.0.0' + }); + assertInstrumentationLibraryMetrics(result?.instrumentationLibraryMetrics[2], { + name: 'meter1', + version: 'v1.0.1' + }); + assertInstrumentationLibraryMetrics(result?.instrumentationLibraryMetrics[3], { + name: 'meter1', + version: 'v1.0.1', + schemaUrl: 'https://opentelemetry.io/schemas/1.4.0', + }); + }); }); describe('addView', () => {