Skip to content
This repository was archived by the owner on Oct 3, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the : Stats type specifier needed here?

Those are useful for enforcing the type assignment to a structural type like const x: Y = {...}, but since BaseStats.instance already has a type I would think it isn't needed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is added to avoid compiler error -> Exported variable 'globalStats' has or is using name 'Stats' from external module "/opencensus-core/src/stats/types" but cannot be named.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@draffensperger Are you ok with my comment or you have better approach to handle this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that makes sense, thanks for clarifying.

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 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: do we need to include : void here? (Same comment applies to the other methods below)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This not really required, but we are already using the same notion in other classes. I was trying to make things consistent.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I think that's fine.

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;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need : void here? (Same comment applies to registerExporter below).


/**
* 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