Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ project adheres to [Semantic Versioning](http://semver.org/).
- ci: switch out deprecated benchmark-regression library for replacement
- AggregatorRegistry renamed to ClusterRegistry, old name deprecated
- chore: update faceoff to 1.1
- perf: Avoid array conversion in getMetricsAsJSON by directly iterating over metric values (~1.3% faster)
- perf: Optimize string escaping for better metrics serialization

### Added

- Expanded benchmarking code
- Expanded benchmarks and using new benchmarking library
- new WorkerRegistry to provide equivalent support to AggregatorRegistry

## [15.1.3] - 2024-06-27
Expand Down
58 changes: 58 additions & 0 deletions benchmarks/defaultMetrics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use strict';

const Path = require('path');
const { createRequire } = require('node:module');
const { getLabelCombinations } = require('./utils/labels');

let count = 1;

module.exports = function setupSuites(benchmark) {
benchmark.suite('osMemoryHeap', suite => {
suite.add(
'new',
(client, { labels, metric: osMemoryHeap, registry }) =>
osMemoryHeap(registry, {
prefix: `heap${count++}`,
help: 'HeapUsed',
labels,
}),
{
setup: (client, location) =>
loadMetrics(client, location, 'osMemoryHeap'),
teardown,
},
);

suite.add('collect', async (client, { registry }) => registry.metrics(), {
setup: (client, location) => {
const ctx = loadMetrics(client, location, 'osMemoryHeap');
const { metric: osMemoryHeap, labels, registry } = ctx;

osMemoryHeap(registry, {
prefix: `heap${count++}`,
help: 'HeapUsed',
labels,
});

return { registry };
},
teardown,
});
});
};

function loadMetrics(client, location, metricName) {
const require = createRequire(location);
const fromModule = Path.join(location, `./lib/metrics/${metricName}`);
const combinations = getLabelCombinations([1], ['region', 'env']);

return {
metric: require(fromModule),
labels: combinations[0],
registry: new client.Registry(),
};
}

function teardown(client, { registry }) {
registry.clear();
}
1 change: 1 addition & 0 deletions benchmarks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ benchmarks.suite('histogram', require('./histogram'));
benchmarks.suite('util', require('./util'));
benchmarks.suite('summary', require('./summary'));
benchmarks.suite('registry', require('./registry'));
benchmarks.suite('default metrics', require('./defaultMetrics'));
benchmarks.suite('cluster', require('./cluster'));

benchmarks
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const Path = require('path');
module.exports = setupUtilSuite;

function setupUtilSuite(suite) {
const skip = ['prom-client@latest', 'prom-client@trunk'];
const skip = ['prom-client@latest'];

suite.add(
'hashObject',
Expand Down
1 change: 0 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,3 @@ exports.ClusterRegistry = require('./lib/cluster');
exports.WorkerRegistry = require('./lib/worker');
/** @deprecated */
exports.AggregatorRegistry = exports.ClusterRegistry;
exports[Symbol('util')] = require('./lib/util');
41 changes: 38 additions & 3 deletions lib/registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class Registry {

const promises = [];

for (const metric of this.getMetricsAsArray()) {
for (const metric of this._metrics.values()) {
promises.push(metric.get());
}

Expand Down Expand Up @@ -293,11 +293,46 @@ function escapeLabelValue(str) {
if (typeof str !== 'string') {
return str;
}
return escapeString(str).replace(/"/g, '\\"');

let result = '';
for (let i = 0; i < str.length; i++) {
const char = str[i];
switch (char) {
case '\\':
result += '\\\\';
break;
case '\n':
result += '\\n';
break;
case '"':
result += '\\"';
break;
default:
result += char;
}
}

return result;
}

function escapeString(str) {
return str.replace(/\\/g, '\\\\').replace(/\n/g, '\\n');
let result = '';
for (let i = 0; i < str.length; i++) {
const char = str[i];
switch (char) {
case '\\':
result += '\\\\';
break;
case '\n':
result += '\\n';
break;
default:
result += char;
}
}
return result;
}

function standardizeCounterName(name) {
return name.replace(/_total$/, '');
}
Expand Down