Skip to content

Commit 0a77ca1

Browse files
Pigrabbitzbjornson
authored andcommitted
feat: implement startTimerWithExemplar
1 parent 15767e3 commit 0a77ca1

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

lib/histogram.js

+27-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ class Histogram extends Metric {
2424
this.type = 'histogram';
2525
this.defaultLabels = {};
2626
this.defaultExemplarLabelSet = {};
27+
this.enableExemplars = false;
2728

2829
if (config.enableExemplars) {
30+
this.enableExemplars = true;
2931
this.observe = this.observeWithExemplar;
3032
} else {
3133
this.observe = this.observeWithoutExemplar;
@@ -143,6 +145,7 @@ class Histogram extends Metric {
143145
/**
144146
* Start a timer that could be used to logging durations
145147
* @param {object} labels - Object with labels where key is the label key and value is label value. Can only be one level deep
148+
* @param {object} exemplarLabels - Object with labels for exemplar where key is the label key and value is label value. Can only be one level deep
146149
* @returns {function} - Function to invoke when you want to stop the timer and observe the duration in seconds
147150
* @example
148151
* var end = histogram.startTimer();
@@ -151,8 +154,10 @@ class Histogram extends Metric {
151154
* console.log('Duration', duration);
152155
* });
153156
*/
154-
startTimer(labels) {
155-
return startTimer.call(this, labels)();
157+
startTimer(labels, exemplarLabels) {
158+
return this.enableExemplars
159+
? startTimerWithExemplar.call(this, labels, exemplarLabels)()
160+
: startTimer.call(this, labels)();
156161
}
157162

158163
labels(...args) {
@@ -183,6 +188,26 @@ function startTimer(startLabels) {
183188
};
184189
}
185190

191+
function startTimerWithExemplar(startLabels, startExemplarLabels) {
192+
return () => {
193+
const start = process.hrtime();
194+
return (endLabels, endExemplarLabels) => {
195+
const delta = process.hrtime(start);
196+
const value = delta[0] + delta[1] / 1e9;
197+
this.observe({
198+
labels: Object.assign({}, startLabels, endLabels),
199+
value,
200+
exemplarLabels: Object.assign(
201+
{},
202+
startExemplarLabels,
203+
endExemplarLabels,
204+
),
205+
});
206+
return value;
207+
};
208+
};
209+
}
210+
186211
function setValuePair(labels, value, metricName, exemplar, sharedLabels = {}) {
187212
return {
188213
labels,

test/exemplarsTest.js

+25
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,31 @@ describe('Exemplars', () => {
147147
jest.useRealTimers();
148148
});
149149

150+
it('should allow exemplar labels before and after timers', async () => {
151+
jest.useFakeTimers('modern');
152+
jest.setSystemTime(0);
153+
const histogramInstance = new Histogram({
154+
name: 'histogram_start_timer_exemplar_label_test',
155+
help: 'test',
156+
labelNames: ['method', 'code'],
157+
enableExemplars: true,
158+
});
159+
const end = histogramInstance.startTimer(
160+
{ method: 'get' },
161+
{ traceId: 'trace_id_test_1' },
162+
);
163+
164+
jest.advanceTimersByTime(500);
165+
end({ code: '200' }, { spanId: 'span_id_test_1' });
166+
167+
const vals = (await histogramInstance.get()).values;
168+
expect(getValuesByLabel(0.5, vals)[0].value).toEqual(1);
169+
expect(
170+
getValuesByLabel(0.5, vals)[0].exemplar.labelSet.traceId,
171+
).toEqual('trace_id_test_1');
172+
jest.useRealTimers();
173+
});
174+
150175
function getValueByLabel(label, values, key) {
151176
return values.reduce((acc, val) => {
152177
if (val.labels && val.labels[key || 'le'] === label) {

0 commit comments

Comments
 (0)