Skip to content

Commit 17cf8b8

Browse files
committed
Metrics: Add lastUpdateTimestamp associated with point
1 parent 584eeab commit 17cf8b8

File tree

5 files changed

+99
-56
lines changed

5 files changed

+99
-56
lines changed

packages/opentelemetry-exporter-prometheus/src/prometheus.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
import { ExportResult } from '@opentelemetry/base';
18-
import { NoopLogger } from '@opentelemetry/core';
18+
import { NoopLogger, hrTimeToMilliseconds } from '@opentelemetry/core';
1919
import {
2020
CounterSumAggregator,
2121
LastValue,
@@ -124,27 +124,30 @@ export class PrometheusExporter implements MetricExporter {
124124
if (!metric) return;
125125

126126
const labelKeys = record.descriptor.labelKeys;
127-
const value = record.aggregator.value();
127+
const point = record.aggregator.toPoint();
128128

129129
if (metric instanceof Counter) {
130130
// Prometheus counter saves internal state and increments by given value.
131131
// MetricRecord value is the current state, not the delta to be incremented by.
132132
// Currently, _registerMetric creates a new counter every time the value changes,
133133
// so the increment here behaves as a set value (increment from 0)
134-
metric.inc(this._getLabelValues(labelKeys, record.labels), value as Sum);
134+
metric.inc(
135+
this._getLabelValues(labelKeys, record.labels),
136+
point.value as Sum
137+
);
135138
}
136139

137140
if (metric instanceof Gauge) {
138141
if (record.aggregator instanceof CounterSumAggregator) {
139142
metric.set(
140143
this._getLabelValues(labelKeys, record.labels),
141-
value as Sum
144+
point.value as Sum
142145
);
143146
} else if (record.aggregator instanceof ObserverAggregator) {
144147
metric.set(
145148
this._getLabelValues(labelKeys, record.labels),
146-
value as LastValue,
147-
new Date()
149+
point.value as LastValue,
150+
hrTimeToMilliseconds(point.timestamp)
148151
);
149152
}
150153
}

packages/opentelemetry-metrics/src/export/Aggregator.ts

+23-7
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,50 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { Aggregator, Distribution, LastValue, Sum } from './types';
17+
import { Aggregator, Distribution, Point } from './types';
18+
import { HrTime } from '@opentelemetry/api';
19+
import { hrTime } from '@opentelemetry/core';
1820

1921
/** Basic aggregator which calculates a Sum from individual measurements. */
2022
export class CounterSumAggregator implements Aggregator {
2123
private _current: number = 0;
24+
private _lastUpdateTime: HrTime = [0, 0];
2225

2326
update(value: number): void {
2427
this._current += value;
28+
this._lastUpdateTime = hrTime();
2529
}
2630

27-
value(): Sum {
28-
return this._current;
31+
toPoint(): Point {
32+
return {
33+
value: this._current,
34+
timestamp: this._lastUpdateTime,
35+
};
2936
}
3037
}
3138

3239
/** Basic aggregator for Observer which keeps the last recorded value. */
3340
export class ObserverAggregator implements Aggregator {
3441
private _current: number = 0;
42+
private _lastUpdateTime: HrTime = [0, 0];
3543

3644
update(value: number): void {
3745
this._current = value;
46+
this._lastUpdateTime = hrTime();
3847
}
3948

40-
value(): LastValue {
41-
return this._current;
49+
toPoint(): Point {
50+
return {
51+
value: this._current,
52+
timestamp: this._lastUpdateTime,
53+
};
4254
}
4355
}
4456

4557
/** Basic aggregator keeping all raw values (events, sum, max and min). */
4658
export class MeasureExactAggregator implements Aggregator {
4759
private _distribution: Distribution;
60+
private _lastUpdateTime: HrTime = [0, 0];
4861

4962
constructor() {
5063
this._distribution = {
@@ -62,7 +75,10 @@ export class MeasureExactAggregator implements Aggregator {
6275
this._distribution.max = Math.max(this._distribution.max, value);
6376
}
6477

65-
value(): Distribution {
66-
return this._distribution;
78+
toPoint(): Point {
79+
return {
80+
value: this._distribution,
81+
timestamp: this._lastUpdateTime,
82+
};
6783
}
6884
}

packages/opentelemetry-metrics/src/export/ConsoleMetricExporter.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@ export class ConsoleMetricExporter implements MetricExporter {
3737
console.log(metric.labels.labels);
3838
switch (metric.descriptor.metricKind) {
3939
case MetricKind.COUNTER:
40-
const sum = metric.aggregator.value() as Sum;
40+
const sum = metric.aggregator.toPoint().value as Sum;
4141
console.log('value: ' + sum);
4242
break;
4343
default:
44-
const distribution = metric.aggregator.value() as Distribution;
44+
const distribution = metric.aggregator.toPoint()
45+
.value as Distribution;
4546
console.log(
4647
'min: ' +
4748
distribution.min +

packages/opentelemetry-metrics/src/export/types.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { ValueType } from '@opentelemetry/api';
17+
import { ValueType, HrTime } from '@opentelemetry/api';
1818
import { ExportResult } from '@opentelemetry/base';
1919
import { LabelSet } from '../LabelSet';
2020

@@ -76,6 +76,11 @@ export interface Aggregator {
7676
/** Updates the current with the new value. */
7777
update(value: number): void;
7878

79-
/** Returns snapshot of the current value. */
80-
value(): Sum | Distribution;
79+
/** Returns snapshot of the current point (value with timestamp). */
80+
toPoint(): Point;
81+
}
82+
83+
export interface Point {
84+
value: Sum | LastValue | Distribution;
85+
timestamp: HrTime;
8186
}

packages/opentelemetry-metrics/test/Meter.test.ts

+56-38
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ describe('Meter', () => {
8484
meter.collect();
8585
const [record1] = meter.getBatcher().checkPointSet();
8686

87-
assert.strictEqual(record1.aggregator.value(), 10);
87+
assert.strictEqual(record1.aggregator.toPoint().value, 10);
8888
counter.add(10, labelSet);
89-
assert.strictEqual(record1.aggregator.value(), 20);
89+
assert.strictEqual(record1.aggregator.toPoint().value, 20);
9090
});
9191

9292
it('should return counter with resource', () => {
@@ -102,9 +102,9 @@ describe('Meter', () => {
102102
meter.collect();
103103
const [record1] = meter.getBatcher().checkPointSet();
104104

105-
assert.strictEqual(record1.aggregator.value(), 10);
105+
assert.strictEqual(record1.aggregator.toPoint().value, 10);
106106
boundCounter.add(10);
107-
assert.strictEqual(record1.aggregator.value(), 20);
107+
assert.strictEqual(record1.aggregator.toPoint().value, 20);
108108
});
109109

110110
it('should return the aggregator', () => {
@@ -123,9 +123,9 @@ describe('Meter', () => {
123123
meter.collect();
124124
const [record1] = meter.getBatcher().checkPointSet();
125125

126-
assert.strictEqual(record1.aggregator.value(), 10);
126+
assert.strictEqual(record1.aggregator.toPoint().value, 10);
127127
boundCounter.add(-100);
128-
assert.strictEqual(record1.aggregator.value(), 10);
128+
assert.strictEqual(record1.aggregator.toPoint().value, 10);
129129
});
130130

131131
it('should not add the instrument data when disabled', () => {
@@ -136,7 +136,7 @@ describe('Meter', () => {
136136
boundCounter.add(10);
137137
meter.collect();
138138
const [record1] = meter.getBatcher().checkPointSet();
139-
assert.strictEqual(record1.aggregator.value(), 0);
139+
assert.strictEqual(record1.aggregator.toPoint().value, 0);
140140
});
141141

142142
it('should add negative value when monotonic is set to false', () => {
@@ -147,7 +147,7 @@ describe('Meter', () => {
147147
boundCounter.add(-10);
148148
meter.collect();
149149
const [record1] = meter.getBatcher().checkPointSet();
150-
assert.strictEqual(record1.aggregator.value(), -10);
150+
assert.strictEqual(record1.aggregator.toPoint().value, -10);
151151
});
152152

153153
it('should return same instrument on same label values', () => {
@@ -159,7 +159,7 @@ describe('Meter', () => {
159159
meter.collect();
160160
const [record1] = meter.getBatcher().checkPointSet();
161161

162-
assert.strictEqual(record1.aggregator.value(), 20);
162+
assert.strictEqual(record1.aggregator.toPoint().value, 20);
163163
assert.strictEqual(boundCounter, boundCounter1);
164164
});
165165
});
@@ -214,7 +214,7 @@ describe('Meter', () => {
214214
unit: '1',
215215
valueType: ValueType.DOUBLE,
216216
});
217-
assert.strictEqual(record[0].aggregator.value(), 10);
217+
assert.strictEqual(record[0].aggregator.toPoint().value, 10);
218218
});
219219
});
220220

@@ -319,12 +319,15 @@ describe('Meter', () => {
319319

320320
meter.collect();
321321
const [record1] = meter.getBatcher().checkPointSet();
322-
assert.deepStrictEqual(record1.aggregator.value() as Distribution, {
323-
count: 0,
324-
max: -Infinity,
325-
min: Infinity,
326-
sum: 0,
327-
});
322+
assert.deepStrictEqual(
323+
record1.aggregator.toPoint().value as Distribution,
324+
{
325+
count: 0,
326+
max: -Infinity,
327+
min: Infinity,
328+
sum: 0,
329+
}
330+
);
328331
});
329332

330333
it('should not set the instrument data when disabled', () => {
@@ -336,12 +339,15 @@ describe('Meter', () => {
336339

337340
meter.collect();
338341
const [record1] = meter.getBatcher().checkPointSet();
339-
assert.deepStrictEqual(record1.aggregator.value() as Distribution, {
340-
count: 0,
341-
max: -Infinity,
342-
min: Infinity,
343-
sum: 0,
344-
});
342+
assert.deepStrictEqual(
343+
record1.aggregator.toPoint().value as Distribution,
344+
{
345+
count: 0,
346+
max: -Infinity,
347+
min: Infinity,
348+
sum: 0,
349+
}
350+
);
345351
});
346352

347353
it('should accept negative (and positive) values when absolute is set to false', () => {
@@ -354,12 +360,15 @@ describe('Meter', () => {
354360

355361
meter.collect();
356362
const [record1] = meter.getBatcher().checkPointSet();
357-
assert.deepStrictEqual(record1.aggregator.value() as Distribution, {
358-
count: 2,
359-
max: 50,
360-
min: -10,
361-
sum: 40,
362-
});
363+
assert.deepStrictEqual(
364+
record1.aggregator.toPoint().value as Distribution,
365+
{
366+
count: 2,
367+
max: 50,
368+
min: -10,
369+
sum: 40,
370+
}
371+
);
363372
});
364373

365374
it('should return same instrument on same label values', () => {
@@ -370,12 +379,15 @@ describe('Meter', () => {
370379
boundMeasure2.record(100);
371380
meter.collect();
372381
const [record1] = meter.getBatcher().checkPointSet();
373-
assert.deepStrictEqual(record1.aggregator.value() as Distribution, {
374-
count: 2,
375-
max: 100,
376-
min: 10,
377-
sum: 110,
378-
});
382+
assert.deepStrictEqual(
383+
record1.aggregator.toPoint().value as Distribution,
384+
{
385+
count: 2,
386+
max: 100,
387+
min: 10,
388+
sum: 110,
389+
}
390+
);
379391
assert.strictEqual(boundMeasure1, boundMeasure2);
380392
});
381393
});
@@ -500,7 +512,7 @@ describe('Meter', () => {
500512
labelKeys: ['key'],
501513
});
502514
assert.strictEqual(record[0].labels, labelSet);
503-
const value = record[0].aggregator.value() as Sum;
515+
const value = record[0].aggregator.toPoint().value as Sum;
504516
assert.strictEqual(value, 10.45);
505517
});
506518

@@ -529,16 +541,22 @@ describe('Meter', () => {
529541
labelKeys: ['key'],
530542
});
531543
assert.strictEqual(record[0].labels, labelSet);
532-
const value = record[0].aggregator.value() as Sum;
544+
const value = record[0].aggregator.toPoint().value as Sum;
533545
assert.strictEqual(value, 10);
534546
});
535547
});
536548
});
537549

538550
function ensureMetric(metric: MetricRecord) {
539551
assert.ok(metric.aggregator instanceof ObserverAggregator);
540-
assert.ok(metric.aggregator.value() >= 0 && metric.aggregator.value() <= 1);
541-
assert.ok(metric.aggregator.value() >= 0 && metric.aggregator.value() <= 1);
552+
assert.ok(
553+
metric.aggregator.toPoint().value >= 0 &&
554+
metric.aggregator.toPoint().value <= 1
555+
);
556+
assert.ok(
557+
metric.aggregator.toPoint().value >= 0 &&
558+
metric.aggregator.toPoint().value <= 1
559+
);
542560
const descriptor = metric.descriptor;
543561
assert.strictEqual(descriptor.name, 'name');
544562
assert.strictEqual(descriptor.description, 'desc');

0 commit comments

Comments
 (0)