Skip to content

Commit

Permalink
Merge pull request #2155 from artilleryio/bernardobridge/art-1358-mem…
Browse files Browse the repository at this point in the history
…ory-inspector-plugin-allow-memory-units

feat(memory-inspector): allow memory units to be specified
  • Loading branch information
bernardobridge committed Sep 20, 2023
2 parents 8bbf8df + dca54d2 commit 989328c
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 12 deletions.
8 changes: 7 additions & 1 deletion packages/artillery-plugin-memory-inspector/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ You can set more than one `pid` to be watched by the plugin, so that you can wat

_Optional_. The name of the process to display in the custom metrics report. It is the name that will show up in the custom metrics, otherwise defaults to `process_${pid}`.

### `unit`

_Optional_. The unit to convert memory metrics to. Accepts `mb`/`megabyte` or `kb`/`kilobyte`. Defaults to `mb` if not specified.

### Example Usage

```yaml
Expand Down Expand Up @@ -59,4 +63,6 @@ This will emit the following additional metrics from [`process.memoryUsage`](htt
- artillery_internal.rss
- artillery_internal.external
- artillery_internal.heap_total
- artillery_internal.heap_used
- artillery_internal.heap_used

__Note: These extended Artillery metrics cannot have their unit configured and default to using mb as the unit.__
51 changes: 45 additions & 6 deletions packages/artillery-plugin-memory-inspector/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
const pidusage = require('pidusage');
const debug = require('debug')('plugin:memory-inspector');

const fromBytesToUnit = (value, unit) => {
const allowedUnits = {
kb: ['kb', 'kilobyte'],
mb: ['mb', 'megabyte']
};

if (!unit) {
debug('No unit specified. Defaulting to mb.');
return value / 1024 / 1024;
}

if (allowedUnits.kb.includes(unit)) {
return value / 1024;
}

if (allowedUnits.mb.includes(unit)) {
return value / 1024 / 1024;
}

debug(`Unit ${unit} is not an allowed unit! Defaulting to mb`);
return value / 1024 / 1024;
};

function ArtilleryPluginMemoryInspector(script, events) {
this.script = script;
this.events = events;
Expand All @@ -13,13 +36,29 @@ function ArtilleryPluginMemoryInspector(script, events) {
if (typeof process.env.ARTILLERY_INTROSPECT_MEMORY !== 'undefined') {
//https://nodejs.org/api/process.html#processmemoryusage
const { rss, heapUsed, heapTotal, external } = process.memoryUsage();
ee.emit('histogram', 'artillery_internal.memory', rss);
ee.emit('histogram', 'artillery_internal.external', external);
ee.emit('histogram', 'artillery_internal.heap_used', heapUsed);
ee.emit('histogram', 'artillery_internal.heap_total', heapTotal);
ee.emit(
'histogram',
'artillery_internal.memory',
fromBytesToUnit(rss, 'mb')
);
ee.emit(
'histogram',
'artillery_internal.external',
fromBytesToUnit(external, 'mb')
);
ee.emit(
'histogram',
'artillery_internal.heap_used',
fromBytesToUnit(heapUsed, 'mb')
);
ee.emit(
'histogram',
'artillery_internal.heap_total',
fromBytesToUnit(heapTotal, 'mb')
);
}

for (let { pid, name } of inspectorConfig) {
for (let { pid, name, unit } of inspectorConfig) {
if (!pid) {
debug(`No pid (${pid}) found. Skipping!`);
continue;
Expand All @@ -32,7 +71,7 @@ function ArtilleryPluginMemoryInspector(script, events) {
ee.emit(
'histogram',
`${name || `process_${pid}`}.memory`,
stats.memory
fromBytesToUnit(stats.memory, unit)
);
} catch (error) {
debug(`Could not get usage stats for pid ${pid}.\n${error}`);
Expand Down
2 changes: 1 addition & 1 deletion packages/artillery-plugin-memory-inspector/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Inspect the memory of processes running together with your load tests!",
"main": "index.js",
"scripts": {
"test": "tap ./test/*.spec.mjs --no-coverage --color --timeout 300"
"test": "export ARTILLERY_TELEMETRY_DEFAULTS='{\"source\":\"test-suite\"}' && tap ./test/*.spec.mjs --no-coverage --color --timeout 300"
},
"author": "",
"license": "MPL-2.0",
Expand Down
36 changes: 33 additions & 3 deletions packages/artillery-plugin-memory-inspector/test/index.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ afterEach(async () => {
childProcess.kill()
});

test('cpu and memory metrics display in the aggregate report with the correct name', async (t) => {
test('cpu and memory metrics display in the aggregate report with the correct name and unit', async (t) => {
//Arrange: Test Server and Plugin overrides
const testServer = await startTestServer();
childProcess = testServer.childProcess

const override = JSON.stringify({
config: {
plugins: {
'memory-inspector': [{ pid: testServer.currentPid, name: 'express-example' }]
'memory-inspector': [{ pid: testServer.currentPid, name: 'express-example', unit: 'kb' }]
}
}
});
Expand Down Expand Up @@ -65,9 +65,19 @@ test('cpu and memory metrics display in the aggregate report with the correct na
'express-example.memory',
"Aggregate Histograms doesn't have Memory metric"
);

//assert that kb unit is used
for (const [metric, value] of Object.entries(report.aggregate.summaries['express-example.memory'])) {
if (metric == 'count') {
continue;
}

const lengthOfValue = Math.round(value).toString().length;
t.ok(lengthOfValue > 3 && lengthOfValue <= 6, `Length of value ${value} should be in KB (more than mb unit, less than byte unit)`)
}
});

test('cpu and memory metrics display in the aggregate report with a default name when no name is given', async (t) => {
test('cpu and memory metrics display in the aggregate report with a default name and unit when no name is given', async (t) => {
//Arrange: Test Server and Plugin overrides
const testServer = await startTestServer();
childProcess = testServer.childProcess;
Expand Down Expand Up @@ -112,6 +122,16 @@ test('cpu and memory metrics display in the aggregate report with a default name
`process_${testServer.currentPid}.memory`,
"Aggregate Histograms doesn't have Memory metric"
);

//assert that mb unit is used by default
for (const [metric, value] of Object.entries(report.aggregate.summaries[`process_${testServer.currentPid}.memory`])) {
if (metric == 'count') {
continue;
}

const lengthOfValue = Math.round(value).toString().length;
t.ok(lengthOfValue <= 3, `Length of value ${value} in MB should be less than 4`)
}
});

test('cpu and memory metrics also display in the aggregate report for artillery internals', async (t) => {
Expand Down Expand Up @@ -202,4 +222,14 @@ test('cpu and memory metrics also display in the aggregate report for artillery
'artillery_internal.heap_total',
"Aggregate Histograms doesn't have Artillery Heap Total metric"
);

//assert that mb unit is used by default
for (const [metric, value] of Object.entries(report.aggregate.summaries['artillery_internal.memory'])) {
if (metric == 'count') {
continue;
}

const lengthOfValue = Math.round(value).toString().length;
t.ok(lengthOfValue <= 3, `Length of value ${value} in MB should be less than 4`)
}
});
3 changes: 2 additions & 1 deletion packages/artillery/lib/cmds/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,8 @@ async function sendTelemetry(script, flags, extraProps) {
'metrics-by-endpoint',
'hls',
'fuzzer',
'ensure'
'ensure',
'memory-inspector'
];
for (const p of OFFICIAL_PLUGINS) {
if (script.config.plugins[p]) {
Expand Down

0 comments on commit 989328c

Please sign in to comment.