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

Commit

Permalink
Make Stats singleton (globalStats), separate registerView from creat…
Browse files Browse the repository at this point in the history
…eView (#291)

* Make Stats singleton (globalStats), separate registerView from createView

* fix tests

* remove type annotation and redundant comment
  • Loading branch information
mayurkale22 committed Jan 22, 2019
1 parent 37fd034 commit 8e3d5aa
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 138 deletions.
24 changes: 23 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**
Expand Down
8 changes: 7 additions & 1 deletion packages/opencensus-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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};
2 changes: 1 addition & 1 deletion packages/opencensus-core/src/stats/metric-producer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
40 changes: 26 additions & 14 deletions packages/opencensus-core/src/stats/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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
Expand All @@ -82,15 +87,14 @@ export class Stats {
bucketBoundaries?: number[]): View {
const view = new BaseView(
name, measure, aggregation, tagKeys, description, bucketBoundaries);
this.registerView(view);
return view;
}

/**
* 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)) {
Expand Down Expand Up @@ -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.`);
Expand All @@ -176,4 +180,12 @@ export class Stats {
}
}
}

/**
* Remove all registered Views and exporters from the stats.
*/
clear(): void {
this.registeredViews = {};
this.statsEventListeners = [];
}
}
68 changes: 68 additions & 0 deletions packages/opencensus-core/src/stats/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
20 changes: 12 additions & 8 deletions packages/opencensus-core/test/test-metric-producer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@
*/

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';
const viewName2 = 'test/view/name2';
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[] = [
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 8e3d5aa

Please sign in to comment.