Skip to content

Commit 1df34ed

Browse files
Dan ShappirDan Shappir
Dan Shappir
and
Dan Shappir
authored
perf: improve perf by refactoring code to be cleaner and more efficient (#559)
Co-authored-by: Dan Shappir <[email protected]>
1 parent 126d4f3 commit 1df34ed

File tree

3 files changed

+64
-68
lines changed

3 files changed

+64
-68
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Cleanup code and refactor to be more efficient
13+
1014
### Breaking
1115

1216
- drop support for Node.js versions 10, 12 and 17

lib/histogram.js

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ class Histogram extends Metric {
5656
this.hashMap = {
5757
[hashObject({})]: createBaseValues(
5858
{},
59-
Object.assign({}, this.bucketValues),
60-
Object.assign({}, this.bucketExemplars),
59+
this.bucketValues,
60+
this.bucketExemplars,
6161
),
6262
};
6363
}
@@ -84,16 +84,17 @@ class Histogram extends Metric {
8484

8585
updateExemplar(labels, value, exemplarLabels) {
8686
const hash = hashObject(labels);
87-
const b = findBound(this.upperBounds, value);
88-
if (!isObject(this.hashMap[hash].bucketExemplars[b])) {
89-
this.hashMap[hash].bucketExemplars[b] = new Exemplar();
87+
const bound = findBound(this.upperBounds, value);
88+
const { bucketExemplars } = this.hashMap[hash];
89+
let exemplar = bucketExemplars[bound];
90+
if (!isObject(exemplar)) {
91+
exemplar = new Exemplar();
92+
bucketExemplars[bound] = exemplar;
9093
}
91-
this.hashMap[hash].bucketExemplars[b].validateExemplarLabelSet(
92-
exemplarLabels,
93-
);
94-
this.hashMap[hash].bucketExemplars[b].labelSet = exemplarLabels;
95-
this.hashMap[hash].bucketExemplars[b].value = value;
96-
this.hashMap[hash].bucketExemplars[b].timestamp = nowTimestamp();
94+
exemplar.validateExemplarLabelSet(exemplarLabels);
95+
exemplar.labelSet = exemplarLabels;
96+
exemplar.value = value;
97+
exemplar.timestamp = nowTimestamp();
9798
}
9899

99100
async get() {
@@ -134,8 +135,8 @@ class Histogram extends Metric {
134135
const hash = hashObject(labels);
135136
this.hashMap[hash] = createBaseValues(
136137
labels,
137-
Object.assign({}, this.bucketValues),
138-
Object.assign({}, this.bucketExemplars),
138+
this.bucketValues,
139+
this.bucketExemplars,
139140
);
140141
}
141142

@@ -218,8 +219,8 @@ function observe(labels) {
218219
if (!valueFromMap) {
219220
valueFromMap = createBaseValues(
220221
labelValuePair.labels,
221-
Object.assign({}, this.bucketValues),
222-
Object.assign({}, this.bucketExemplars),
222+
this.bucketValues,
223+
this.bucketExemplars,
223224
);
224225
}
225226

@@ -239,43 +240,39 @@ function observe(labels) {
239240
function createBaseValues(labels, bucketValues, bucketExemplars) {
240241
return {
241242
labels,
242-
bucketValues,
243-
bucketExemplars,
243+
bucketValues: { ...bucketValues },
244+
bucketExemplars: { ...bucketExemplars },
244245
sum: 0,
245246
count: 0,
246247
};
247248
}
248249

249250
function convertLabelsAndValues(labels, value) {
250-
if (!isObject(labels)) {
251-
return {
252-
value: labels,
253-
labels: {},
254-
};
255-
}
256-
return {
257-
labels,
258-
value,
259-
};
251+
return isObject(labels)
252+
? {
253+
labels,
254+
value,
255+
}
256+
: {
257+
value: labels,
258+
labels: {},
259+
};
260260
}
261261

262262
function extractBucketValuesForExport(histogram) {
263+
const name = `${histogram.name}_bucket`;
263264
return bucketData => {
264-
const buckets = [];
265265
let acc = 0;
266-
for (const upperBound of histogram.upperBounds) {
266+
const buckets = histogram.upperBounds.map(upperBound => {
267267
acc += bucketData.bucketValues[upperBound];
268-
const lbls = { le: upperBound };
269-
buckets.push(
270-
setValuePair(
271-
lbls,
272-
acc,
273-
`${histogram.name}_bucket`,
274-
bucketData.bucketExemplars[upperBound],
275-
bucketData.labels,
276-
),
268+
return setValuePair(
269+
{ le: upperBound },
270+
acc,
271+
name,
272+
bucketData.bucketExemplars[upperBound],
273+
bucketData.labels,
277274
);
278-
}
275+
});
279276
return { buckets, data: bucketData };
280277
};
281278
}

lib/registry.js

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ class Registry {
4242
const defaultLabels =
4343
Object.keys(this._defaultLabels).length > 0 ? this._defaultLabels : null;
4444

45+
const isOpenMetrics =
46+
this.contentType === Registry.OPENMETRICS_CONTENT_TYPE;
47+
4548
for (const val of metric.values || []) {
4649
let { metricName = name, labels = {} } = val;
4750
const { sharedLabels = {} } = val;
48-
if (
49-
this.contentType === Registry.OPENMETRICS_CONTENT_TYPE &&
50-
metric.type === 'counter'
51-
) {
51+
if (isOpenMetrics && metric.type === 'counter') {
5252
metricName = `${metricName}_total`;
5353
}
5454

@@ -58,13 +58,7 @@ class Registry {
5858

5959
// We have to flatten these separately to avoid duplicate labels appearing
6060
// between the base labels and the shared labels
61-
const formattedLabels = [];
62-
for (const [n, v] of Object.entries(labels)) {
63-
if (Object.prototype.hasOwnProperty.call(sharedLabels, n)) {
64-
continue;
65-
}
66-
formattedLabels.push(`${n}="${escapeLabelValue(v)}"`);
67-
}
61+
const formattedLabels = formatLabels(labels, sharedLabels);
6862

6963
const flattenedShared = flattenSharedLabels(sharedLabels);
7064
const labelParts = [...formattedLabels, flattenedShared].filter(Boolean);
@@ -74,7 +68,7 @@ class Registry {
7468
)}`;
7569

7670
const { exemplar } = val;
77-
if (exemplar && this.contentType === Registry.OPENMETRICS_CONTENT_TYPE) {
71+
if (exemplar && isOpenMetrics) {
7872
const formattedExemplars = formatLabels(exemplar.labelSet);
7973
fullMetricLine += ` # {${formattedExemplars.join(
8074
',',
@@ -87,25 +81,21 @@ class Registry {
8781
}
8882

8983
async metrics() {
90-
const promises = [];
84+
const isOpenMetrics =
85+
this.contentType === Registry.OPENMETRICS_CONTENT_TYPE;
9186

92-
for (const metric of this.getMetricsAsArray()) {
93-
if (
94-
this.contentType === Registry.OPENMETRICS_CONTENT_TYPE &&
95-
metric.type === 'counter'
96-
) {
87+
const promises = this.getMetricsAsArray().map(metric => {
88+
if (isOpenMetrics && metric.type === 'counter') {
9789
metric.name = standardizeCounterName(metric.name);
9890
}
99-
promises.push(this.getMetricsAsString(metric));
100-
}
91+
return this.getMetricsAsString(metric);
92+
});
10193

10294
const resolves = await Promise.all(promises);
10395

104-
if (this.contentType === Registry.OPENMETRICS_CONTENT_TYPE) {
105-
return `${resolves.join('\n')}\n# EOF\n`;
106-
} else {
107-
return `${resolves.join('\n\n')}\n`;
108-
}
96+
return isOpenMetrics
97+
? `${resolves.join('\n')}\n# EOF\n`
98+
: `${resolves.join('\n\n')}\n`;
10999
}
110100

111101
registerMetric(metric) {
@@ -212,10 +202,15 @@ class Registry {
212202
}
213203
}
214204

215-
function formatLabels(labels) {
216-
return Object.entries(labels).map(
217-
([n, v]) => `${n}="${escapeLabelValue(v)}"`,
218-
);
205+
function formatLabels(labels, exclude) {
206+
const { hasOwnProperty } = Object.prototype;
207+
const formatted = [];
208+
for (const [name, value] of Object.entries(labels)) {
209+
if (!exclude || !hasOwnProperty.call(exclude, name)) {
210+
formatted.push(`${name}="${escapeLabelValue(value)}"`);
211+
}
212+
}
213+
return formatted;
219214
}
220215

221216
const sharedLabelCache = new WeakMap();

0 commit comments

Comments
 (0)