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

Commit 1b03ba7

Browse files
authored
Derived Gauge: Add support for extracting value from a function (#469)
* Derived Gauge: Add support for extracting value from a function * fix review comment * Add new type ValueExtractorOrFunction * Add strongly-typed function
1 parent 9235b50 commit 1b03ba7

File tree

3 files changed

+76
-21
lines changed

3 files changed

+76
-21
lines changed

examples/gauge/derived-gauge-quickstart.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const { Metrics, MeasureUnit } = require('@opencensus/core');
3232
// To instrument a queue's depth.
3333
class QueueManager {
3434
constructor () { this.depth = 0; }
35-
getValue () { return this.depth; }
35+
getPendingJobs () { return this.depth; }
3636
addJob () { this.depth++; }
3737
}
3838

@@ -54,6 +54,6 @@ const gauge = metricRegistry.addDerivedInt64Gauge('active_handles_total', metric
5454
const queue = new QueueManager();
5555
queue.addJob();
5656

57-
// The value of the gauge is observed from the obj whenever metrics are
57+
// The value of the gauge is observed from a function whenever metrics are
5858
// collected. In this case it will be 1.
59-
gauge.createTimeSeries(labelValues, queue);
59+
gauge.createTimeSeries(labelValues, () => queue.getPendingJobs());

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

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,13 @@ interface GaugeEntry {
6262
readonly extractor: ValueExtractor;
6363
}
6464

65-
export type AccessorInterface = LengthAttributeInterface|LengthMethodInterface|
66-
SizeAttributeInterface|SizeMethodInterface|ToValueInterface;
65+
interface AccessorFunction {
66+
(): number;
67+
}
68+
69+
export type AccessorInterface =
70+
LengthAttributeInterface|LengthMethodInterface|SizeAttributeInterface|
71+
SizeMethodInterface|ToValueInterface|AccessorFunction;
6772

6873
/**
6974
* DerivedGauge metric
@@ -145,19 +150,23 @@ export class DerivedGauge implements types.Meter {
145150

146151
/**
147152
* Creates a TimeSeries. The value of a single point in the TimeSeries is
148-
* observed from a obj. The ValueExtractor is invoked whenever
153+
* observed from a obj or a function. The ValueExtractor is invoked whenever
149154
* metrics are collected, meaning the reported value is up-to-date.
150155
*
151156
* @param {LabelValue[]} labelValues The list of the label values.
152-
* @param obj The obj to get the size or length or value from. If multiple
153-
* options are available, the value (ToValueInterface) takes precedence
154-
* first, followed by length and size. e.g value -> length -> size.
157+
* @param objOrFn obj The obj to get the size or length or value from. If
158+
* multiple options are available, the value (ToValueInterface) takes
159+
* precedence first, followed by length and size. e.g value -> length ->
160+
* size.
161+
* fn is the function that will be called to get the current value
162+
* of the gauge.
155163
*/
156-
createTimeSeries(labelValues: LabelValue[], obj: AccessorInterface): void {
164+
createTimeSeries(labelValues: LabelValue[], objOrFn: AccessorInterface):
165+
void {
157166
validateArrayElementsNotNull(
158167
validateNotNull(labelValues, DerivedGauge.LABEL_VALUES),
159168
DerivedGauge.LABEL_VALUE);
160-
validateNotNull(obj, DerivedGauge.OBJECT);
169+
validateNotNull(objOrFn, DerivedGauge.OBJECT);
161170

162171
const hash = hashLabelValues(labelValues);
163172
if (this.registeredPoints.has(hash)) {
@@ -167,16 +176,18 @@ export class DerivedGauge implements types.Meter {
167176
throw new Error(DerivedGauge.ERROR_MESSAGE_INVALID_SIZE);
168177
}
169178

170-
if (DerivedGauge.isToValueInterface(obj)) {
171-
this.extractor = () => obj.getValue();
172-
} else if (DerivedGauge.isLengthAttributeInterface(obj)) {
173-
this.extractor = () => obj.length;
174-
} else if (DerivedGauge.isLengthMethodInterface(obj)) {
175-
this.extractor = () => obj.length();
176-
} else if (DerivedGauge.isSizeAttributeInterface(obj)) {
177-
this.extractor = () => obj.size;
178-
} else if (DerivedGauge.isSizeMethodInterface(obj)) {
179-
this.extractor = () => obj.size();
179+
if (objOrFn instanceof Function) {
180+
this.extractor = objOrFn;
181+
} else if (DerivedGauge.isToValueInterface(objOrFn)) {
182+
this.extractor = () => objOrFn.getValue();
183+
} else if (DerivedGauge.isLengthAttributeInterface(objOrFn)) {
184+
this.extractor = () => objOrFn.length;
185+
} else if (DerivedGauge.isLengthMethodInterface(objOrFn)) {
186+
this.extractor = () => objOrFn.length();
187+
} else if (DerivedGauge.isSizeAttributeInterface(objOrFn)) {
188+
this.extractor = () => objOrFn.size;
189+
} else if (DerivedGauge.isSizeMethodInterface(objOrFn)) {
190+
this.extractor = () => objOrFn.size();
180191
} else {
181192
throw new Error(DerivedGauge.ERROR_MESSAGE_UNKNOWN_INTERFACE);
182193
}

packages/opencensus-core/test/test-derived-gauge.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,50 @@ describe('DerivedGauge', () => {
143143
}]
144144
}]);
145145
});
146+
147+
it('should return a Metric value from a function', () => {
148+
class QueueManager {
149+
private depth = 0;
150+
get pendingJobs() {
151+
return this.depth;
152+
}
153+
addJob() {
154+
this.depth++;
155+
}
156+
}
157+
const queue = new QueueManager();
158+
queue.addJob();
159+
instance.createTimeSeries(LABEL_VALUES_200, () => {
160+
return queue.pendingJobs;
161+
});
162+
163+
let metric = instance.getMetric();
164+
assert.notEqual(metric, null);
165+
assert.deepStrictEqual(metric!.descriptor, expectedMetricDescriptor);
166+
assert.equal(metric!.timeseries.length, 1);
167+
assert.deepStrictEqual(
168+
metric!.timeseries, [{
169+
labelValues: LABEL_VALUES_200,
170+
points: [{
171+
value: 1,
172+
timestamp:
173+
{nanos: mockedTime.nanos, seconds: mockedTime.seconds}
174+
}]
175+
}]);
176+
// Simulate a adding multiple jobs in queue
177+
queue.addJob();
178+
queue.addJob();
179+
queue.addJob();
180+
metric = instance.getMetric();
181+
assert.equal(metric!.timeseries.length, 1);
182+
assert.deepStrictEqual(
183+
metric!.timeseries[0].points, [{
184+
value: 4,
185+
timestamp:
186+
{nanos: mockedTime.nanos, seconds: mockedTime.seconds}
187+
}]);
188+
});
189+
146190
it('should return a Metric (Double) - custom object', () => {
147191
class QueueManager {
148192
getValue(): number {

0 commit comments

Comments
 (0)