Skip to content
This repository was archived by the owner on Oct 3, 2023. It is now read-only.

Commit 8e3d5aa

Browse files
authored
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
1 parent 37fd034 commit 8e3d5aa

File tree

10 files changed

+279
-138
lines changed

10 files changed

+279
-138
lines changed

CHANGELOG.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,31 @@ All notable changes to this project will be documented in this file.
1010
- Add ignoreIncomingPaths and ignoreOutgoingUrls support to the http and https tracing instrumentations.
1111
- Add ```opencensus-resource-util``` to auto detect AWS, GCE and Kubernetes(K8S) monitored resource, based on the environment where the application is running.
1212

13-
**Contains API breaking changes for trace implementations**
13+
**This release has multiple breaking changes. Please test your code accordingly after upgrading.**
1414

1515
- Modify `Logger` interface: `level` made optional, `silly` removed.
16+
- 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()```.
17+
18+
##### Old code
19+
```js
20+
const { Stats } = require("@opencensus/core");
21+
const stats = new Stats();
22+
23+
// Create and register the view
24+
stats.createView(...);
25+
```
26+
27+
##### New code
28+
```js
29+
// Get the global singleton stats object
30+
const { globalStats } = require("@opencensus/core");
31+
32+
// Create the view
33+
const view = globalStats.createView(...);
34+
35+
// register the view
36+
globalStats.registerView(view);
37+
```
1638

1739
## 0.0.8 - 2018-12-14
1840
**Contains API breaking changes for stats/metrics implementations**

packages/opencensus-core/src/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ export * from './exporters/console-exporter';
6666
// STATS CLASSES
6767

6868
// classes
69-
export * from './stats/stats';
7069
export * from './stats/view';
7170
export * from './stats/recorder';
7271
export * from './stats/bucket-boundaries';
@@ -94,3 +93,10 @@ export * from './metrics/metric-registry';
9493
// GAUGES CLASSES
9594
export * from './metrics/gauges/derived-gauge';
9695
export * from './metrics/gauges/gauge';
96+
97+
98+
// Stats singleton instance
99+
import {BaseStats} from './stats/stats';
100+
import {Stats} from './stats/types';
101+
const globalStats: Stats = BaseStats.instance;
102+
export {globalStats};

packages/opencensus-core/src/stats/metric-producer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import {BaseMetricProducer} from '../metrics/export/base-metric-producer';
1818
import {Metric} from '../metrics/export/types';
1919

20-
import {Stats} from './stats';
20+
import {Stats} from './types';
2121

2222
/**
2323
* A MetricProducer producer that can be registered for exporting using

packages/opencensus-core/src/stats/stats.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,21 @@ import * as defaultLogger from '../common/console-logger';
1818
import * as loggerTypes from '../common/types';
1919
import {StatsEventListener} from '../exporters/types';
2020
import {Metric} from '../metrics/export/types';
21+
import {Metrics} from '../metrics/metrics';
2122

22-
import {AggregationType, Measure, Measurement, MeasureType, MeasureUnit, View} from './types';
23+
import {MetricProducerForStats} from './metric-producer';
24+
import {AggregationType, Measure, Measurement, MeasureType, MeasureUnit, Stats, View} from './types';
2325
import {BaseView} from './view';
2426

25-
export class Stats {
27+
export class BaseStats implements Stats {
2628
/** A list of Stats exporters */
2729
private statsEventListeners: StatsEventListener[] = [];
2830
/** A map of Measures (name) to their corresponding Views */
2931
private registeredViews: {[key: string]: View[]} = {};
3032
/** An object to log information to */
3133
private logger: loggerTypes.Logger;
34+
/** Singleton instance */
35+
private static singletonInstance: BaseStats;
3236

3337
/**
3438
* Creates stats
@@ -37,21 +41,22 @@ export class Stats {
3741
constructor(logger = defaultLogger) {
3842
this.logger = logger.logger();
3943

40-
// TODO (mayurkale): Decide how to inject MetricProducerForStats.
41-
// It should be something like below, but looks like not the right place.
42-
4344
// Create a new MetricProducerForStats and register it to
4445
// MetricProducerManager when Stats is initialized.
45-
// const metricProducer: MetricProducer = new MetricProducerForStats(this);
46-
// Metrics.getMetricProducerManager().add(metricProducer);
46+
const metricProducer = new MetricProducerForStats(this);
47+
Metrics.getMetricProducerManager().add(metricProducer);
48+
}
49+
50+
/** Gets the stats instance. */
51+
static get instance(): Stats {
52+
return this.singletonInstance || (this.singletonInstance = new this());
4753
}
4854

4955
/**
50-
* Registers a view to listen to new measurements in its measure. Prefer using
51-
* the method createView() that creates an already registered view.
56+
* Registers a view to listen to new measurements in its measure.
5257
* @param view The view to be registered
5358
*/
54-
registerView(view: View) {
59+
registerView(view: View): void {
5560
if (this.registeredViews[view.measure.name]) {
5661
this.registeredViews[view.measure.name].push(view);
5762
} else {
@@ -67,7 +72,7 @@ export class Stats {
6772
}
6873

6974
/**
70-
* Creates and registers a view.
75+
* Creates a view.
7176
* @param name The view name
7277
* @param measure The view measure
7378
* @param aggregation The view aggregation type
@@ -82,15 +87,14 @@ export class Stats {
8287
bucketBoundaries?: number[]): View {
8388
const view = new BaseView(
8489
name, measure, aggregation, tagKeys, description, bucketBoundaries);
85-
this.registerView(view);
8690
return view;
8791
}
8892

8993
/**
9094
* Registers an exporter to send stats data to a service.
9195
* @param exporter An stats exporter
9296
*/
93-
registerExporter(exporter: StatsEventListener) {
97+
registerExporter(exporter: StatsEventListener): void {
9498
this.statsEventListeners.push(exporter);
9599

96100
for (const measureName of Object.keys(this.registeredViews)) {
@@ -153,7 +157,7 @@ export class Stats {
153157
* Updates all views with the new measurements.
154158
* @param measurements A list of measurements to record
155159
*/
156-
record(...measurements: Measurement[]) {
160+
record(...measurements: Measurement[]): void {
157161
if (this.hasNegativeValue(measurements)) {
158162
this.logger.warn(`Dropping measurments ${measurements}, value to record
159163
must be non-negative.`);
@@ -176,4 +180,12 @@ export class Stats {
176180
}
177181
}
178182
}
183+
184+
/**
185+
* Remove all registered Views and exporters from the stats.
186+
*/
187+
clear(): void {
188+
this.registeredViews = {};
189+
this.statsEventListeners = [];
190+
}
179191
}

packages/opencensus-core/src/stats/types.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,76 @@
1414
* limitations under the License.
1515
*/
1616

17+
import {StatsEventListener} from '../exporters/types';
1718
import {Metric} from '../metrics/export/types';
1819

20+
/** Main interface for stats. */
21+
export interface Stats {
22+
/**
23+
* Creates a view.
24+
* @param name The view name
25+
* @param measure The view measure
26+
* @param aggregation The view aggregation type
27+
* @param tagKeys The view columns (tag keys)
28+
* @param description The view description
29+
* @param bucketBoundaries The view bucket boundaries for a distribution
30+
* aggregation type
31+
*/
32+
createView(
33+
name: string, measure: Measure, aggregation: AggregationType,
34+
tagKeys: string[], description: string,
35+
bucketBoundaries?: number[]): View;
36+
37+
/**
38+
* Registers a view to listen to new measurements in its measure.
39+
* @param view The view to be registered
40+
*/
41+
registerView(view: View): void;
42+
43+
/**
44+
* Creates a measure of type Double.
45+
* @param name The measure name
46+
* @param unit The measure unit
47+
* @param description The measure description
48+
*/
49+
createMeasureDouble(name: string, unit: MeasureUnit, description?: string):
50+
Measure;
51+
52+
/**
53+
* Creates a measure of type Int64. Values must be integers up to
54+
* Number.MAX_SAFE_INTERGER.
55+
* @param name The measure name
56+
* @param unit The measure unit
57+
* @param description The measure description
58+
*/
59+
createMeasureInt64(name: string, unit: MeasureUnit, description?: string):
60+
Measure;
61+
62+
/**
63+
* Updates all views with the new measurements.
64+
* @param measurements A list of measurements to record
65+
*/
66+
record(...measurements: Measurement[]): void;
67+
68+
/**
69+
* Remove all registered Views and exporters from the stats.
70+
*/
71+
clear(): void;
72+
73+
/**
74+
* Gets a collection of produced Metric`s to be exported.
75+
* @returns {Metric[]} List of metrics
76+
*/
77+
getMetrics(): Metric[];
78+
79+
/**
80+
* Registers an exporter to send stats data to a service.
81+
* @param exporter An stats exporter
82+
*/
83+
registerExporter(exporter: StatsEventListener): void;
84+
}
85+
86+
1987
/** Tags are maps of names -> values */
2088
export interface Tags {
2189
[key: string]: string;

packages/opencensus-core/test/test-metric-producer.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,21 @@
1515
*/
1616

1717
import * as assert from 'assert';
18-
import {AggregationType, Measurement, MeasureUnit, Stats, Tags, View} from '../src';
18+
19+
import {AggregationType, globalStats, Measurement, MeasureUnit, Tags, View} from '../src';
1920
import {LabelKey, LabelValue, MetricDescriptorType} from '../src/metrics/export/types';
2021
import {MetricProducerForStats} from '../src/stats/metric-producer';
2122

2223
describe('Metric producer for stats', () => {
23-
const stats = new Stats();
24-
const metricProducerForStats = new MetricProducerForStats(stats);
24+
const metricProducerForStats = new MetricProducerForStats(globalStats);
2525

2626
// constants for view name
2727
const viewName1 = 'test/view/name1';
2828
const viewName2 = 'test/view/name2';
2929
const viewName3 = 'test/view/name2';
3030
const description = 'test description';
3131

32-
const measureDouble = stats.createMeasureDouble(
32+
const measureDouble = globalStats.createMeasureDouble(
3333
'opencensus.io/test/double', MeasureUnit.UNIT, 'Measure Double');
3434
const tags: Tags = {testKey1: 'testValue1', testKey2: 'testValue2'};
3535
const labelKeys: LabelKey[] = [
@@ -72,9 +72,10 @@ describe('Metric producer for stats', () => {
7272
};
7373

7474
it('should add sum stats', () => {
75-
const view: View = stats.createView(
75+
const view: View = globalStats.createView(
7676
viewName1, measureDouble, AggregationType.SUM, Object.keys(tags),
7777
description);
78+
globalStats.registerView(view);
7879
view.recordMeasurement(measurement1);
7980

8081
const metrics = metricProducerForStats.getMetrics();
@@ -92,9 +93,10 @@ describe('Metric producer for stats', () => {
9293

9394
it('should add count stats',
9495
() => {
95-
const view: View = stats.createView(
96+
const view: View = globalStats.createView(
9697
viewName2, measureDouble, AggregationType.COUNT, Object.keys(tags),
9798
description);
99+
globalStats.registerView(view);
98100
view.recordMeasurement(measurement1);
99101

100102
let metrics = metricProducerForStats.getMetrics();
@@ -122,9 +124,10 @@ describe('Metric producer for stats', () => {
122124
});
123125

124126
it('should add lastValue stats', () => {
125-
const view: View = stats.createView(
127+
const view: View = globalStats.createView(
126128
viewName3, measureDouble, AggregationType.LAST_VALUE, Object.keys(tags),
127129
description);
130+
globalStats.registerView(view);
128131
view.recordMeasurement(measurement1);
129132
view.recordMeasurement(measurement2);
130133

@@ -153,9 +156,10 @@ describe('Metric producer for stats', () => {
153156
const measurementValues = [1.1, 2.3, 3.2, 4.3, 5.2];
154157
const buckets = [2, 4, 6];
155158

156-
const view: View = stats.createView(
159+
const view: View = globalStats.createView(
157160
viewName3, measureDouble, AggregationType.DISTRIBUTION,
158161
Object.keys(tags), description, buckets);
162+
globalStats.registerView(view);
159163
for (const value of measurementValues) {
160164
const measurement: Measurement = {measure: measureDouble, value, tags};
161165
view.recordMeasurement(measurement);

0 commit comments

Comments
 (0)