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

Commit

Permalink
Plug-in Cumulative APIs into the Metric-Registry (#505)
Browse files Browse the repository at this point in the history
* Plug-in Cumulative into the Metric-Registry

* fix review comments

* update CHANGELOG.md
  • Loading branch information
mayurkale22 authored May 8, 2019
1 parent 49ef54f commit 5db22c9
Show file tree
Hide file tree
Showing 3 changed files with 261 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.

## Unreleased

- Add Cumulative (`DoubleCumulative`, `Int64Cumulative`) APIs.

**This release has a breaking change. Please test your code accordingly after upgrading.**

- removing Tracer's `startChildSpan(name?: string, kind?: types.SpanKind)` interface
Expand Down
95 changes: 79 additions & 16 deletions packages/opencensus-core/src/metrics/metric-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import {validateArrayElementsNotNull, validateDuplicateKeys, validateMapElementNotNull, validateNotNull} from '../common/validations';
import {MeasureUnit} from '../stats/types';
import {Cumulative} from './cumulative/cumulative';
import {BaseMetricProducer} from './export/base-metric-producer';
import {Metric, MetricDescriptorType, MetricProducer} from './export/types';
import {DerivedGauge} from './gauges/derived-gauge';
Expand Down Expand Up @@ -46,9 +47,9 @@ export class MetricRegistry {
* convenient form when you want to manually increase and decrease values as
* per your service requirements.
*
* @param {string} name The name of the metric.
* @param {MetricOptions} options The options for the metric.
* @returns {Gauge} A Int64 Gauge metric.
* @param name The name of the metric.
* @param options The options for the metric.
* @returns A Int64 Gauge metric.
*/
addInt64Gauge(name: string, options?: MetricOptions): Gauge {
const description =
Expand Down Expand Up @@ -77,9 +78,9 @@ export class MetricRegistry {
* convenient form when you want to manually increase and decrease values as
* per your service requirements.
*
* @param {string} name The name of the metric.
* @param {MetricOptions} options The options for the metric.
* @returns {Gauge} A Double Gauge metric.
* @param name The name of the metric.
* @param options The options for the metric.
* @returns A Double Gauge metric.
*/
addDoubleGauge(name: string, options?: MetricOptions): Gauge {
const description =
Expand Down Expand Up @@ -108,9 +109,9 @@ export class MetricRegistry {
* convenient form when you want to manually increase and decrease values as
* per your service requirements.
*
* @param {string} name The name of the metric.
* @param {MetricOptions} options The options for the metric.
* @returns {DerivedGauge} A Int64 DerivedGauge metric.
* @param name The name of the metric.
* @param options The options for the metric.
* @returns A Int64 DerivedGauge metric.
*/
addDerivedInt64Gauge(name: string, options?: MetricOptions): DerivedGauge {
const description =
Expand Down Expand Up @@ -139,9 +140,9 @@ export class MetricRegistry {
* convenient form when you want to manually increase and decrease values as
* per your service requirements.
*
* @param {string} name The name of the metric.
* @param {MetricOptions} options The options for the metric.
* @returns {DerivedGauge} A Double DerivedGauge metric.
* @param name The name of the metric.
* @param options The options for the metric.
* @returns A Double DerivedGauge metric.
*/
addDerivedDoubleGauge(name: string, options?: MetricOptions): DerivedGauge {
const description =
Expand All @@ -165,11 +166,73 @@ export class MetricRegistry {
return derivedDoubleGauge;
}

/**
* Builds a new Int64 cumulative to be added to the registry. This API is
* useful when you want to manually increase and reset values as per service
* requirements.
*
* @param name The name of the metric.
* @param options The options for the metric.
* @returns A Int64 Cumulative metric.
*/
addInt64Cumulative(name: string, options?: MetricOptions): Cumulative {
const description =
(options && options.description) || MetricRegistry.DEFAULT_DESCRIPTION;
const unit = (options && options.unit) || MetricRegistry.DEFAULT_UNIT;
const labelKeys =
(options && options.labelKeys) || MetricRegistry.DEFAULT_LABEL_KEYS;
const constantLabels = (options && options.constantLabels) ||
MetricRegistry.DEFAULT_CONSTANT_LABEL;
// TODO(mayurkale): Add support for resource

validateArrayElementsNotNull(labelKeys, MetricRegistry.LABEL_KEY);
validateMapElementNotNull(constantLabels, MetricRegistry.CONSTANT_LABELS);
validateDuplicateKeys(labelKeys, constantLabels);

const labelKeysCopy = Object.assign([], labelKeys);
const int64Cumulative = new Cumulative(
validateNotNull(name, MetricRegistry.NAME), description, unit,
MetricDescriptorType.CUMULATIVE_INT64, labelKeysCopy, constantLabels);
this.registerMetric(name, int64Cumulative);
return int64Cumulative;
}

/**
* Builds a new double cumulative to be added to the registry. This API is
* useful when you want to manually increase and reset values as per service
* requirements.
*
* @param name The name of the metric.
* @param options The options for the metric.
* @returns A Double Cumulative metric.
*/
addDoubleCumulative(name: string, options?: MetricOptions): Cumulative {
const description =
(options && options.description) || MetricRegistry.DEFAULT_DESCRIPTION;
const unit = (options && options.unit) || MetricRegistry.DEFAULT_UNIT;
const labelKeys =
(options && options.labelKeys) || MetricRegistry.DEFAULT_LABEL_KEYS;
const constantLabels = (options && options.constantLabels) ||
MetricRegistry.DEFAULT_CONSTANT_LABEL;
// TODO(mayurkale): Add support for resource

validateArrayElementsNotNull(labelKeys, MetricRegistry.LABEL_KEY);
validateMapElementNotNull(constantLabels, MetricRegistry.CONSTANT_LABELS);
validateDuplicateKeys(labelKeys, constantLabels);

const labelKeysCopy = Object.assign([], labelKeys);
const doubleCumulative = new Cumulative(
validateNotNull(name, MetricRegistry.NAME), description, unit,
MetricDescriptorType.CUMULATIVE_DOUBLE, labelKeysCopy, constantLabels);
this.registerMetric(name, doubleCumulative);
return doubleCumulative;
}

/**
* Registers metric to register.
*
* @param {string} name The name of the metric.
* @param {Meter} meter The metric to register.
* @param name The name of the metric.
* @param meter The metric to register.
*/
private registerMetric(name: string, meter: Meter): void {
if (this.registeredMetrics.has(name)) {
Expand All @@ -182,7 +245,7 @@ export class MetricRegistry {
/**
* Gets a metric producer for registry.
*
* @returns {MetricProducer} The metric producer.
* @returns The metric producer.
*/
getMetricProducer(): MetricProducer {
return this.metricProducer;
Expand All @@ -204,7 +267,7 @@ class MetricProducerForRegistry extends BaseMetricProducer {
/**
* Gets a collection of produced Metric`s to be exported.
*
* @returns {Metric[]} The list of metrics.
* @returns The list of metrics.
*/
getMetrics(): Metric[] {
return Array.from(this.registeredMetrics.values())
Expand Down
182 changes: 180 additions & 2 deletions packages/opencensus-core/test/test-metric-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,170 @@ describe('addDerivedDoubleGauge', () => {
});
});

describe('addInt64Cumulative', () => {
let registry: MetricRegistry;
const realHrtimeFn = process.hrtime;
const realNowFn = Date.now;
const mockedTime: Timestamp = {seconds: 1450000100, nanos: 1e7};

beforeEach(() => {
registry = new MetricRegistry();

process.hrtime = () => [100, 1e7];
Date.now = () => 1450000000000;
// Force the clock to recalibrate the time offset with the mocked time
TEST_ONLY.setHrtimeReference();
});

afterEach(() => {
process.hrtime = realHrtimeFn;
Date.now = realNowFn;
// Reset the hrtime reference so that it uses a real clock again.
TEST_ONLY.resetHrtimeFunctionCache();
});

it('should return a metric', () => {
const int64Gauge = registry.addInt64Cumulative(METRIC_NAME, METRIC_OPTIONS);
const pointEntry = int64Gauge.getOrCreateTimeSeries(LABEL_VALUES_200);
pointEntry.inc();

const metrics = registry.getMetricProducer().getMetrics();
assert.strictEqual(metrics.length, 1);
const [{descriptor, timeseries}] = metrics;
assert.deepStrictEqual(descriptor, {
name: METRIC_NAME,
description: METRIC_DESCRIPTION,
labelKeys: LABEL_KEYS,
unit: UNIT,
type: MetricDescriptorType.CUMULATIVE_INT64
});
assert.strictEqual(timeseries.length, 1);
const [{points}] = timeseries;
const [point] = points;
assert.equal(point.value, 1);
assert.deepStrictEqual(
point.timestamp,
{seconds: mockedTime.seconds, nanos: mockedTime.nanos});
});

it('should return a metric without options', () => {
const int64Gauge = registry.addInt64Cumulative(METRIC_NAME);
const pointEntry = int64Gauge.getDefaultTimeSeries();
pointEntry.inc(100);

const metrics = registry.getMetricProducer().getMetrics();
assert.strictEqual(metrics.length, 1);
const [{descriptor, timeseries}] = metrics;
assert.deepStrictEqual(descriptor, {
name: METRIC_NAME,
description: '',
labelKeys: [],
unit: UNIT,
type: MetricDescriptorType.CUMULATIVE_INT64
});
assert.strictEqual(timeseries.length, 1);
const [{points}] = timeseries;
const [point] = points;
assert.equal(point.value, 100);
assert.deepStrictEqual(
point.timestamp,
{seconds: mockedTime.seconds, nanos: mockedTime.nanos});
});

it('should throw an error when the duplicate keys in labelKeys and constantLabels',
() => {
const constantLabels = new Map();
constantLabels.set({key: 'k1'}, {value: 'v1'});
const labelKeys = [{key: 'k1', description: 'desc'}];
assert.throws(() => {
registry.addInt64Cumulative(METRIC_NAME, {constantLabels, labelKeys});
}, /^Error: The keys from LabelKeys should not be present in constantLabels or LabelKeys should not contains duplicate keys$/);
});
});

describe('addDoubleCumulative', () => {
let registry: MetricRegistry;
const realHrtimeFn = process.hrtime;
const realNowFn = Date.now;
const mockedTime: Timestamp = {seconds: 1450000100, nanos: 1e7};

beforeEach(() => {
registry = new MetricRegistry();

process.hrtime = () => [100, 1e7];
Date.now = () => 1450000000000;
// Force the clock to recalibrate the time offset with the mocked time
TEST_ONLY.setHrtimeReference();
});

afterEach(() => {
process.hrtime = realHrtimeFn;
Date.now = realNowFn;
// Reset the hrtime reference so that it uses a real clock again.
TEST_ONLY.resetHrtimeFunctionCache();
});

it('should return a metric', () => {
const int64Gauge =
registry.addDoubleCumulative(METRIC_NAME, METRIC_OPTIONS);
const pointEntry = int64Gauge.getOrCreateTimeSeries(LABEL_VALUES_200);
pointEntry.inc(1.1);

const metrics = registry.getMetricProducer().getMetrics();
assert.strictEqual(metrics.length, 1);
const [{descriptor, timeseries}] = metrics;
assert.deepStrictEqual(descriptor, {
name: METRIC_NAME,
description: METRIC_DESCRIPTION,
labelKeys: LABEL_KEYS,
unit: UNIT,
type: MetricDescriptorType.CUMULATIVE_DOUBLE
});
assert.strictEqual(timeseries.length, 1);
const [{points}] = timeseries;
const [point] = points;
assert.equal(point.value, 1.1);
assert.deepStrictEqual(
point.timestamp,
{seconds: mockedTime.seconds, nanos: mockedTime.nanos});
});

it('should return a metric without options', () => {
const int64Gauge = registry.addDoubleCumulative(METRIC_NAME);
const pointEntry = int64Gauge.getDefaultTimeSeries();
pointEntry.inc();
pointEntry.inc(100.12);

const metrics = registry.getMetricProducer().getMetrics();
assert.strictEqual(metrics.length, 1);
const [{descriptor, timeseries}] = metrics;
assert.deepStrictEqual(descriptor, {
name: METRIC_NAME,
description: '',
labelKeys: [],
unit: UNIT,
type: MetricDescriptorType.CUMULATIVE_DOUBLE
});
assert.strictEqual(timeseries.length, 1);
const [{points}] = timeseries;
const [point] = points;
assert.equal(point.value, 101.12);
assert.deepStrictEqual(
point.timestamp,
{seconds: mockedTime.seconds, nanos: mockedTime.nanos});
});

it('should throw an error when the duplicate keys in labelKeys and constantLabels',
() => {
const constantLabels = new Map();
constantLabels.set({key: 'k1'}, {value: 'v1'});
const labelKeys = [{key: 'k1', description: 'desc'}];
assert.throws(() => {
registry.addDoubleCumulative(METRIC_NAME, {constantLabels, labelKeys});
}, /^Error: The keys from LabelKeys should not be present in constantLabels or LabelKeys should not contains duplicate keys$/);
});
});

describe('Add multiple gauges', () => {
let registry: MetricRegistry;
const realHrtimeFn = process.hrtime;
Expand Down Expand Up @@ -406,9 +570,13 @@ describe('Add multiple gauges', () => {
size: () => arr.length,
});

const int64Cumulative =
registry.addInt64Cumulative('metric-name4', METRIC_OPTIONS);
int64Cumulative.getOrCreateTimeSeries(LABEL_VALUES_200).inc();

const metrics = registry.getMetricProducer().getMetrics();
assert.strictEqual(metrics.length, 3);
const [{descriptor: descriptor1, timeseries: timeseries1}, {descriptor: descriptor2, timeseries: timeseries2}, {descriptor: descriptor3, timeseries: timeseries3}] = metrics;
assert.strictEqual(metrics.length, 4);
const [{descriptor: descriptor1, timeseries: timeseries1}, {descriptor: descriptor2, timeseries: timeseries2}, {descriptor: descriptor3, timeseries: timeseries3}, {descriptor: descriptor4, timeseries: timeseries4}] = metrics;
assert.deepStrictEqual(descriptor1, {
name: 'metric-name1',
description: METRIC_DESCRIPTION,
Expand All @@ -430,6 +598,13 @@ describe('Add multiple gauges', () => {
unit: UNIT,
type: MetricDescriptorType.GAUGE_INT64
});
assert.deepStrictEqual(descriptor4, {
name: 'metric-name4',
description: METRIC_DESCRIPTION,
labelKeys: LABEL_KEYS,
unit: UNIT,
type: MetricDescriptorType.CUMULATIVE_INT64
});
assert.strictEqual(timeseries1.length, 1);
assert.strictEqual(timeseries1[0].points.length, 1);
assert.equal(timeseries1[0].points[0].value, 100);
Expand All @@ -446,5 +621,8 @@ describe('Add multiple gauges', () => {
timeseries1[0].points[0].timestamp, timeseries2[0].points[0].timestamp);
assert.deepStrictEqual(
timeseries2[0].points[0].timestamp, timeseries3[0].points[0].timestamp);
assert.strictEqual(timeseries4.length, 1);
assert.strictEqual(timeseries4[0].points.length, 1);
assert.equal(timeseries4[0].points[0].value, 1);
});
});

0 comments on commit 5db22c9

Please sign in to comment.