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

Commit 645e620

Browse files
authored
Plug-in gauges into the registry and register Metric-Registry with MetricProducer. (#223)
1 parent 7e22f53 commit 645e620

File tree

3 files changed

+243
-24
lines changed

3 files changed

+243
-24
lines changed

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

Lines changed: 103 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,28 @@
1616

1717
import {validateArrayElementsNotNull, validateNotNull} from '../common/validations';
1818
import {MeasureUnit} from '../stats/types';
19-
import {LabelKey} from './export/types';
19+
import {MetricProducer} from './export/metric-producer';
20+
import {LabelKey, Metric, MetricDescriptorType} from './export/types';
21+
import {Gauge} from './gauges/gauge';
22+
import {Meter} from './gauges/types';
2023

2124
/**
2225
* Creates and manages application's set of metrics.
2326
*/
2427
export class MetricRegistry {
28+
private registeredMetrics: Map<string, Meter> = new Map();
29+
private metricProducer: MetricProducer;
30+
31+
private static readonly NAME = 'name';
32+
private static readonly DESCRIPTION = 'description';
33+
private static readonly UNIT = 'unit';
34+
private static readonly LABEL_KEY = 'labelKey';
35+
private static readonly LABEL_KEYS = 'labelKeys';
36+
37+
constructor() {
38+
this.metricProducer = new MetricProducerForRegistry(this.registeredMetrics);
39+
}
40+
2541
/**
2642
* Builds a new Int64 gauge to be added to the registry. This is more
2743
* convenient form when you want to manually increase and decrease values as
@@ -31,16 +47,23 @@ export class MetricRegistry {
3147
* @param {string} description The description of the metric.
3248
* @param {MeasureUnit} unit The unit of the metric.
3349
* @param {LabelKey[]} labelKeys The list of the label keys.
50+
* @returns {Gauge} A Int64 Gauge metric.
3451
*/
3552
addInt64Gauge(
3653
name: string, description: string, unit: MeasureUnit,
37-
labelKeys: LabelKey[]): void {
38-
validateNotNull(name, 'name');
39-
validateNotNull(description, 'description');
40-
validateNotNull(unit, 'unit');
54+
labelKeys: LabelKey[]): Gauge {
4155
validateArrayElementsNotNull(
42-
validateNotNull(labelKeys, 'labelKeys'), 'labelKey');
43-
// TODO(mayurkale): Add Int64Gauge.
56+
validateNotNull(labelKeys, MetricRegistry.LABEL_KEYS),
57+
MetricRegistry.LABEL_KEY);
58+
59+
const labelKeysCopy = Object.assign([], labelKeys);
60+
const int64Gauge = new Gauge(
61+
validateNotNull(name, MetricRegistry.NAME),
62+
validateNotNull(description, MetricRegistry.DESCRIPTION),
63+
validateNotNull(unit, MetricRegistry.UNIT),
64+
MetricDescriptorType.GAUGE_INT64, labelKeysCopy);
65+
this.registerMetric(name, int64Gauge);
66+
return int64Gauge;
4467
}
4568

4669
/**
@@ -52,16 +75,23 @@ export class MetricRegistry {
5275
* @param {string} description The description of the metric.
5376
* @param {MeasureUnit} unit The unit of the metric.
5477
* @param {LabelKey[]} labelKeys The list of the label keys.
78+
* @returns {Gauge} A Double Gauge metric.
5579
*/
5680
addDoubleGauge(
5781
name: string, description: string, unit: MeasureUnit,
58-
labelKeys: LabelKey[]): void {
59-
validateNotNull(name, 'name');
60-
validateNotNull(description, 'description');
61-
validateNotNull(unit, 'unit');
82+
labelKeys: LabelKey[]): Gauge {
6283
validateArrayElementsNotNull(
63-
validateNotNull(labelKeys, 'labelKeys'), 'labelKey');
64-
// TODO(mayurkale): Add DoubleGauge.
84+
validateNotNull(labelKeys, MetricRegistry.LABEL_KEYS),
85+
MetricRegistry.LABEL_KEY);
86+
87+
const labelKeysCopy = Object.assign([], labelKeys);
88+
const doubleGauge = new Gauge(
89+
validateNotNull(name, MetricRegistry.NAME),
90+
validateNotNull(description, MetricRegistry.DESCRIPTION),
91+
validateNotNull(unit, MetricRegistry.UNIT),
92+
MetricDescriptorType.GAUGE_DOUBLE, labelKeysCopy);
93+
this.registerMetric(name, doubleGauge);
94+
return doubleGauge;
6595
}
6696

6797
/**
@@ -77,11 +107,12 @@ export class MetricRegistry {
77107
addDerivedInt64Gauge(
78108
name: string, description: string, unit: MeasureUnit,
79109
labelKeys: LabelKey[]): void {
80-
validateNotNull(name, 'name');
81-
validateNotNull(description, 'description');
82-
validateNotNull(unit, 'unit');
110+
validateNotNull(name, MetricRegistry.NAME);
111+
validateNotNull(description, MetricRegistry.DESCRIPTION);
112+
validateNotNull(unit, MetricRegistry.UNIT);
83113
validateArrayElementsNotNull(
84-
validateNotNull(labelKeys, 'labelKeys'), 'labelKey');
114+
validateNotNull(labelKeys, MetricRegistry.LABEL_KEYS),
115+
MetricRegistry.LABEL_KEY);
85116
// TODO(mayurkale): Add Derived Int64Gauge.
86117
}
87118

@@ -98,11 +129,62 @@ export class MetricRegistry {
98129
addDerivedDoubleGauge(
99130
name: string, description: string, unit: MeasureUnit,
100131
labelKeys: LabelKey[]): void {
101-
validateNotNull(name, 'name');
102-
validateNotNull(description, 'description');
103-
validateNotNull(unit, 'unit');
132+
validateNotNull(name, MetricRegistry.NAME);
133+
validateNotNull(description, MetricRegistry.DESCRIPTION);
134+
validateNotNull(unit, MetricRegistry.UNIT);
104135
validateArrayElementsNotNull(
105-
validateNotNull(labelKeys, 'labelKeys'), 'labelKey');
136+
validateNotNull(labelKeys, MetricRegistry.LABEL_KEYS),
137+
MetricRegistry.LABEL_KEY);
106138
// TODO(mayurkale): Add Derived DoubleGauge.
107139
}
140+
141+
/**
142+
* Registers metric to register.
143+
*
144+
* @param {string} name The name of the metric.
145+
* @param {Meter} meter The metric to register.
146+
*/
147+
private registerMetric(name: string, meter: Meter): void {
148+
if (this.registeredMetrics.has(name)) {
149+
throw new Error(
150+
`A metric with the name ${name} has already been registered.`);
151+
}
152+
this.registeredMetrics.set(name, meter);
153+
}
154+
155+
/**
156+
* Gets a metric producer for registry.
157+
*
158+
* @returns {MetricProducer} The metric producer.
159+
*/
160+
getMetricProducer(): MetricProducer {
161+
return this.metricProducer;
162+
}
163+
}
164+
165+
/**
166+
* A MetricProducerForRegistry is a producer that can be registered for
167+
* exporting using MetricProducerManager.
168+
*
169+
* TODO (mayurkale): Add MetricProducerManager, that Keeps a set of
170+
* MetricProducer that is used by exporters to determine the metrics that
171+
* need to be exported.
172+
*/
173+
class MetricProducerForRegistry extends MetricProducer {
174+
private registeredMetrics: Map<string, Meter>;
175+
176+
constructor(registeredMetrics: Map<string, Meter>) {
177+
super();
178+
this.registeredMetrics = registeredMetrics;
179+
}
180+
181+
/**
182+
* Gets a collection of produced Metric`s to be exported.
183+
*
184+
* @returns {Metric[]} The list of metrics.
185+
*/
186+
getMetrics(): Metric[] {
187+
return Array.from(
188+
this.registeredMetrics, ([_, meter]) => meter.getMetric());
189+
}
108190
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Copyright 2018, 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 {MetricRegistry} from './metric-registry';
18+
19+
export class Metrics {
20+
private static readonly METRIC_REGISTRY = Metrics.newMetricRegistry();
21+
22+
/**
23+
* Returns the global MetricRegistry.
24+
*
25+
* @return {MetricRegistry}.
26+
*/
27+
static getMetricRegistry(): MetricRegistry {
28+
return Metrics.METRIC_REGISTRY;
29+
}
30+
31+
private static newMetricRegistry(): MetricRegistry {
32+
return new MetricRegistry();
33+
}
34+
}

packages/opencensus-core/test/test-metric-registry.ts

Lines changed: 106 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
import * as assert from 'assert';
18-
import {LabelKey} from '../src/metrics/export/types';
18+
import {LabelKey, LabelValue, MetricDescriptorType} from '../src/metrics/export/types';
1919
import {MetricRegistry} from '../src/metrics/metric-registry';
2020
import {MeasureUnit} from '../src/stats/types';
2121

@@ -25,10 +25,21 @@ const UNIT = MeasureUnit.UNIT;
2525
const LABEL_KEYS: LabelKey[] = [{key: 'code', description: 'desc'}];
2626
const LABEL_KEYS_WITH_NULL: LabelKey[] =
2727
[{key: 'code', description: 'desc'}, null];
28-
29-
const registry = new MetricRegistry();
28+
const LABEL_VALUES_200: LabelValue[] = [{value: '200'}];
3029

3130
describe('addInt64Gauge', () => {
31+
const oldProcessHrtime = process.hrtime;
32+
let registry: MetricRegistry;
33+
34+
beforeEach(() => {
35+
registry = new MetricRegistry();
36+
process.hrtime = () => [1000, 1e7];
37+
});
38+
39+
afterEach(() => {
40+
process.hrtime = oldProcessHrtime;
41+
});
42+
3243
it('should throw an error when the name is null', () => {
3344
assert.throws(() => {
3445
registry.addInt64Gauge(null, METRIC_DESCRIPTION, UNIT, LABEL_KEYS);
@@ -76,9 +87,44 @@ describe('addInt64Gauge', () => {
7687
METRIC_NAME, METRIC_DESCRIPTION, UNIT, LABEL_KEYS_WITH_NULL);
7788
}, /^Error: labelKey elements should not be a NULL$/);
7889
});
90+
91+
it('should return a metric', () => {
92+
const int64Gauge = registry.addInt64Gauge(
93+
METRIC_NAME, METRIC_DESCRIPTION, UNIT, LABEL_KEYS);
94+
const pointEntry = int64Gauge.getOrCreateTimeSeries(LABEL_VALUES_200);
95+
pointEntry.add(100);
96+
97+
const metrics = registry.getMetricProducer().getMetrics();
98+
assert.strictEqual(metrics.length, 1);
99+
const [{descriptor, timeseries}] = metrics;
100+
assert.deepStrictEqual(descriptor, {
101+
name: METRIC_NAME,
102+
description: METRIC_DESCRIPTION,
103+
'labelKeys': LABEL_KEYS,
104+
unit: UNIT,
105+
type: MetricDescriptorType.GAUGE_INT64
106+
});
107+
assert.strictEqual(timeseries.length, 1);
108+
const [{points}] = timeseries;
109+
const [point] = points;
110+
assert.equal(point.value, 100);
111+
assert.deepStrictEqual(point.timestamp, {seconds: 1000, nanos: 1e7});
112+
});
79113
});
80114

81115
describe('addDoubleGauge', () => {
116+
const oldProcessHrtime = process.hrtime;
117+
let registry: MetricRegistry;
118+
119+
beforeEach(() => {
120+
registry = new MetricRegistry();
121+
process.hrtime = () => [1000, 1e7];
122+
});
123+
124+
afterEach(() => {
125+
process.hrtime = oldProcessHrtime;
126+
});
127+
82128
it('should throw an error when the name is null', () => {
83129
assert.throws(() => {
84130
registry.addDoubleGauge(null, METRIC_DESCRIPTION, UNIT, LABEL_KEYS);
@@ -127,9 +173,54 @@ describe('addDoubleGauge', () => {
127173
METRIC_NAME, METRIC_DESCRIPTION, UNIT, LABEL_KEYS_WITH_NULL);
128174
}, /^Error: labelKey elements should not be a NULL$/);
129175
});
176+
it('should return a metric', () => {
177+
const int64Gauge = registry.addDoubleGauge(
178+
METRIC_NAME, METRIC_DESCRIPTION, UNIT, LABEL_KEYS);
179+
const pointEntry = int64Gauge.getOrCreateTimeSeries(LABEL_VALUES_200);
180+
pointEntry.add(5.5);
181+
182+
const pointEntry1 = int64Gauge.getOrCreateTimeSeries(LABEL_VALUES_200);
183+
pointEntry1.set(0.7);
184+
185+
const metrics = registry.getMetricProducer().getMetrics();
186+
assert.strictEqual(metrics.length, 1);
187+
const [{descriptor, timeseries}] = metrics;
188+
assert.deepStrictEqual(descriptor, {
189+
name: METRIC_NAME,
190+
description: METRIC_DESCRIPTION,
191+
'labelKeys': LABEL_KEYS,
192+
unit: UNIT,
193+
type: MetricDescriptorType.GAUGE_DOUBLE
194+
});
195+
assert.strictEqual(timeseries.length, 1);
196+
const [{points}] = timeseries;
197+
const [point] = points;
198+
assert.equal(point.value, 0.7);
199+
assert.deepStrictEqual(point.timestamp, {seconds: 1000, nanos: 1e7});
200+
});
201+
202+
it('should throw an error when the register same metric', () => {
203+
registry.addDoubleGauge(METRIC_NAME, METRIC_DESCRIPTION, UNIT, LABEL_KEYS);
204+
assert.throws(() => {
205+
registry.addDoubleGauge(
206+
METRIC_NAME, METRIC_DESCRIPTION, UNIT, LABEL_KEYS);
207+
}, /^Error: A metric with the name metric-name has already been registered.$/);
208+
});
130209
});
131210

132211
describe('addDerivedInt64Gauge', () => {
212+
const oldProcessHrtime = process.hrtime;
213+
let registry: MetricRegistry;
214+
215+
beforeEach(() => {
216+
registry = new MetricRegistry();
217+
process.hrtime = () => [1000, 1e7];
218+
});
219+
220+
afterEach(() => {
221+
process.hrtime = oldProcessHrtime;
222+
});
223+
133224
it('should throw an error when the name is null', () => {
134225
assert.throws(() => {
135226
registry.addDerivedInt64Gauge(null, METRIC_DESCRIPTION, UNIT, LABEL_KEYS);
@@ -184,6 +275,18 @@ describe('addDerivedInt64Gauge', () => {
184275
});
185276

186277
describe('addDerivedDoubleGauge', () => {
278+
const oldProcessHrtime = process.hrtime;
279+
let registry: MetricRegistry;
280+
281+
beforeEach(() => {
282+
registry = new MetricRegistry();
283+
process.hrtime = () => [1000, 1e7];
284+
});
285+
286+
afterEach(() => {
287+
process.hrtime = oldProcessHrtime;
288+
});
289+
187290
it('should throw an error when the name is null', () => {
188291
assert.throws(() => {
189292
registry.addDerivedDoubleGauge(

0 commit comments

Comments
 (0)