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

Commit

Permalink
add tests, fix viewToMetricDescriptor, fix startTimestamp (#219)
Browse files Browse the repository at this point in the history
  • Loading branch information
mayurkale22 authored Dec 10, 2018
1 parent 12f184a commit 6b27a67
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 81 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,4 @@ jobs:
command: npm install
- run:
name: Publish the module to npm.
command: npm publish
command: npm publish
4 changes: 3 additions & 1 deletion packages/opencensus-core/src/stats/metric-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@ export class MetricUtils {
* @returns {MetricDescriptor}
*/
static viewToMetricDescriptor(view: View): MetricDescriptor {
// TODO(mayurkale): add description
return {
name: view.name,
description: view.description,
unit: view.measure.unit,
type: MetricUtils.getType(view.measure, view.aggregation),
labelKeys: view.getColumns().map(tag => ({key: tag} as LabelKey))
labelKeys: view.getColumns().map(
tag => ({key: tag, description: ''} as LabelKey))
};
}

Expand Down
14 changes: 12 additions & 2 deletions packages/opencensus-core/src/stats/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,18 @@ export class BaseView implements View {
const {type} = this.metricDescriptor;
let startTimestamp: Timestamp;

// The moment when this point was recorded.
const [currentSeconds, currentNanos] = process.hrtime();
const now: Timestamp = {seconds: currentSeconds, nanos: currentNanos};

switch (type) {
case MetricDescriptorType.GAUGE_INT64:
case MetricDescriptorType.GAUGE_DOUBLE:
startTimestamp = null;
break;
default:
const [seconds, nanos] = process.hrtime();
// TODO (mayurkale): This should be set when create Cumulative view.
startTimestamp = {seconds, nanos};
}

Expand All @@ -217,8 +222,13 @@ export class BaseView implements View {
Object.keys(this.rows).forEach(key => {
const {tags} = this.rows[key];
const labelValues: LabelValue[] = MetricUtils.tagsToLabelValues(tags);
const point: Point = this.toPoint(startTimestamp, this.getSnapshot(tags));
timeseries.push({startTimestamp, labelValues, points: [point]});
const point: Point = this.toPoint(now, this.getSnapshot(tags));

if (startTimestamp) {
timeseries.push({startTimestamp, labelValues, points: [point]});
} else {
timeseries.push({labelValues, points: [point]});
}
});

return {descriptor: this.metricDescriptor, timeseries};
Expand Down
257 changes: 186 additions & 71 deletions packages/opencensus-core/test/test-metric-producer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,87 +15,202 @@
*/

import * as assert from 'assert';

import {AggregationType, Measure, MeasureType, MeasureUnit, Stats, Tags, View} from '../src';
import {MetricDescriptorType} from '../src/metrics/export/types';
import {AggregationType, Measurement, MeasureUnit, Stats, Tags, View} from '../src';
import {LabelKey, LabelValue, MetricDescriptorType, Timestamp} from '../src/metrics/export/types';
import {MetricProducerForStats} from '../src/stats/metric-producer';

describe('Metric producer for stats', () => {
interface AggregationTestCase {
aggregationType: AggregationType;
description: string;
metricDescriptorType: MetricDescriptorType;
}
const aggregationTestCases: AggregationTestCase[] = [
{
aggregationType: AggregationType.SUM,
description: 'Sum',
metricDescriptorType: MetricDescriptorType.CUMULATIVE_DOUBLE
},
{
aggregationType: AggregationType.COUNT,
description: 'Count',
metricDescriptorType: MetricDescriptorType.CUMULATIVE_INT64
},
{
aggregationType: AggregationType.LAST_VALUE,
description: 'Last Value',
metricDescriptorType: MetricDescriptorType.GAUGE_DOUBLE
},
{
aggregationType: AggregationType.DISTRIBUTION,
description: 'Distribution',
metricDescriptorType: MetricDescriptorType.CUMULATIVE_DISTRIBUTION
}
const {hrtime} = process;
const mockedTime: Timestamp = {nanos: 1e7, seconds: 1000};

before(() => {
process.hrtime = () => [1000, 1e7];
});

after(() => {
process.hrtime = hrtime;
});

const stats = new Stats();
const metricProducerForStats = new MetricProducerForStats(stats);

// 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(
'opencensus.io/test/double', MeasureUnit.UNIT, 'Measure Double');
const tags: Tags = {testKey1: 'testValue1', testKey2: 'testValue2'};
const labelKeys: LabelKey[] = [
{'key': 'testKey1', 'description': ''},
{'key': 'testKey2', 'description': ''}
];
const measure: Measure = {
name: 'Test Measure',
type: MeasureType.DOUBLE,
unit: MeasureUnit.UNIT
const labelValues: LabelValue[] =
[{'value': 'testValue1'}, {'value': 'testValue2'}];
const measurement1: Measurement = {measure: measureDouble, value: 25, tags};
const measurement2: Measurement = {measure: measureDouble, value: 300, tags};

// expected constants
const expectedMetricDescriptor1 = {
name: viewName1,
description,
labelKeys,
unit: MeasureUnit.UNIT,
type: MetricDescriptorType.CUMULATIVE_DOUBLE,
};
const expectedTimeSeries1 = [{
labelValues,
points: [{value: 25, timestamp: mockedTime}],
startTimestamp: mockedTime
}];
const expectedMetricDescriptor2 = {
name: viewName2,
description,
labelKeys,
unit: MeasureUnit.UNIT,
type: MetricDescriptorType.CUMULATIVE_INT64,
};
const expectedTimeSeries2 = [{
labelValues,
points: [{value: 1, timestamp: mockedTime}],
startTimestamp: mockedTime
}];
const expectedMetricDescriptor3 = {
name: viewName3,
description,
labelKeys,
unit: MeasureUnit.UNIT,
type: MetricDescriptorType.GAUGE_DOUBLE,
};
const expectedTimeSeries3 =
[{labelValues, points: [{value: 300, timestamp: mockedTime}]}];
const expectedMetricDescriptor4 = {
name: viewName3,
description,
labelKeys,
unit: MeasureUnit.UNIT,
type: MetricDescriptorType.CUMULATIVE_DISTRIBUTION,
};
const expectedTimeSeries4 = [{
labelValues,
points: [{
value: {
'bucketOptions': {'explicit': {'bounds': [2, 4, 6]}},
'buckets': [1, 2, 2, 0],
'count': 5,
'sum': 16.099999999999998,
'sumOfSquaredDeviation': 10.427999999999997
},
timestamp: mockedTime
}],
startTimestamp: mockedTime
}];

let stats: Stats;
let metricProducerForStats: MetricProducerForStats;
it('should add sum stats', () => {
const view: View = stats.createView(
viewName1, measureDouble, AggregationType.SUM, Object.keys(tags),
description);
view.recordMeasurement(measurement1);

beforeEach(() => {
stats = new Stats();
metricProducerForStats = new MetricProducerForStats(stats);
const metrics = metricProducerForStats.getMetrics();

assert.strictEqual(metrics.length, 1);
const [{
descriptor: actualMetricDescriptor1,
timeseries: actualTimeSeries1
}] = metrics;
assert.deepStrictEqual(actualMetricDescriptor1, expectedMetricDescriptor1);
assert.strictEqual(actualTimeSeries1.length, 1);
assert.deepStrictEqual(actualTimeSeries1, expectedTimeSeries1);
});

it('should add count stats',
() => {
const view: View = stats.createView(
viewName2, measureDouble, AggregationType.COUNT, Object.keys(tags),
description);
view.recordMeasurement(measurement1);

let metrics = metricProducerForStats.getMetrics();

assert.strictEqual(metrics.length, 2);
const
[{descriptor: actualMetricDescriptor1, timeseries: actualTimeSeries1},
{descriptor: actualMetricDescriptor2, timeseries: actualTimeSeries2}] =
metrics;
assert.deepStrictEqual(
actualMetricDescriptor1, expectedMetricDescriptor1);
assert.strictEqual(actualTimeSeries1.length, 1);
assert.deepStrictEqual(actualTimeSeries1, expectedTimeSeries1);
assert.deepStrictEqual(
actualMetricDescriptor2, expectedMetricDescriptor2);
assert.strictEqual(actualTimeSeries2.length, 1);
assert.deepStrictEqual(actualTimeSeries2, expectedTimeSeries2);

// update count view
view.recordMeasurement(measurement2);
metrics = metricProducerForStats.getMetrics();
assert.deepStrictEqual(metrics[1].timeseries[0].points[0].value, 2);
});

it('should add lastValue stats', () => {
const view: View = stats.createView(
viewName3, measureDouble, AggregationType.LAST_VALUE, Object.keys(tags),
description);
view.recordMeasurement(measurement1);
view.recordMeasurement(measurement2);

const metrics = metricProducerForStats.getMetrics();

assert.strictEqual(metrics.length, 3);
const
[{descriptor: actualMetricDescriptor1, timeseries: actualTimeSeries1},
{descriptor: actualMetricDescriptor2, timeseries: actualTimeSeries2},
{descriptor: actualMetricDescriptor3, timeseries: actualTimeSeries3}] =
metrics;
assert.deepStrictEqual(actualMetricDescriptor1, expectedMetricDescriptor1);
assert.strictEqual(actualTimeSeries1.length, 1);
assert.deepStrictEqual(actualTimeSeries1, expectedTimeSeries1);
assert.deepStrictEqual(actualMetricDescriptor2, expectedMetricDescriptor2);
assert.strictEqual(actualTimeSeries2.length, 1);
assert.deepStrictEqual(actualMetricDescriptor3, expectedMetricDescriptor3);
assert.strictEqual(actualTimeSeries3.length, 1);
assert.deepStrictEqual(actualTimeSeries3, expectedTimeSeries3);
});

describe('Metric producer', () => {
const tags: Tags = {testKey1: 'testValue', testKey2: 'testValue'};
it('should add distribution stats', () => {
const measurementValues = [1.1, 2.3, 3.2, 4.3, 5.2];
const buckets = [2, 4, 6];

describe('getMetrics()', () => {
// Detailed coverage in test-viev.ts
for (const aggregation of aggregationTestCases) {
it(`should return list of metrics for ${
aggregation.aggregationType} aggregation`,
() => {
const view: View = stats.createView(
'test/view/name', measure, aggregation.aggregationType,
Object.keys(tags), 'test description', buckets);
for (const value of measurementValues) {
const measurement = {measure, tags, value};
view.recordMeasurement(measurement);
}

const metrics = metricProducerForStats.getMetrics();

assert.strictEqual(metrics.length, 1);
const [{descriptor, timeseries}] = metrics;

assert.deepStrictEqual(descriptor, {
name: 'test/view/name',
description: 'test description',
'labelKeys': [{'key': 'testKey1'}, {'key': 'testKey2'}],
unit: MeasureUnit.UNIT,
type: aggregation.metricDescriptorType,
});
assert.strictEqual(timeseries.length, 1);
});
}
});
const view: View = stats.createView(
viewName3, measureDouble, AggregationType.DISTRIBUTION,
Object.keys(tags), description, buckets);
for (const value of measurementValues) {
const measurement: Measurement = {measure: measureDouble, value, tags};
view.recordMeasurement(measurement);
}

const metrics = metricProducerForStats.getMetrics();

assert.strictEqual(metrics.length, 4);
const
[{descriptor: actualMetricDescriptor1, timeseries: actualTimeSeries1},
{descriptor: actualMetricDescriptor2, timeseries: actualTimeSeries2},
{descriptor: actualMetricDescriptor3, timeseries: actualTimeSeries3},
{descriptor: actualMetricDescriptor4, timeseries: actualTimeSeries4}] =
metrics;
assert.deepStrictEqual(actualMetricDescriptor1, expectedMetricDescriptor1);
assert.strictEqual(actualTimeSeries1.length, 1);
assert.deepStrictEqual(actualTimeSeries1, expectedTimeSeries1);
assert.deepStrictEqual(actualMetricDescriptor2, expectedMetricDescriptor2);
assert.strictEqual(actualTimeSeries2.length, 1);
assert.deepStrictEqual(actualMetricDescriptor3, expectedMetricDescriptor3);
assert.strictEqual(actualTimeSeries3.length, 1);
assert.deepStrictEqual(actualTimeSeries3, expectedTimeSeries3);
assert.deepStrictEqual(actualMetricDescriptor4, expectedMetricDescriptor4);
assert.strictEqual(actualTimeSeries4.length, 1);
assert.deepStrictEqual(actualTimeSeries4, expectedTimeSeries4);
});
});
});
5 changes: 3 additions & 2 deletions packages/opencensus-core/test/test-metric-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ describe('MetricUtil', () => {
assert.strictEqual(
metricDescriptor.type, MetricDescriptorType.GAUGE_DOUBLE);
assert.strictEqual(metricDescriptor.description, VIEW_DESCRIPTION);
assert.deepStrictEqual(
metricDescriptor.labelKeys, [{key: 'testKey1'}, {key: 'testKey2'}]);
assert.deepStrictEqual(metricDescriptor.labelKeys, [
{key: 'testKey1', description: ''}, {key: 'testKey2', description: ''}
]);
});

it('should convert tag values to label values', () => {
Expand Down
11 changes: 7 additions & 4 deletions packages/opencensus-core/test/test-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,10 @@ describe('BaseView', () => {
assert.ok(descriptor);
assert.deepStrictEqual(descriptor, {
description: 'description test',
labelKeys: [{key: 'testKey1'}, {key: 'testKey2'}],
labelKeys: [
{key: 'testKey1', description: ''},
{key: 'testKey2', description: ''}
],
name: 'test/view/name',
type: aggregationTestCase.metricDescriptorType,
unit: '1',
Expand All @@ -237,13 +240,13 @@ describe('BaseView', () => {
if (aggregationTestCase.metricDescriptorType ===
MetricDescriptorType.GAUGE_INT64) {
it('GAUGE_INT64 shouldnt has timeseries startTimestamp', () => {
assert.strictEqual(startTimestamp, null);
assert.strictEqual(startTimestamp, undefined);
});
} else if (
aggregationTestCase.metricDescriptorType ===
MetricDescriptorType.GAUGE_DOUBLE) {
it('GAUGE_DOUBLE shouldnt has timeseries startTimestamp', () => {
assert.strictEqual(startTimestamp, null);
assert.strictEqual(startTimestamp, undefined);
});
} else {
it('shouldnt has timeseries startTimestamp', () => {
Expand Down Expand Up @@ -363,7 +366,7 @@ describe('BaseView', () => {
assert.ok(points);
const [point] = points;
const {timestamp, value} = point;
assert.strictEqual(timestamp, null);
assert.deepStrictEqual(timestamp, {nanos: 1e7, seconds: 1000});
assert.equal(typeof value, 'number');
assert.strictEqual(
value, measurementValues[measurementValues.length - 1]);
Expand Down

0 comments on commit 6b27a67

Please sign in to comment.