From 3e1a9a08389de1a30c9f33ac16a8cb20a7b358eb Mon Sep 17 00:00:00 2001 From: Mayur Kale Date: Mon, 7 Jan 2019 14:39:58 -0800 Subject: [PATCH] Add MetricProducerManager to keep track of all MetricProducers (#253) * Add MetricProducerManager to keep set of MetricProducer * fix review comments * fix review comments * Fix JSDoc and change copyright 2018 -> 2019 * Fix JSDoc comments --- ...ic-producer.ts => base-metric-producer.ts} | 4 +- .../metrics/export/metric-producer-manager.ts | 69 ++++++++++++++ .../src/metrics/export/types.ts | 24 +++++ .../src/metrics/metric-component.ts | 42 +++++++++ .../src/metrics/metric-registry.ts | 8 +- .../opencensus-core/src/metrics/metrics.ts | 23 +++-- .../src/stats/metric-producer.ts | 4 +- packages/opencensus-core/src/stats/stats.ts | 8 ++ .../test/test-metric-component.ts | 34 +++++++ .../test/test-metric-producer-manager.ts | 91 +++++++++++++++++++ 10 files changed, 289 insertions(+), 18 deletions(-) rename packages/opencensus-core/src/metrics/export/{metric-producer.ts => base-metric-producer.ts} (88%) create mode 100644 packages/opencensus-core/src/metrics/export/metric-producer-manager.ts create mode 100644 packages/opencensus-core/src/metrics/metric-component.ts create mode 100644 packages/opencensus-core/test/test-metric-component.ts create mode 100644 packages/opencensus-core/test/test-metric-producer-manager.ts diff --git a/packages/opencensus-core/src/metrics/export/metric-producer.ts b/packages/opencensus-core/src/metrics/export/base-metric-producer.ts similarity index 88% rename from packages/opencensus-core/src/metrics/export/metric-producer.ts rename to packages/opencensus-core/src/metrics/export/base-metric-producer.ts index af7c26f1b..87f2dbe2b 100644 --- a/packages/opencensus-core/src/metrics/export/metric-producer.ts +++ b/packages/opencensus-core/src/metrics/export/base-metric-producer.ts @@ -14,13 +14,13 @@ * limitations under the License. */ -import {Metric} from './types'; +import {Metric, MetricProducer} from './types'; /** * A MetricProducer producer that can be registered for exporting using * MetricProducerManager. */ -export abstract class MetricProducer { +export abstract class BaseMetricProducer implements MetricProducer { /** * Gets a collection of produced Metric`s to be exported. * @returns {Metric[]} List of metrics diff --git a/packages/opencensus-core/src/metrics/export/metric-producer-manager.ts b/packages/opencensus-core/src/metrics/export/metric-producer-manager.ts new file mode 100644 index 000000000..9d45ed5b3 --- /dev/null +++ b/packages/opencensus-core/src/metrics/export/metric-producer-manager.ts @@ -0,0 +1,69 @@ +/** + * Copyright 2019, OpenCensus 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 + * + * http://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 {validateNotNull} from '../../common/validations'; +import {MetricProducer, MetricProducerManager} from './types'; + +/** + * Keeps a set of MetricProducer that is used by exporters to determine the + * metrics that need to be exported. + */ +class BaseMetricProducerManager implements MetricProducerManager { + private metricProducers: Set = new Set(); + + /** + * Adds the MetricProducer to the manager if it is not already present. + * + * @param {MetricProducer} The MetricProducer to be added to the manager. + */ + add(metricProducer: MetricProducer): void { + validateNotNull(metricProducer, 'metricProducer'); + if (!this.metricProducers.has(metricProducer)) { + this.metricProducers.add(metricProducer); + } + } + + /** + * Removes the MetricProducer to the manager if it is present. + * + * @param {MetricProducer} The MetricProducer to be removed from the manager. + */ + remove(metricProducer: MetricProducer): void { + validateNotNull(metricProducer, 'metricProducer'); + this.metricProducers.delete(metricProducer); + } + + /** + * Clears all MetricProducers. + */ + removeAll(): void { + this.metricProducers.clear(); + } + + /** + * Returns all registered MetricProducers that should be exported. + * + * This method should be used by any metrics exporter that automatically + * exports data for MetricProducer registered with the MetricProducerManager. + * + * @return {Set} The Set of MetricProducers. + */ + getAllMetricProducer(): Set { + return this.metricProducers; + } +} + +export const metricProducerManagerInstance = new BaseMetricProducerManager(); diff --git a/packages/opencensus-core/src/metrics/export/types.ts b/packages/opencensus-core/src/metrics/export/types.ts index e8e8a1b20..c9f0288df 100644 --- a/packages/opencensus-core/src/metrics/export/types.ts +++ b/packages/opencensus-core/src/metrics/export/types.ts @@ -326,3 +326,27 @@ export interface Timestamp { */ nanos: number|null; } + +/** + * Keeps a set of MetricProducer that is used by exporters to determine the + * metrics that need to be exported. + */ +export interface MetricProducerManager { + /** Adds the MetricProducer to the manager */ + add(metricProducer: MetricProducer): void; + /** Removes the MetricProducer to the manager */ + remove(metricProducer: MetricProducer): void; + /** Clears all MetricProducers */ + removeAll(): void; + /** Gets all registered MetricProducers that should be exported */ + getAllMetricProducer(): Set; +} + +/** + * A MetricProducer producer that can be registered for exporting using + * MetricProducerManager. + */ +export interface MetricProducer { + /** Gets a collection of produced Metric`s to be exported */ + getMetrics(): Metric[]; +} diff --git a/packages/opencensus-core/src/metrics/metric-component.ts b/packages/opencensus-core/src/metrics/metric-component.ts new file mode 100644 index 000000000..a41133d02 --- /dev/null +++ b/packages/opencensus-core/src/metrics/metric-component.ts @@ -0,0 +1,42 @@ +/** + * Copyright 2019, OpenCensus 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 + * + * http://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 {metricProducerManagerInstance} from './export/metric-producer-manager'; +import {MetricRegistry} from './metric-registry'; + +/** + * Class that holds the implementation instance for MetricRegistry. + */ +export class MetricsComponent { + private metricRegistry: MetricRegistry; + + constructor() { + this.metricRegistry = new MetricRegistry(); + + // Register the MetricRegistry's MetricProducer to the global + // MetricProducerManager. + metricProducerManagerInstance.add(this.metricRegistry.getMetricProducer()); + } + + /** + * Returns the MetricRegistry. + * + * @return {MetricRegistry}. + */ + getMetricRegistry(): MetricRegistry { + return this.metricRegistry; + } +} diff --git a/packages/opencensus-core/src/metrics/metric-registry.ts b/packages/opencensus-core/src/metrics/metric-registry.ts index 462a8abb6..f72f21dca 100644 --- a/packages/opencensus-core/src/metrics/metric-registry.ts +++ b/packages/opencensus-core/src/metrics/metric-registry.ts @@ -15,10 +15,10 @@ */ import {validateArrayElementsNotNull, validateNotNull} from '../common/validations'; -import {MeasureUnit} from '../stats/types'; +import {MeasureUnit,} from '../stats/types'; -import {MetricProducer} from './export/metric-producer'; -import {LabelKey, Metric, MetricDescriptorType} from './export/types'; +import {BaseMetricProducer} from './export/base-metric-producer'; +import {LabelKey, Metric, MetricDescriptorType, MetricProducer} from './export/types'; import {DerivedGauge} from './gauges/derived-gauge'; import {Gauge} from './gauges/gauge'; import {Meter} from './gauges/types'; @@ -184,7 +184,7 @@ export class MetricRegistry { * MetricProducer that is used by exporters to determine the metrics that * need to be exported. */ -class MetricProducerForRegistry extends MetricProducer { +class MetricProducerForRegistry extends BaseMetricProducer { private registeredMetrics: Map; constructor(registeredMetrics: Map) { diff --git a/packages/opencensus-core/src/metrics/metrics.ts b/packages/opencensus-core/src/metrics/metrics.ts index 6f0e33f54..d5284b33f 100644 --- a/packages/opencensus-core/src/metrics/metrics.ts +++ b/packages/opencensus-core/src/metrics/metrics.ts @@ -14,21 +14,24 @@ * limitations under the License. */ +import {metricProducerManagerInstance} from './export/metric-producer-manager'; +import {MetricProducerManager} from './export/types'; +import {MetricsComponent} from './metric-component'; import {MetricRegistry} from './metric-registry'; +/** + * Class for accessing the default MetricsComponent. + */ export class Metrics { - private static readonly METRIC_REGISTRY = Metrics.newMetricRegistry(); + private static readonly METRIC_COMPONENT = new MetricsComponent(); - /** - * Returns the global MetricRegistry. - * - * @return {MetricRegistry}. - */ - static getMetricRegistry(): MetricRegistry { - return Metrics.METRIC_REGISTRY; + /** @return {MetricProducerManager} The global MetricProducerManager. */ + static getMetricProducerManager(): MetricProducerManager { + return metricProducerManagerInstance; } - private static newMetricRegistry(): MetricRegistry { - return new MetricRegistry(); + /** @return {MetricRegistry} The global MetricRegistry. */ + static getMetricRegistry(): MetricRegistry { + return Metrics.METRIC_COMPONENT.getMetricRegistry(); } } diff --git a/packages/opencensus-core/src/stats/metric-producer.ts b/packages/opencensus-core/src/stats/metric-producer.ts index 3aed75a4c..2d539db83 100644 --- a/packages/opencensus-core/src/stats/metric-producer.ts +++ b/packages/opencensus-core/src/stats/metric-producer.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import {MetricProducer} from '../metrics/export/metric-producer'; +import {BaseMetricProducer} from '../metrics/export/base-metric-producer'; import {Metric} from '../metrics/export/types'; import {Stats} from './stats'; @@ -23,7 +23,7 @@ import {Stats} from './stats'; * A MetricProducer producer that can be registered for exporting using * MetricProducerManager. */ -export class MetricProducerForStats extends MetricProducer { +export class MetricProducerForStats extends BaseMetricProducer { private statsManager: Stats; /** diff --git a/packages/opencensus-core/src/stats/stats.ts b/packages/opencensus-core/src/stats/stats.ts index 89826c26e..686b2b955 100644 --- a/packages/opencensus-core/src/stats/stats.ts +++ b/packages/opencensus-core/src/stats/stats.ts @@ -36,6 +36,14 @@ export class Stats { */ constructor(logger = defaultLogger) { this.logger = logger.logger(); + + // TODO (mayurkale): Decide how to inject MetricProducerForStats. + // It should be something like below, but looks like not the right place. + + // Create a new MetricProducerForStats and register it to + // MetricProducerManager when Stats is initialized. + // const metricProducer: MetricProducer = new MetricProducerForStats(this); + // Metrics.getMetricProducerManager().add(metricProducer); } /** diff --git a/packages/opencensus-core/test/test-metric-component.ts b/packages/opencensus-core/test/test-metric-component.ts new file mode 100644 index 000000000..4e47f5138 --- /dev/null +++ b/packages/opencensus-core/test/test-metric-component.ts @@ -0,0 +1,34 @@ +/** + * Copyright 2019, OpenCensus 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 + * + * http://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 * as assert from 'assert'; +import {metricProducerManagerInstance} from '../src/metrics/export/metric-producer-manager'; +import {MetricsComponent} from '../src/metrics/metric-component'; +import {MetricRegistry} from '../src/metrics/metric-registry'; + +describe('MetricsComponent()', () => { + const metricsComponent: MetricsComponent = new MetricsComponent(); + + it('should return a MetricRegistry instance', () => { + assert.ok(metricsComponent.getMetricRegistry() instanceof MetricRegistry); + }); + + it('should register metricRegistry to MetricProducerManger', () => { + assert.equal(metricProducerManagerInstance.getAllMetricProducer().size, 1); + assert.ok(metricProducerManagerInstance.getAllMetricProducer().has( + metricsComponent.getMetricRegistry().getMetricProducer())); + }); +}); diff --git a/packages/opencensus-core/test/test-metric-producer-manager.ts b/packages/opencensus-core/test/test-metric-producer-manager.ts new file mode 100644 index 000000000..26a7a43a0 --- /dev/null +++ b/packages/opencensus-core/test/test-metric-producer-manager.ts @@ -0,0 +1,91 @@ +/** + * Copyright 2019, OpenCensus 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 + * + * http://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 * as assert from 'assert'; +import {metricProducerManagerInstance} from '../src/metrics/export/metric-producer-manager'; +import {MetricRegistry} from '../src/metrics/metric-registry'; + +describe('MetricProducerManager()', () => { + const registry: MetricRegistry = new MetricRegistry(); + const metricProducer = registry.getMetricProducer(); + const registryOther: MetricRegistry = new MetricRegistry(); + const metricProducerOther = registryOther.getMetricProducer(); + + beforeEach(() => { + metricProducerManagerInstance.removeAll(); + }); + + describe('add()', () => { + it('should throw an error when the metricproducer is null', () => { + assert.throws(() => { + metricProducerManagerInstance.add(null); + }, /^Error: Missing mandatory metricProducer parameter$/); + }); + + it('add metricproducer', () => { + metricProducerManagerInstance.add(metricProducer); + const metricProducerList = + metricProducerManagerInstance.getAllMetricProducer(); + + assert.notDeepEqual(metricProducerList, null); + assert.equal(metricProducerList.size, 1); + }); + + it('should not add same metricproducer metricProducerManagerInstance', + () => { + metricProducerManagerInstance.add(metricProducer); + metricProducerManagerInstance.add(metricProducer); + metricProducerManagerInstance.add(metricProducer); + const metricProducerList = + metricProducerManagerInstance.getAllMetricProducer(); + + assert.equal(metricProducerList.size, 1); + assert.ok(metricProducerList.has(metricProducer)); + }); + + it('should add different metricproducer metricProducerManagerInstance', + () => { + metricProducerManagerInstance.add(metricProducer); + metricProducerManagerInstance.add(metricProducerOther); + const metricProducerList = + metricProducerManagerInstance.getAllMetricProducer(); + + assert.equal(metricProducerList.size, 2); + assert.ok(metricProducerList.has(metricProducer)); + assert.ok(metricProducerList.has(metricProducerOther)); + }); + }); + + describe('remove()', () => { + it('should throw an error when the metricproducer is null', () => { + assert.throws(() => { + metricProducerManagerInstance.add(null); + }, /^Error: Missing mandatory metricProducer parameter$/); + }); + + it('remove metricproducer', () => { + metricProducerManagerInstance.add(metricProducer); + + const metricProducerList = + metricProducerManagerInstance.getAllMetricProducer(); + assert.equal(metricProducerList.size, 1); + assert.ok(metricProducerList.has(metricProducer)); + + metricProducerManagerInstance.remove(metricProducer); + assert.equal(metricProducerList.size, 0); + }); + }); +});