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

Commit 1853dc9

Browse files
authored
Add support for Cumulative API (#480)
* Add support for Cumulative API * Handle NaN and add test * Add comments for getMetric() method
1 parent abd41db commit 1853dc9

9 files changed

Lines changed: 591 additions & 30 deletions

File tree

packages/opencensus-core/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ export * from './common/version';
7171
export * from './metrics/metrics';
7272
export * from './metrics/metric-registry';
7373

74+
// Cumulative CLASSES
75+
export * from './metrics/cumulative/cumulative';
76+
7477
// GAUGES CLASSES
7578
export * from './metrics/gauges/derived-gauge';
7679
export * from './metrics/gauges/gauge';
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/**
2+
* Copyright 2019, OpenCensus Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {getTimestampWithProcessHRTime} from '../../common/time-util';
18+
import {validateArrayElementsNotNull, validateNotNull} from '../../common/validations';
19+
import {LabelKey, LabelValue, Metric, MetricDescriptor, MetricDescriptorType, TimeSeries, Timestamp} from '../export/types';
20+
import {Meter} from '../types';
21+
import {hashLabelValues, initializeDefaultLabels} from '../utils';
22+
import {CumulativePoint} from './types';
23+
24+
/**
25+
* Cumulative metric is used to record aggregated metrics that represents a
26+
* single numerical value accumulated over a time interval. The value can only
27+
* increase or be reset to zero on restart or reset the event.
28+
*/
29+
export class Cumulative implements Meter {
30+
private readonly metricDescriptor: MetricDescriptor;
31+
private labelKeysLength: number;
32+
private defaultLabelValues: LabelValue[];
33+
private registeredPoints: Map<string, CumulativePoint> = new Map();
34+
private readonly constantLabelValues: LabelValue[];
35+
36+
/**
37+
* Constructs a new Cumulative instance.
38+
*
39+
* @param {string} name The name of the metric.
40+
* @param {string} description The description of the metric.
41+
* @param {string} unit The unit of the metric.
42+
* @param {MetricDescriptorType} type The type of metric.
43+
* @param {LabelKey[]} labelKeys The list of the label keys.
44+
* @param {Map<LabelKey, LabelValue>} constantLabels The map of constant
45+
* labels for the Metric.
46+
*/
47+
constructor(
48+
name: string, description: string, unit: string,
49+
type: MetricDescriptorType, readonly labelKeys: LabelKey[],
50+
readonly constantLabels: Map<LabelKey, LabelValue>) {
51+
this.labelKeysLength = labelKeys.length;
52+
const keysAndConstantKeys = [...labelKeys, ...constantLabels.keys()];
53+
this.constantLabelValues = [...constantLabels.values()];
54+
55+
this.metricDescriptor =
56+
{name, description, unit, type, labelKeys: keysAndConstantKeys};
57+
this.defaultLabelValues = initializeDefaultLabels(this.labelKeysLength);
58+
}
59+
60+
/**
61+
* Creates a TimeSeries and returns a Point if the specified
62+
* labelValues is not already associated with this cumulative, else returns an
63+
* existing Point.
64+
*
65+
* It is recommended to keep a reference to the Point instead of always
66+
* calling this method for manual operations.
67+
*
68+
* @param {LabelValue[]} labelValues The list of the label values.
69+
* @returns {CumulativePoint} The value of single cumulative.
70+
*/
71+
getOrCreateTimeSeries(labelValues: LabelValue[]): CumulativePoint {
72+
validateArrayElementsNotNull(
73+
validateNotNull(labelValues, 'labelValues'), 'labelValue');
74+
return this.registerTimeSeries(labelValues);
75+
}
76+
77+
/**
78+
* Returns a Point for a cumulative with all labels not set, or default
79+
* labels.
80+
*
81+
* @returns {CumulativePoint} The value of single cumulative.
82+
*/
83+
getDefaultTimeSeries(): CumulativePoint {
84+
return this.registerTimeSeries(this.defaultLabelValues);
85+
}
86+
87+
/**
88+
* Removes the TimeSeries from the cumulative metric, if it is present. i.e.
89+
* references to previous Point objects are invalid (not part of the
90+
* metric).
91+
*
92+
* @param {LabelValue[]} labelValues The list of label values.
93+
*/
94+
removeTimeSeries(labelValues: LabelValue[]): void {
95+
validateNotNull(labelValues, 'labelValues');
96+
this.registeredPoints.delete(hashLabelValues(labelValues));
97+
}
98+
99+
/**
100+
* Removes all TimeSeries from the cumulative metric. i.e. references to all
101+
* previous Point objects are invalid (not part of the metric).
102+
*/
103+
clear(): void {
104+
this.registeredPoints.clear();
105+
}
106+
107+
/**
108+
* Registers a TimeSeries and returns a Point if the specified
109+
* labelValues is not already associated with this cumulative, else returns an
110+
* existing Point.
111+
*
112+
* @param {LabelValue[]} labelValues The list of the label values.
113+
* @returns {CumulativePoint} The value of single cumulative.
114+
*/
115+
private registerTimeSeries(labelValues: LabelValue[]): CumulativePoint {
116+
const hash = hashLabelValues(labelValues);
117+
// return if the specified labelValues is already associated with the point.
118+
if (this.registeredPoints.has(hash)) {
119+
return this.registeredPoints.get(hash)!;
120+
}
121+
if (this.labelKeysLength !== labelValues.length) {
122+
throw new Error('Label Keys and Label Values don\'t have same size');
123+
}
124+
125+
const point =
126+
new CumulativePointEntry([...labelValues, ...this.constantLabelValues]);
127+
this.registeredPoints.set(hash, point);
128+
return point;
129+
}
130+
131+
/**
132+
* Provides a Metric with one or more TimeSeries.
133+
*
134+
* @returns {Metric} The Metric, or null if TimeSeries is not present in
135+
* Metric.
136+
*/
137+
getMetric(): Metric|null {
138+
if (this.registeredPoints.size === 0) {
139+
return null;
140+
}
141+
const now: Timestamp = getTimestampWithProcessHRTime();
142+
return {
143+
descriptor: this.metricDescriptor,
144+
timeseries: Array.from(
145+
this.registeredPoints, ([_, point]) => point.getTimeSeries(now))
146+
};
147+
}
148+
}
149+
150+
/**
151+
* The value of a single point in the Cumulative.TimeSeries.
152+
*/
153+
export class CumulativePointEntry implements CumulativePoint {
154+
private readonly labelValues: LabelValue[];
155+
private startTimestamp: Timestamp;
156+
private value = 0;
157+
158+
constructor(labelValues: LabelValue[]) {
159+
this.labelValues = labelValues;
160+
this.startTimestamp = getTimestampWithProcessHRTime();
161+
}
162+
163+
/** Reset cumulative metric. */
164+
reset(): void {
165+
this.value = 0;
166+
this.startTimestamp = getTimestampWithProcessHRTime();
167+
}
168+
169+
/**
170+
* Increment the cumulative metric.
171+
* @param {number} val The new value.
172+
*/
173+
inc(val?: number): void {
174+
if ((val && !Number.isFinite(val)) || (val !== undefined && isNaN(val))) {
175+
throw new TypeError(`Value is not a valid number: ${val}`);
176+
}
177+
if (val && val < 0) {
178+
throw new Error('It is not possible to decrease a cumulative metric');
179+
}
180+
const incValue = (val === null || val === undefined) ? 1 : val;
181+
this.value += incValue;
182+
}
183+
184+
/**
185+
* Returns the TimeSeries with one or more Point.
186+
*
187+
* @param {Timestamp} now The time at which the cumulative is recorded.
188+
* @returns {TimeSeries} The TimeSeries.
189+
*/
190+
getTimeSeries(now: Timestamp): TimeSeries {
191+
return {
192+
labelValues: this.labelValues,
193+
points: [{value: this.value, timestamp: now}],
194+
startTimestamp: this.startTimestamp
195+
};
196+
}
197+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright 2019, OpenCensus Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {TimeSeries, Timestamp} from '../export/types';
18+
19+
export interface CumulativePoint {
20+
/** Reset cumulative metric. */
21+
reset(): void;
22+
23+
/**
24+
* Increment the cumulative metric.
25+
* @param {number} val The new value.
26+
*/
27+
inc(val?: number): void;
28+
29+
/**
30+
* Returns the TimeSeries with one or more Point.
31+
*
32+
* @param {Timestamp} now The time at which the cumulative is recorded.
33+
* @returns {TimeSeries} The TimeSeries.
34+
*/
35+
getTimeSeries(now: Timestamp): TimeSeries;
36+
}

packages/opencensus-core/src/metrics/gauges/derived-gauge.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import {getTimestampWithProcessHRTime} from '../../common/time-util';
1818
import {validateArrayElementsNotNull, validateNotNull} from '../../common/validations';
1919
import {LabelKey, LabelValue, Metric, MetricDescriptor, MetricDescriptorType, TimeSeries, Timestamp} from '../export/types';
20-
import * as types from '../gauges/types';
20+
import * as types from '../types';
2121
import {hashLabelValues} from '../utils';
2222

2323
/**

packages/opencensus-core/src/metrics/gauges/gauge.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
import {getTimestampWithProcessHRTime} from '../../common/time-util';
1818
import {validateArrayElementsNotNull, validateNotNull} from '../../common/validations';
1919
import {LabelKey, LabelValue, Metric, MetricDescriptor, MetricDescriptorType, TimeSeries, Timestamp} from '../export/types';
20-
import * as types from '../gauges/types';
20+
import {Meter} from '../types';
2121
import {hashLabelValues, initializeDefaultLabels} from '../utils';
22+
import * as types from './types';
2223

2324
/**
2425
* Gauge metric
2526
*/
26-
export class Gauge implements types.Meter {
27+
export class Gauge implements Meter {
2728
private readonly metricDescriptor: MetricDescriptor;
2829
private labelKeysLength: number;
2930
private defaultLabelValues: LabelValue[];

packages/opencensus-core/src/metrics/gauges/types.ts

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import {MeasureUnit} from '../../stats/types';
18-
import {LabelKey, LabelValue, Metric, TimeSeries, Timestamp} from '../export/types';
19-
20-
export interface Meter {
21-
/**
22-
* Provides a Metric with one or more TimeSeries.
23-
*
24-
* @returns {Metric} The Metric.
25-
*/
26-
getMetric(): Metric|null;
27-
}
17+
import {TimeSeries, Timestamp} from '../export/types';
2818

2919
export interface Point {
3020
/**
@@ -49,18 +39,3 @@ export interface Point {
4939
*/
5040
getTimeSeries(timestamp: Timestamp): TimeSeries;
5141
}
52-
53-
/** Options for every metric added to the MetricRegistry. */
54-
export interface MetricOptions {
55-
/** The description of the metric. */
56-
readonly description?: string;
57-
/** The unit of the metric. */
58-
readonly unit?: MeasureUnit;
59-
/** The list of the label keys. */
60-
readonly labelKeys?: LabelKey[];
61-
/** The map of constant labels for the Metric. */
62-
readonly constantLabels?: Map<LabelKey, LabelValue>;
63-
64-
// TODO(mayurkale): Add resource information.
65-
// https://github.com/census-instrumentation/opencensus-specs/pull/248
66-
}

packages/opencensus-core/src/metrics/metric-registry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {BaseMetricProducer} from './export/base-metric-producer';
2020
import {Metric, MetricDescriptorType, MetricProducer} from './export/types';
2121
import {DerivedGauge} from './gauges/derived-gauge';
2222
import {Gauge} from './gauges/gauge';
23-
import {Meter, MetricOptions} from './gauges/types';
23+
import {Meter, MetricOptions} from './types';
2424

2525
/**
2626
* Creates and manages application's set of metrics.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Copyright 2019, OpenCensus Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {MeasureUnit} from './../stats/types';
18+
import {LabelKey, LabelValue, Metric} from './export/types';
19+
20+
/** Provides a {@link Metric} with one or more {@link TimeSeries} */
21+
export interface Meter {
22+
/**
23+
* Provides a Metric with one or more TimeSeries.
24+
*
25+
* @returns {Metric} The Metric, or null if TimeSeries is not present in
26+
* Metric.
27+
*/
28+
getMetric(): Metric|null;
29+
}
30+
31+
/** Options for every metric added to the MetricRegistry. */
32+
export interface MetricOptions {
33+
/** The description of the metric. */
34+
readonly description?: string;
35+
/** The unit of the metric. */
36+
readonly unit?: MeasureUnit;
37+
/** The list of the label keys. */
38+
readonly labelKeys?: LabelKey[];
39+
/** The map of constant labels for the Metric. */
40+
readonly constantLabels?: Map<LabelKey, LabelValue>;
41+
42+
// TODO(mayurkale): Add resource information.
43+
// https://github.com/census-instrumentation/opencensus-specs/pull/248
44+
}

0 commit comments

Comments
 (0)