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

Commit

Permalink
Add support for Cumulative API (#480)
Browse files Browse the repository at this point in the history
* Add support for Cumulative API

* Handle NaN and add test

* Add comments for getMetric() method
  • Loading branch information
mayurkale22 committed Apr 11, 2019
1 parent abd41db commit 1853dc9
Show file tree
Hide file tree
Showing 9 changed files with 591 additions and 30 deletions.
3 changes: 3 additions & 0 deletions packages/opencensus-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ export * from './common/version';
export * from './metrics/metrics';
export * from './metrics/metric-registry';

// Cumulative CLASSES
export * from './metrics/cumulative/cumulative';

// GAUGES CLASSES
export * from './metrics/gauges/derived-gauge';
export * from './metrics/gauges/gauge';
Expand Down
197 changes: 197 additions & 0 deletions packages/opencensus-core/src/metrics/cumulative/cumulative.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/**
* Copyright 2019, OpenCensus Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {getTimestampWithProcessHRTime} from '../../common/time-util';
import {validateArrayElementsNotNull, validateNotNull} from '../../common/validations';
import {LabelKey, LabelValue, Metric, MetricDescriptor, MetricDescriptorType, TimeSeries, Timestamp} from '../export/types';
import {Meter} from '../types';
import {hashLabelValues, initializeDefaultLabels} from '../utils';
import {CumulativePoint} from './types';

/**
* Cumulative metric is used to record aggregated metrics that represents a
* single numerical value accumulated over a time interval. The value can only
* increase or be reset to zero on restart or reset the event.
*/
export class Cumulative implements Meter {
private readonly metricDescriptor: MetricDescriptor;
private labelKeysLength: number;
private defaultLabelValues: LabelValue[];
private registeredPoints: Map<string, CumulativePoint> = new Map();
private readonly constantLabelValues: LabelValue[];

/**
* Constructs a new Cumulative instance.
*
* @param {string} name The name of the metric.
* @param {string} description The description of the metric.
* @param {string} unit The unit of the metric.
* @param {MetricDescriptorType} type The type of metric.
* @param {LabelKey[]} labelKeys The list of the label keys.
* @param {Map<LabelKey, LabelValue>} constantLabels The map of constant
* labels for the Metric.
*/
constructor(
name: string, description: string, unit: string,
type: MetricDescriptorType, readonly labelKeys: LabelKey[],
readonly constantLabels: Map<LabelKey, LabelValue>) {
this.labelKeysLength = labelKeys.length;
const keysAndConstantKeys = [...labelKeys, ...constantLabels.keys()];
this.constantLabelValues = [...constantLabels.values()];

this.metricDescriptor =
{name, description, unit, type, labelKeys: keysAndConstantKeys};
this.defaultLabelValues = initializeDefaultLabels(this.labelKeysLength);
}

/**
* Creates a TimeSeries and returns a Point if the specified
* labelValues is not already associated with this cumulative, else returns an
* existing Point.
*
* It is recommended to keep a reference to the Point instead of always
* calling this method for manual operations.
*
* @param {LabelValue[]} labelValues The list of the label values.
* @returns {CumulativePoint} The value of single cumulative.
*/
getOrCreateTimeSeries(labelValues: LabelValue[]): CumulativePoint {
validateArrayElementsNotNull(
validateNotNull(labelValues, 'labelValues'), 'labelValue');
return this.registerTimeSeries(labelValues);
}

/**
* Returns a Point for a cumulative with all labels not set, or default
* labels.
*
* @returns {CumulativePoint} The value of single cumulative.
*/
getDefaultTimeSeries(): CumulativePoint {
return this.registerTimeSeries(this.defaultLabelValues);
}

/**
* Removes the TimeSeries from the cumulative metric, if it is present. i.e.
* references to previous Point objects are invalid (not part of the
* metric).
*
* @param {LabelValue[]} labelValues The list of label values.
*/
removeTimeSeries(labelValues: LabelValue[]): void {
validateNotNull(labelValues, 'labelValues');
this.registeredPoints.delete(hashLabelValues(labelValues));
}

/**
* Removes all TimeSeries from the cumulative metric. i.e. references to all
* previous Point objects are invalid (not part of the metric).
*/
clear(): void {
this.registeredPoints.clear();
}

/**
* Registers a TimeSeries and returns a Point if the specified
* labelValues is not already associated with this cumulative, else returns an
* existing Point.
*
* @param {LabelValue[]} labelValues The list of the label values.
* @returns {CumulativePoint} The value of single cumulative.
*/
private registerTimeSeries(labelValues: LabelValue[]): CumulativePoint {
const hash = hashLabelValues(labelValues);
// return if the specified labelValues is already associated with the point.
if (this.registeredPoints.has(hash)) {
return this.registeredPoints.get(hash)!;
}
if (this.labelKeysLength !== labelValues.length) {
throw new Error('Label Keys and Label Values don\'t have same size');
}

const point =
new CumulativePointEntry([...labelValues, ...this.constantLabelValues]);
this.registeredPoints.set(hash, point);
return point;
}

/**
* Provides a Metric with one or more TimeSeries.
*
* @returns {Metric} The Metric, or null if TimeSeries is not present in
* Metric.
*/
getMetric(): Metric|null {
if (this.registeredPoints.size === 0) {
return null;
}
const now: Timestamp = getTimestampWithProcessHRTime();
return {
descriptor: this.metricDescriptor,
timeseries: Array.from(
this.registeredPoints, ([_, point]) => point.getTimeSeries(now))
};
}
}

/**
* The value of a single point in the Cumulative.TimeSeries.
*/
export class CumulativePointEntry implements CumulativePoint {
private readonly labelValues: LabelValue[];
private startTimestamp: Timestamp;
private value = 0;

constructor(labelValues: LabelValue[]) {
this.labelValues = labelValues;
this.startTimestamp = getTimestampWithProcessHRTime();
}

/** Reset cumulative metric. */
reset(): void {
this.value = 0;
this.startTimestamp = getTimestampWithProcessHRTime();
}

/**
* Increment the cumulative metric.
* @param {number} val The new value.
*/
inc(val?: number): void {
if ((val && !Number.isFinite(val)) || (val !== undefined && isNaN(val))) {
throw new TypeError(`Value is not a valid number: ${val}`);
}
if (val && val < 0) {
throw new Error('It is not possible to decrease a cumulative metric');
}
const incValue = (val === null || val === undefined) ? 1 : val;
this.value += incValue;
}

/**
* Returns the TimeSeries with one or more Point.
*
* @param {Timestamp} now The time at which the cumulative is recorded.
* @returns {TimeSeries} The TimeSeries.
*/
getTimeSeries(now: Timestamp): TimeSeries {
return {
labelValues: this.labelValues,
points: [{value: this.value, timestamp: now}],
startTimestamp: this.startTimestamp
};
}
}
36 changes: 36 additions & 0 deletions packages/opencensus-core/src/metrics/cumulative/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright 2019, OpenCensus Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {TimeSeries, Timestamp} from '../export/types';

export interface CumulativePoint {
/** Reset cumulative metric. */
reset(): void;

/**
* Increment the cumulative metric.
* @param {number} val The new value.
*/
inc(val?: number): void;

/**
* Returns the TimeSeries with one or more Point.
*
* @param {Timestamp} now The time at which the cumulative is recorded.
* @returns {TimeSeries} The TimeSeries.
*/
getTimeSeries(now: Timestamp): TimeSeries;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import {getTimestampWithProcessHRTime} from '../../common/time-util';
import {validateArrayElementsNotNull, validateNotNull} from '../../common/validations';
import {LabelKey, LabelValue, Metric, MetricDescriptor, MetricDescriptorType, TimeSeries, Timestamp} from '../export/types';
import * as types from '../gauges/types';
import * as types from '../types';
import {hashLabelValues} from '../utils';

/**
Expand Down
5 changes: 3 additions & 2 deletions packages/opencensus-core/src/metrics/gauges/gauge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
import {getTimestampWithProcessHRTime} from '../../common/time-util';
import {validateArrayElementsNotNull, validateNotNull} from '../../common/validations';
import {LabelKey, LabelValue, Metric, MetricDescriptor, MetricDescriptorType, TimeSeries, Timestamp} from '../export/types';
import * as types from '../gauges/types';
import {Meter} from '../types';
import {hashLabelValues, initializeDefaultLabels} from '../utils';
import * as types from './types';

/**
* Gauge metric
*/
export class Gauge implements types.Meter {
export class Gauge implements Meter {
private readonly metricDescriptor: MetricDescriptor;
private labelKeysLength: number;
private defaultLabelValues: LabelValue[];
Expand Down
27 changes: 1 addition & 26 deletions packages/opencensus-core/src/metrics/gauges/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,7 @@
* limitations under the License.
*/

import {MeasureUnit} from '../../stats/types';
import {LabelKey, LabelValue, Metric, TimeSeries, Timestamp} from '../export/types';

export interface Meter {
/**
* Provides a Metric with one or more TimeSeries.
*
* @returns {Metric} The Metric.
*/
getMetric(): Metric|null;
}
import {TimeSeries, Timestamp} from '../export/types';

export interface Point {
/**
Expand All @@ -49,18 +39,3 @@ export interface Point {
*/
getTimeSeries(timestamp: Timestamp): TimeSeries;
}

/** Options for every metric added to the MetricRegistry. */
export interface MetricOptions {
/** The description of the metric. */
readonly description?: string;
/** The unit of the metric. */
readonly unit?: MeasureUnit;
/** The list of the label keys. */
readonly labelKeys?: LabelKey[];
/** The map of constant labels for the Metric. */
readonly constantLabels?: Map<LabelKey, LabelValue>;

// TODO(mayurkale): Add resource information.
// https://github.com/census-instrumentation/opencensus-specs/pull/248
}
2 changes: 1 addition & 1 deletion packages/opencensus-core/src/metrics/metric-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {BaseMetricProducer} from './export/base-metric-producer';
import {Metric, MetricDescriptorType, MetricProducer} from './export/types';
import {DerivedGauge} from './gauges/derived-gauge';
import {Gauge} from './gauges/gauge';
import {Meter, MetricOptions} from './gauges/types';
import {Meter, MetricOptions} from './types';

/**
* Creates and manages application's set of metrics.
Expand Down
44 changes: 44 additions & 0 deletions packages/opencensus-core/src/metrics/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright 2019, OpenCensus Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {MeasureUnit} from './../stats/types';
import {LabelKey, LabelValue, Metric} from './export/types';

/** Provides a {@link Metric} with one or more {@link TimeSeries} */
export interface Meter {
/**
* Provides a Metric with one or more TimeSeries.
*
* @returns {Metric} The Metric, or null if TimeSeries is not present in
* Metric.
*/
getMetric(): Metric|null;
}

/** Options for every metric added to the MetricRegistry. */
export interface MetricOptions {
/** The description of the metric. */
readonly description?: string;
/** The unit of the metric. */
readonly unit?: MeasureUnit;
/** The list of the label keys. */
readonly labelKeys?: LabelKey[];
/** The map of constant labels for the Metric. */
readonly constantLabels?: Map<LabelKey, LabelValue>;

// TODO(mayurkale): Add resource information.
// https://github.com/census-instrumentation/opencensus-specs/pull/248
}
Loading

0 comments on commit 1853dc9

Please sign in to comment.