From 8e3d5aa80a165b05d9217835e9acf6a8541a138b Mon Sep 17 00:00:00 2001 From: Mayur Kale Date: Tue, 22 Jan 2019 15:30:32 -0800 Subject: [PATCH] Make Stats singleton (globalStats), separate registerView from createView (#291) * Make Stats singleton (globalStats), separate registerView from createView * fix tests * remove type annotation and redundant comment --- CHANGELOG.md | 24 +++- packages/opencensus-core/src/index.ts | 8 +- .../src/stats/metric-producer.ts | 2 +- packages/opencensus-core/src/stats/stats.ts | 40 +++--- packages/opencensus-core/src/stats/types.ts | 68 ++++++++++ .../test/test-metric-producer.ts | 20 +-- packages/opencensus-core/test/test-stats.ts | 53 ++++---- .../test/test-prometheus-stats.ts | 76 +++++------ .../test/test-stackdriver-monitoring.ts | 7 +- .../test/test-zpages.ts | 119 ++++++++++-------- 10 files changed, 279 insertions(+), 138 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8459b3170..9c6a28e24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,31 @@ All notable changes to this project will be documented in this file. - Add ignoreIncomingPaths and ignoreOutgoingUrls support to the http and https tracing instrumentations. - Add ```opencensus-resource-util``` to auto detect AWS, GCE and Kubernetes(K8S) monitored resource, based on the environment where the application is running. - **Contains API breaking changes for trace implementations** + **This release has multiple breaking changes. Please test your code accordingly after upgrading.** - Modify `Logger` interface: `level` made optional, `silly` removed. +- The ```new Stats()``` has been deprecated on Stats class. The global singleton ```globalStats``` object should be used instead. Also, ```registerView()``` is separated out from ```createView()```. + +##### Old code +```js +const { Stats } = require("@opencensus/core"); +const stats = new Stats(); + +// Create and register the view +stats.createView(...); +``` + +##### New code +```js +// Get the global singleton stats object +const { globalStats } = require("@opencensus/core"); + +// Create the view +const view = globalStats.createView(...); + +// register the view +globalStats.registerView(view); +``` ## 0.0.8 - 2018-12-14 **Contains API breaking changes for stats/metrics implementations** diff --git a/packages/opencensus-core/src/index.ts b/packages/opencensus-core/src/index.ts index 635b84585..90fc23a6c 100644 --- a/packages/opencensus-core/src/index.ts +++ b/packages/opencensus-core/src/index.ts @@ -66,7 +66,6 @@ export * from './exporters/console-exporter'; // STATS CLASSES // classes -export * from './stats/stats'; export * from './stats/view'; export * from './stats/recorder'; export * from './stats/bucket-boundaries'; @@ -94,3 +93,10 @@ export * from './metrics/metric-registry'; // GAUGES CLASSES export * from './metrics/gauges/derived-gauge'; export * from './metrics/gauges/gauge'; + + +// Stats singleton instance +import {BaseStats} from './stats/stats'; +import {Stats} from './stats/types'; +const globalStats: Stats = BaseStats.instance; +export {globalStats}; diff --git a/packages/opencensus-core/src/stats/metric-producer.ts b/packages/opencensus-core/src/stats/metric-producer.ts index 2d539db83..5be26c5b2 100644 --- a/packages/opencensus-core/src/stats/metric-producer.ts +++ b/packages/opencensus-core/src/stats/metric-producer.ts @@ -17,7 +17,7 @@ import {BaseMetricProducer} from '../metrics/export/base-metric-producer'; import {Metric} from '../metrics/export/types'; -import {Stats} from './stats'; +import {Stats} from './types'; /** * A MetricProducer producer that can be registered for exporting using diff --git a/packages/opencensus-core/src/stats/stats.ts b/packages/opencensus-core/src/stats/stats.ts index e1338ed36..bd5d8b6d7 100644 --- a/packages/opencensus-core/src/stats/stats.ts +++ b/packages/opencensus-core/src/stats/stats.ts @@ -18,17 +18,21 @@ import * as defaultLogger from '../common/console-logger'; import * as loggerTypes from '../common/types'; import {StatsEventListener} from '../exporters/types'; import {Metric} from '../metrics/export/types'; +import {Metrics} from '../metrics/metrics'; -import {AggregationType, Measure, Measurement, MeasureType, MeasureUnit, View} from './types'; +import {MetricProducerForStats} from './metric-producer'; +import {AggregationType, Measure, Measurement, MeasureType, MeasureUnit, Stats, View} from './types'; import {BaseView} from './view'; -export class Stats { +export class BaseStats implements Stats { /** A list of Stats exporters */ private statsEventListeners: StatsEventListener[] = []; /** A map of Measures (name) to their corresponding Views */ private registeredViews: {[key: string]: View[]} = {}; /** An object to log information to */ private logger: loggerTypes.Logger; + /** Singleton instance */ + private static singletonInstance: BaseStats; /** * Creates stats @@ -37,21 +41,22 @@ 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); + const metricProducer = new MetricProducerForStats(this); + Metrics.getMetricProducerManager().add(metricProducer); + } + + /** Gets the stats instance. */ + static get instance(): Stats { + return this.singletonInstance || (this.singletonInstance = new this()); } /** - * Registers a view to listen to new measurements in its measure. Prefer using - * the method createView() that creates an already registered view. + * Registers a view to listen to new measurements in its measure. * @param view The view to be registered */ - registerView(view: View) { + registerView(view: View): void { if (this.registeredViews[view.measure.name]) { this.registeredViews[view.measure.name].push(view); } else { @@ -67,7 +72,7 @@ export class Stats { } /** - * Creates and registers a view. + * Creates a view. * @param name The view name * @param measure The view measure * @param aggregation The view aggregation type @@ -82,7 +87,6 @@ export class Stats { bucketBoundaries?: number[]): View { const view = new BaseView( name, measure, aggregation, tagKeys, description, bucketBoundaries); - this.registerView(view); return view; } @@ -90,7 +94,7 @@ export class Stats { * Registers an exporter to send stats data to a service. * @param exporter An stats exporter */ - registerExporter(exporter: StatsEventListener) { + registerExporter(exporter: StatsEventListener): void { this.statsEventListeners.push(exporter); for (const measureName of Object.keys(this.registeredViews)) { @@ -153,7 +157,7 @@ export class Stats { * Updates all views with the new measurements. * @param measurements A list of measurements to record */ - record(...measurements: Measurement[]) { + record(...measurements: Measurement[]): void { if (this.hasNegativeValue(measurements)) { this.logger.warn(`Dropping measurments ${measurements}, value to record must be non-negative.`); @@ -176,4 +180,12 @@ export class Stats { } } } + + /** + * Remove all registered Views and exporters from the stats. + */ + clear(): void { + this.registeredViews = {}; + this.statsEventListeners = []; + } } diff --git a/packages/opencensus-core/src/stats/types.ts b/packages/opencensus-core/src/stats/types.ts index c3f837c93..2a994fb35 100644 --- a/packages/opencensus-core/src/stats/types.ts +++ b/packages/opencensus-core/src/stats/types.ts @@ -14,8 +14,76 @@ * limitations under the License. */ +import {StatsEventListener} from '../exporters/types'; import {Metric} from '../metrics/export/types'; +/** Main interface for stats. */ +export interface Stats { + /** + * Creates a view. + * @param name The view name + * @param measure The view measure + * @param aggregation The view aggregation type + * @param tagKeys The view columns (tag keys) + * @param description The view description + * @param bucketBoundaries The view bucket boundaries for a distribution + * aggregation type + */ + createView( + name: string, measure: Measure, aggregation: AggregationType, + tagKeys: string[], description: string, + bucketBoundaries?: number[]): View; + + /** + * Registers a view to listen to new measurements in its measure. + * @param view The view to be registered + */ + registerView(view: View): void; + + /** + * Creates a measure of type Double. + * @param name The measure name + * @param unit The measure unit + * @param description The measure description + */ + createMeasureDouble(name: string, unit: MeasureUnit, description?: string): + Measure; + + /** + * Creates a measure of type Int64. Values must be integers up to + * Number.MAX_SAFE_INTERGER. + * @param name The measure name + * @param unit The measure unit + * @param description The measure description + */ + createMeasureInt64(name: string, unit: MeasureUnit, description?: string): + Measure; + + /** + * Updates all views with the new measurements. + * @param measurements A list of measurements to record + */ + record(...measurements: Measurement[]): void; + + /** + * Remove all registered Views and exporters from the stats. + */ + clear(): void; + + /** + * Gets a collection of produced Metric`s to be exported. + * @returns {Metric[]} List of metrics + */ + getMetrics(): Metric[]; + + /** + * Registers an exporter to send stats data to a service. + * @param exporter An stats exporter + */ + registerExporter(exporter: StatsEventListener): void; +} + + /** Tags are maps of names -> values */ export interface Tags { [key: string]: string; diff --git a/packages/opencensus-core/test/test-metric-producer.ts b/packages/opencensus-core/test/test-metric-producer.ts index d5a354e35..27c9d56c6 100644 --- a/packages/opencensus-core/test/test-metric-producer.ts +++ b/packages/opencensus-core/test/test-metric-producer.ts @@ -15,13 +15,13 @@ */ import * as assert from 'assert'; -import {AggregationType, Measurement, MeasureUnit, Stats, Tags, View} from '../src'; + +import {AggregationType, globalStats, Measurement, MeasureUnit, Tags, View} from '../src'; import {LabelKey, LabelValue, MetricDescriptorType} from '../src/metrics/export/types'; import {MetricProducerForStats} from '../src/stats/metric-producer'; describe('Metric producer for stats', () => { - const stats = new Stats(); - const metricProducerForStats = new MetricProducerForStats(stats); + const metricProducerForStats = new MetricProducerForStats(globalStats); // constants for view name const viewName1 = 'test/view/name1'; @@ -29,7 +29,7 @@ describe('Metric producer for stats', () => { const viewName3 = 'test/view/name2'; const description = 'test description'; - const measureDouble = stats.createMeasureDouble( + const measureDouble = globalStats.createMeasureDouble( 'opencensus.io/test/double', MeasureUnit.UNIT, 'Measure Double'); const tags: Tags = {testKey1: 'testValue1', testKey2: 'testValue2'}; const labelKeys: LabelKey[] = [ @@ -72,9 +72,10 @@ describe('Metric producer for stats', () => { }; it('should add sum stats', () => { - const view: View = stats.createView( + const view: View = globalStats.createView( viewName1, measureDouble, AggregationType.SUM, Object.keys(tags), description); + globalStats.registerView(view); view.recordMeasurement(measurement1); const metrics = metricProducerForStats.getMetrics(); @@ -92,9 +93,10 @@ describe('Metric producer for stats', () => { it('should add count stats', () => { - const view: View = stats.createView( + const view: View = globalStats.createView( viewName2, measureDouble, AggregationType.COUNT, Object.keys(tags), description); + globalStats.registerView(view); view.recordMeasurement(measurement1); let metrics = metricProducerForStats.getMetrics(); @@ -122,9 +124,10 @@ describe('Metric producer for stats', () => { }); it('should add lastValue stats', () => { - const view: View = stats.createView( + const view: View = globalStats.createView( viewName3, measureDouble, AggregationType.LAST_VALUE, Object.keys(tags), description); + globalStats.registerView(view); view.recordMeasurement(measurement1); view.recordMeasurement(measurement2); @@ -153,9 +156,10 @@ describe('Metric producer for stats', () => { const measurementValues = [1.1, 2.3, 3.2, 4.3, 5.2]; const buckets = [2, 4, 6]; - const view: View = stats.createView( + const view: View = globalStats.createView( viewName3, measureDouble, AggregationType.DISTRIBUTION, Object.keys(tags), description, buckets); + globalStats.registerView(view); for (const value of measurementValues) { const measurement: Measurement = {measure: measureDouble, value, tags}; view.recordMeasurement(measurement); diff --git a/packages/opencensus-core/test/test-stats.ts b/packages/opencensus-core/test/test-stats.ts index f96004224..d9c563d56 100644 --- a/packages/opencensus-core/test/test-stats.ts +++ b/packages/opencensus-core/test/test-stats.ts @@ -15,7 +15,7 @@ */ import * as assert from 'assert'; -import {BaseView, Stats, StatsEventListener} from '../src'; +import {BaseView, globalStats, StatsEventListener} from '../src'; import {AggregationType, LastValueData, Measure, Measurement, MeasureType, MeasureUnit, View} from '../src/stats/types'; class TestExporter implements StatsEventListener { @@ -41,10 +41,8 @@ class TestExporter implements StatsEventListener { } describe('Stats', () => { - let stats: Stats; - - beforeEach(() => { - stats = new Stats(); + afterEach(() => { + globalStats.clear(); }); const viewName = 'testViewName'; @@ -56,8 +54,8 @@ describe('Stats', () => { describe('createMeasureDouble()', () => { it('should create a measure of type double', () => { - const measureDouble = - stats.createMeasureDouble(measureName, measureUnit, description); + const measureDouble = globalStats.createMeasureDouble( + measureName, measureUnit, description); assert.strictEqual(measureDouble.type, MeasureType.DOUBLE); assert.strictEqual(measureDouble.name, measureName); assert.strictEqual(measureDouble.unit, measureUnit); @@ -68,7 +66,7 @@ describe('Stats', () => { describe('createMeasureInt64()', () => { it('should create a measure of type int64', () => { const measureDouble = - stats.createMeasureInt64(measureName, measureUnit, description); + globalStats.createMeasureInt64(measureName, measureUnit, description); assert.strictEqual(measureDouble.type, MeasureType.INT64); assert.strictEqual(measureDouble.name, measureName); assert.strictEqual(measureDouble.unit, measureUnit); @@ -84,16 +82,21 @@ describe('Stats', () => { let measure: Measure; before(() => { - measure = stats.createMeasureInt64(measureName, measureUnit); + measure = globalStats.createMeasureInt64(measureName, measureUnit); + }); + + after(() => { + globalStats.clear(); }); for (const aggregationType of aggregationTypes) { it(`should create a view with ${aggregationType} aggregation`, () => { const bucketBoundaries = AggregationType.DISTRIBUTION ? [1, 2, 3] : null; - const view = stats.createView( + const view = globalStats.createView( viewName, measure, aggregationType, tagKeys, description, bucketBoundaries); + globalStats.registerView(view); assert.strictEqual(view.name, viewName); assert.strictEqual(view.measure, measure); @@ -106,7 +109,7 @@ describe('Stats', () => { it('should not create a view with distribution aggregation when no bucket boundaries were given', () => { - assert.throws(stats.createView, 'No bucketBoundaries specified'); + assert.throws(globalStats.createView, 'No bucketBoundaries specified'); }); }); @@ -115,18 +118,19 @@ describe('Stats', () => { const testExporter = new TestExporter(); before(() => { - measure = stats.createMeasureInt64(measureName, measureUnit); + testExporter.clean(); + measure = globalStats.createMeasureInt64(measureName, measureUnit); }); it('should register a view', () => { - stats.registerExporter(testExporter); + globalStats.registerExporter(testExporter); const view = new BaseView( viewName, measure, AggregationType.LAST_VALUE, tagKeys, description); assert.ok(!view.registered); assert.strictEqual(testExporter.registeredViews.length, 0); - stats.registerView(view); + globalStats.registerView(view); assert.ok(view.registered); assert.strictEqual(testExporter.registeredViews.length, 1); @@ -139,20 +143,25 @@ describe('Stats', () => { const testExporter = new TestExporter(); let aggregationData: LastValueData; before(() => { - measure = stats.createMeasureInt64(measureName, measureUnit); + measure = globalStats.createMeasureInt64(measureName, measureUnit); }); beforeEach(() => { testExporter.clean(); - stats.registerExporter(testExporter); - stats.createView( + globalStats.registerExporter(testExporter); + const view = globalStats.createView( viewName, measure, AggregationType.LAST_VALUE, tagKeys, description); + globalStats.registerView(view); + }); + + afterEach(() => { + globalStats.clear(); }); it('should record a single measurement', () => { const measurement = {measure, tags, value: 1}; assert.strictEqual(testExporter.recordedMeasurements.length, 0); - stats.record(measurement); + globalStats.record(measurement); assert.strictEqual(testExporter.recordedMeasurements.length, 1); assert.deepEqual(testExporter.recordedMeasurements[0], measurement); aggregationData = @@ -161,9 +170,9 @@ describe('Stats', () => { }); it('should not record a single negative measurement', () => { - stats.registerExporter(testExporter); + globalStats.registerExporter(testExporter); const measurement = {measure, tags, value: -1}; - stats.record(measurement); + globalStats.record(measurement); assert.strictEqual(testExporter.recordedMeasurements.length, 0); }); @@ -171,7 +180,7 @@ describe('Stats', () => { const measurement1 = {measure, tags, value: 1}; const measurement2 = {measure, tags, value: 1}; assert.strictEqual(testExporter.recordedMeasurements.length, 0); - stats.record(measurement1, measurement2); + globalStats.record(measurement1, measurement2); assert.strictEqual(testExporter.recordedMeasurements.length, 2); assert.deepEqual(testExporter.recordedMeasurements[0], measurement1); assert.deepEqual(testExporter.recordedMeasurements[1], measurement2); @@ -186,7 +195,7 @@ describe('Stats', () => { {measure, tags, value: 1}, {measure, tags, value: -1}, {measure, tags, value: 1} ]; - stats.record(...measurments); + globalStats.record(...measurments); assert.equal(testExporter.recordedMeasurements.length, 0); }); }); diff --git a/packages/opencensus-exporter-prometheus/test/test-prometheus-stats.ts b/packages/opencensus-exporter-prometheus/test/test-prometheus-stats.ts index b708dc9b8..8ca1fa010 100644 --- a/packages/opencensus-exporter-prometheus/test/test-prometheus-stats.ts +++ b/packages/opencensus-exporter-prometheus/test/test-prometheus-stats.ts @@ -14,9 +14,10 @@ * limitations under the License. */ -import {AggregationType, Measure, MeasureUnit, Stats} from '@opencensus/core'; +import {AggregationType, globalStats, Measure, MeasureUnit} from '@opencensus/core'; import * as assert from 'assert'; import * as http from 'http'; + import {PrometheusStatsExporter} from '../src/'; describe('Prometheus Stats Exporter', () => { @@ -26,23 +27,28 @@ describe('Prometheus Stats Exporter', () => { const tagKeys = Object.keys(tags); let exporter: PrometheusStatsExporter; let measure: Measure; - let stats: Stats; beforeEach((done) => { - stats = new Stats(); - measure = stats.createMeasureDouble('testMeasureDouble', MeasureUnit.UNIT); + measure = + globalStats.createMeasureDouble('testMeasureDouble', MeasureUnit.UNIT); exporter = new PrometheusStatsExporter(options); - stats.registerExporter(exporter); + globalStats.registerExporter(exporter); exporter.startServer(done); }); + afterEach((done) => { + exporter.stopServer(done); + globalStats.clear(); + }); + it('should create a count aggregation', (done) => { - stats.createView( + const view = globalStats.createView( 'ocnodemetrics/countview', measure, AggregationType.COUNT, tagKeys, 'A count aggregation example', null); const measurement = {measure, tags, value: 2}; const measurement2 = {measure, tags, value: 3}; - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); http.get(prometheusServerUrl, (res) => { res.on('data', (chunk) => { @@ -62,15 +68,16 @@ describe('Prometheus Stats Exporter', () => { it('should create a sum aggregation', (done) => { const measure = - stats.createMeasureDouble('testMeasureDouble', MeasureUnit.UNIT); + globalStats.createMeasureDouble('testMeasureDouble', MeasureUnit.UNIT); const tags = {tagKey1: 'tagValue1'}; const tagKeys = Object.keys(tags); - stats.createView( + const view = globalStats.createView( 'ocnodemetrics/sumview', measure, AggregationType.SUM, tagKeys, 'A sum aggregation example', null); const measurement = {measure, tags, value: 2}; const measurement2 = {measure, tags, value: 3}; - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); http.get(prometheusServerUrl, (res) => { res.on('data', (chunk) => { @@ -90,15 +97,16 @@ describe('Prometheus Stats Exporter', () => { it('should create a last value aggregation', (done) => { const measure = - stats.createMeasureDouble('testMeasureDouble', MeasureUnit.UNIT); + globalStats.createMeasureDouble('testMeasureDouble', MeasureUnit.UNIT); const tags = {tagKey1: 'tagValue1'}; const tagKeys = Object.keys(tags); - stats.createView( + const view = globalStats.createView( 'ocnodemetrics/lastvalueview', measure, AggregationType.LAST_VALUE, tagKeys, 'A last value aggregation example', null); const measurement = {measure, tags, value: 2}; const measurement2 = {measure, tags, value: 3}; - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); http.get(prometheusServerUrl, (res) => { res.on('data', (chunk) => { @@ -118,16 +126,17 @@ describe('Prometheus Stats Exporter', () => { it('should create a distribution aggregation', (done) => { const measure = - stats.createMeasureDouble('testMeasureDouble', MeasureUnit.UNIT); + globalStats.createMeasureDouble('testMeasureDouble', MeasureUnit.UNIT); const tags = {tagKey1: 'tagValue1'}; const tagKeys = Object.keys(tags); const boundaries = [10, 20, 30, 40]; - stats.createView( + const view = globalStats.createView( 'ocnodemetrics/distributionview', measure, AggregationType.DISTRIBUTION, tagKeys, 'A distribution aggregation example', boundaries); const measurement = {measure, tags, value: 12}; const measurement2 = {measure, tags, value: 31}; - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); http.get(prometheusServerUrl, (res) => { res.on('data', (chunk) => { @@ -166,26 +175,22 @@ describe('Prometheus Stats Exporter', () => { it('should throw error when labels contains "le" label name in histogram label names', () => { - const measure = - stats.createMeasureDouble('testMeasureDouble', MeasureUnit.UNIT); + const measure = globalStats.createMeasureDouble( + 'testMeasureDouble', MeasureUnit.UNIT); const tags = {le: 'tagValue1'}; const tagKeys = Object.keys(tags); const boundaries = [10, 20, 30, 40]; - stats.createView( + const view = globalStats.createView( 'ocnodemetrics/distributionview1', measure, AggregationType.DISTRIBUTION, tagKeys, 'A distribution aggregation example', boundaries); - + globalStats.registerView(view); const measurement = {measure, tags, value: 2}; assert.throws(() => { - stats.record(measurement); + globalStats.record(measurement); }, /^Error: le is a reserved label keyword$/); }); - - afterEach((done) => { - exporter.stopServer(done); - }); }); describe('Prometheus Stats Exporter with prefix option', () => { @@ -195,23 +200,28 @@ describe('Prometheus Stats Exporter with prefix option', () => { const tagKeys = Object.keys(tags); let exporter: PrometheusStatsExporter; let measure: Measure; - let stats: Stats; beforeEach((done) => { - stats = new Stats(); - measure = stats.createMeasureDouble('testMeasureDouble', MeasureUnit.UNIT); + measure = + globalStats.createMeasureDouble('testMeasureDouble', MeasureUnit.UNIT); exporter = new PrometheusStatsExporter(options); - stats.registerExporter(exporter); + globalStats.registerExporter(exporter); exporter.startServer(done); }); + afterEach((done) => { + exporter.stopServer(done); + globalStats.clear(); + }); + it('should create a count aggregation with le labels', (done) => { - stats.createView( + const view = globalStats.createView( 'test/key-1', measure, AggregationType.COUNT, tagKeys, 'A count aggregation example', null); const measurement = {measure, tags, value: 2}; const measurement2 = {measure, tags, value: 3}; - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); http.get(prometheusServerUrl, (res) => { res.on('data', (chunk) => { @@ -227,8 +237,4 @@ describe('Prometheus Stats Exporter with prefix option', () => { }); }).on('error', done); }); - - afterEach((done) => { - exporter.stopServer(done); - }); }); diff --git a/packages/opencensus-exporter-stackdriver/test/test-stackdriver-monitoring.ts b/packages/opencensus-exporter-stackdriver/test/test-stackdriver-monitoring.ts index 5a3f24f63..345e993d3 100644 --- a/packages/opencensus-exporter-stackdriver/test/test-stackdriver-monitoring.ts +++ b/packages/opencensus-exporter-stackdriver/test/test-stackdriver-monitoring.ts @@ -14,11 +14,12 @@ * limitations under the License. */ -import {LabelKey, Logger, MeasureUnit, Metrics, Stats} from '@opencensus/core'; +import {globalStats, LabelKey, Logger, MeasureUnit, Metrics} from '@opencensus/core'; import * as assert from 'assert'; import {StackdriverStatsExporter} from '../src/stackdriver-monitoring'; import {MetricKind, StackdriverExporterOptions, ValueType} from '../src/types'; + import * as nocks from './nocks'; const PROJECT_ID = 'fake-project-id'; @@ -58,7 +59,6 @@ describe('Stackdriver Stats Exporter', () => { }); describe('Send data to Stackdriver', () => { - const stats = new Stats(); const mockLogger = new MockLogger(); let exporterOptions: StackdriverExporterOptions; let exporter: StackdriverStatsExporter; @@ -73,10 +73,11 @@ describe('Stackdriver Stats Exporter', () => { afterEach(() => { exporter.close(); mockLogger.cleanAll(); + globalStats.clear(); }); it('should not export for empty data', () => { - stats.registerExporter(exporter); + globalStats.registerExporter(exporter); assert.equal(mockLogger.debugBuffer.length, 0); }); diff --git a/packages/opencensus-exporter-zpages/test/test-zpages.ts b/packages/opencensus-exporter-zpages/test/test-zpages.ts index c334f64aa..ecc36b890 100644 --- a/packages/opencensus-exporter-zpages/test/test-zpages.ts +++ b/packages/opencensus-exporter-zpages/test/test-zpages.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import {AggregationType, CountData, DistributionData, Measure, Measurement, MeasureUnit, RootSpan, Stats, SumData, Tags, TracerConfig} from '@opencensus/core'; +import {AggregationType, CountData, DistributionData, globalStats, Measure, Measurement, MeasureUnit, RootSpan, SumData, Tags, TracerConfig} from '@opencensus/core'; import * as assert from 'assert'; import axios from 'axios'; import * as http from 'http'; @@ -243,17 +243,15 @@ describe('Zpages Exporter', () => { return tags[tagKey]; }); let zpages: ZpagesExporter; - let stats: Stats; let measure: Measure; let zpagesData: StatsViewData; let measurement: Measurement; let measurement2: Measurement; beforeEach((done) => { - stats = new Stats(); zpages = new ZpagesExporter(options); - stats.registerExporter(zpages); - measure = stats.createMeasureDouble( + globalStats.registerExporter(zpages); + measure = globalStats.createMeasureDouble( 'testMeasureDouble', MeasureUnit.UNIT, 'A test measure'); measurement = {measure, tags, value: 22}; measurement2 = {measure, tags, value: 11}; @@ -262,14 +260,16 @@ describe('Zpages Exporter', () => { afterEach((done) => { zpages.stopServer(done); + globalStats.clear(); }); describe('with COUNT aggregation type', () => { it('should get view information', async () => { - stats.createView( + const view = globalStats.createView( 'test/CountView', measure, AggregationType.COUNT, tagKeys, 'A count test', null); - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); zpagesData = await zpagesClient.getStatsz({path: 'test/CountView'}); @@ -280,10 +280,11 @@ describe('Zpages Exporter', () => { }); it('should get stats for view', async () => { - stats.createView( + const view = globalStats.createView( 'test/CountView', measure, AggregationType.COUNT, tagKeys, 'A count test', null); - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); zpagesData = await zpagesClient.getStatsz({path: 'test/CountView'}); @@ -299,11 +300,12 @@ describe('Zpages Exporter', () => { describe('with SUM aggregation type', () => { it('should get view information', async () => { - stats.registerExporter(zpages); - stats.createView( + globalStats.registerExporter(zpages); + const view = globalStats.createView( 'test/SumView', measure, AggregationType.SUM, tagKeys, 'A sum test', null); - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); zpagesData = await zpagesClient.getStatsz({path: 'test/SumView'}); @@ -314,12 +316,12 @@ describe('Zpages Exporter', () => { }); it('should get stats for view', async () => { - stats.registerExporter(zpages); - stats.createView( + globalStats.registerExporter(zpages); + const view = globalStats.createView( 'test/SumView', measure, AggregationType.SUM, tagKeys, 'A sum test', null); - - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); zpagesData = await zpagesClient.getStatsz({path: 'test/SumView'}); @@ -335,11 +337,12 @@ describe('Zpages Exporter', () => { describe('with LAST VALUE aggregation type', () => { it('should get view information', async () => { - stats.registerExporter(zpages); - stats.createView( + globalStats.registerExporter(zpages); + const view = globalStats.createView( 'test/LastValueView', measure, AggregationType.LAST_VALUE, tagKeys, 'A last value test', null); - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); zpagesData = await zpagesClient.getStatsz({path: 'test/LastValueView'}); @@ -350,12 +353,12 @@ describe('Zpages Exporter', () => { }); it('should get stats for view', async () => { - stats.registerExporter(zpages); - stats.createView( + globalStats.registerExporter(zpages); + const view = globalStats.createView( 'test/LastValueView', measure, AggregationType.LAST_VALUE, tagKeys, 'A last value test', null); - - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); zpagesData = await zpagesClient.getStatsz({path: 'test/LastValueView'}); @@ -372,11 +375,12 @@ describe('Zpages Exporter', () => { describe('with DISTRIBUTION aggregation type', () => { it('should get view information', async () => { const boundaries = [10, 20, 30, 40]; - stats.registerExporter(zpages); - stats.createView( + globalStats.registerExporter(zpages); + const view = globalStats.createView( 'test/DistributionView', measure, AggregationType.DISTRIBUTION, tagKeys, 'A distribution test', boundaries); - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); zpagesData = await zpagesClient.getStatsz({path: 'test/DistributionView'}); @@ -389,12 +393,12 @@ describe('Zpages Exporter', () => { it('should get stats for view', async () => { const boundaries = [10, 20, 30, 40]; - stats.registerExporter(zpages); - stats.createView( + globalStats.registerExporter(zpages); + const view = globalStats.createView( 'test/DistributionView', measure, AggregationType.DISTRIBUTION, tagKeys, 'A distribution test', boundaries); - - stats.record(measurement, measurement2); + globalStats.registerView(view); + globalStats.record(measurement, measurement2); zpagesData = await zpagesClient.getStatsz({path: 'test/DistributionView'}); @@ -414,19 +418,18 @@ describe('Zpages Exporter', () => { describe('when a view is accessed in rpcz page', () => { let zpages: ZpagesExporter; - let stats: Stats; let rpczData: RpczData; const boundaries = [10, 20, 30, 40]; beforeEach((done) => { - stats = new Stats(); zpages = new ZpagesExporter(options); - stats.registerExporter(zpages); + globalStats.registerExporter(zpages); zpages.startServer(done); }); afterEach((done) => { zpages.stopServer(done); + globalStats.clear(); }); it('should get the sent stats', async () => { @@ -437,44 +440,49 @@ describe('Zpages Exporter', () => { }; const tagKeys = Object.keys(tags); - const measure = stats.createMeasureDouble( + const measure = globalStats.createMeasureDouble( 'grpc.io/client/sent_bytes_per_rpc', MeasureUnit.BYTE, 'Total bytes sent across all request messages per RPC'); - const measure2 = stats.createMeasureDouble( + const measure2 = globalStats.createMeasureDouble( 'grpc.io/client/received_bytes_per_rpc', MeasureUnit.BYTE, 'Total bytes received across all request messages per RPC'); - const measure3 = stats.createMeasureDouble( + const measure3 = globalStats.createMeasureDouble( 'grpc.io/client/roundtrip_latency', MeasureUnit.MS, 'Time between first byte of request sent to last byte of response received or terminal error'); - const measure4 = stats.createMeasureDouble( + const measure4 = globalStats.createMeasureDouble( 'grpc.io/client/started_rpcs', MeasureUnit.UNIT, 'Number of started client RPCs.'); - stats.createView( + const view1 = globalStats.createView( 'grpc.io/client/sent_bytes_per_rpc', measure, AggregationType.DISTRIBUTION, tagKeys, 'Sent bytes per RPC', boundaries); + globalStats.registerView(view1); - stats.createView( + const view2 = globalStats.createView( 'grpc.io/client/received_bytes_per_rpc', measure2, AggregationType.DISTRIBUTION, tagKeys, 'Sent bytes per RPC', boundaries); + globalStats.registerView(view2); - stats.createView( + const view3 = globalStats.createView( 'grpc.io/client/roundtrip_latency', measure3, AggregationType.DISTRIBUTION, tagKeys, 'Latency in msecs', boundaries); + globalStats.registerView(view3); - stats.createView( + const view4 = globalStats.createView( 'grpc.io/client/completed_rpcs', measure3, AggregationType.COUNT, tagKeys, 'Number of completed client RPCs', null); + globalStats.registerView(view4); - stats.createView( + const view5 = globalStats.createView( 'grpc.io/client/started_rpcs', measure4, AggregationType.COUNT, tagKeys, 'Number of started client RPCs', null); + globalStats.registerView(view5); const measurement = {measure, tags, value: 22000}; const measurement2 = {measure: measure2, tags, value: 1100}; @@ -482,7 +490,7 @@ describe('Zpages Exporter', () => { const measurement4 = {measure: measure3, tags: tags2, value: 2}; const measurement5 = {measure: measure4, tags, value: 2}; - stats.record( + globalStats.record( measurement, measurement2, measurement3, measurement4, measurement5); rpczData = await zpagesClient.getRpcz(); @@ -504,44 +512,49 @@ describe('Zpages Exporter', () => { const tagKeys2 = Object.keys(tags3); const boundaries = [10, 20, 30, 40]; - const measure5 = stats.createMeasureDouble( + const measure5 = globalStats.createMeasureDouble( 'grpc.io/server/received_bytes_per_rpc', MeasureUnit.BYTE, 'Total bytes sent across all request messages per RPC'); - const measure6 = stats.createMeasureDouble( + const measure6 = globalStats.createMeasureDouble( 'grpc.io/server/sent_bytes_per_rpc', MeasureUnit.BYTE, 'Total bytes received across all request messages per RPC'); - const measure7 = stats.createMeasureDouble( + const measure7 = globalStats.createMeasureDouble( 'grpc.io/server/server_latency', MeasureUnit.MS, 'Time between first byte of request sent to last byte of response received or terminal error'); - const measure8 = stats.createMeasureDouble( + const measure8 = globalStats.createMeasureDouble( 'grpc.io/server/started_rpcs', MeasureUnit.UNIT, 'Number of started client RPCs.'); - stats.createView( + const view1 = globalStats.createView( 'grpc.io/server/received_bytes_per_rpc', measure5, AggregationType.DISTRIBUTION, tagKeys2, 'Sent bytes per RPC', boundaries); + globalStats.registerView(view1); - stats.createView( + const view2 = globalStats.createView( 'grpc.io/server/sent_bytes_per_rpc', measure6, AggregationType.DISTRIBUTION, tagKeys2, 'Sent bytes per RPC', boundaries); + globalStats.registerView(view2); - stats.createView( + const view3 = globalStats.createView( 'grpc.io/server/server_latency', measure7, AggregationType.DISTRIBUTION, tagKeys2, 'Latency in msecs', boundaries); + globalStats.registerView(view3); - stats.createView( + const view4 = globalStats.createView( 'grpc.io/server/completed_rpcs', measure7, AggregationType.COUNT, tagKeys2, 'Number of completed client RPCs', null); + globalStats.registerView(view4); - stats.createView( + const view5 = globalStats.createView( 'grpc.io/server/started_rpcs', measure8, AggregationType.COUNT, tagKeys2, 'Number of started client RPCs', null); + globalStats.registerView(view5); const measurement6 = {measure: measure5, tags: tags3, value: 2200}; const measurement7 = {measure: measure6, tags: tags3, value: 1100}; @@ -549,7 +562,7 @@ describe('Zpages Exporter', () => { const measurement9 = {measure: measure7, tags: tags4, value: 2}; const measurement10 = {measure: measure8, tags: tags3, value: 2}; - stats.record( + globalStats.record( measurement6, measurement7, measurement8, measurement9, measurement10);